🪤Electron安全初探
2023-9-29
| 2024-1-5
0  |  0 分钟
type
status
slug
tags
category
icon
password
Property
Jan 5, 2024 08:18 AM
date
summary

前言

越来越多的桌面应用程序都使用了electron 开发,再加上最近私建企x爆发了xss漏洞,只要向特定用户发送消息就可以直接rce。所以想研究一下electron安全,本文主要是将了一下electron如何开发,和一些不安全配置下的Rce条件。目前最新版本electron的rce也是主要围绕三个安全配置来操作。

Electron 开发

安装

npm 初始化
通过npm安装electron
新建 index.js 文件 里面包含如下内容
并且在package.js 添加start scripts 完整package.js内容如下
然后执行 npm run start 终端应该会输出 欢迎来到 Electron 👋 ,正确提示则表示Electron 安装完成
notion image

基础

窗口创建

将网页装载到BrowserWindow 在src目录新建index.html
然后修改index.js 文件

vscode debug

在主要程序中加载下面代码,可以开启开发者模式类似浏览器F12
新建一个 .vscode 文件夹,然后在其中新建一个 launch.json 配置文件并填写如下内容
保存后,当您选择侧边栏的 “运行和调试”,将会出现一个 "Main + renderer" 选项。然后您便可设置断点,并跟踪主进程和渲染器进程中的所有变量。
notion image

预加载脚本

Electron 的主进程是一个拥有着完全操作系统访问权限的 Node.js 环境。 On top of Electron modules, you can also access Node.js built-ins, as well as any packages installed via npm. 另一方面,出于安全原因,渲染进程默认跑在网页页面上,而并非 Node.js里。
为了将 Electron 的不同类型的进程桥接在一起,我们需要使用被称为 预加载 的特殊脚本。
从 Electron 20 开始,预加载脚本默认 沙盒化 ,不再拥有完整 Node.js 环境的访问权。 实际上,这意味着你只拥有一个 polyfilled 的 require 函数,这个函数只能访问一组有限的 API。
可用的 API
详细信息
Electron 模块
渲染进程模块
Node.js 模块
Polyfilled 的全局模块
index.js
index.html
preload.js
renderer.js
如果输出如下内容,代表预加载成功
notion image

IPC进程之间通信

使用 Electron 的 ipcMain 模块和 ipcRenderer 模块来进行进程间通信。 为了从你的网页向主进程发送消息,你可以使用 ipcMain.handle 设置一个主进程处理程序(handler),然后在预处理脚本中暴露一个被称为 ipcRenderer.invoke 的函数来触发该处理程序(handler)。
例如如果程序需要打印系统命令 uname -a
首先,在预处理脚本中设置 invoke 调用:
然后,在主进程中设置你的 handle 监听器。 我们在 HTML 文件加载之前完成了这些,所以才能保证在你从渲染器发送 invoke 调用之前处理程序能够准备就绪。
将发送器与接收器设置完成之后,现在你可以将信息通过刚刚定义的 'uname' 通道从渲染器发送至主进程当中。
成功传递到前端
notion image

模式 1:渲染器进程到主进程(单向)

要将单向 IPC 消息从渲染器进程发送到主进程,您可以使用 [ipcRenderer.send](<https://www.electronjs.org/zh/docs/latest/api/ipc-renderer>) API 发送消息,然后使用 [ipcMain.on](<https://www.electronjs.org/zh/docs/latest/api/ipc-main>) API 接收。
通过前端UI 修改标题,实例代码
要将消息发送到上面创建的监听器,您可以使用 ipcRenderer.send API。 默认情况下,渲染器进程没有权限访问 Node.js 和 Electron 模块。 作为应用开发者,您需要使用 contextBridge API 来选择要从预加载脚本中暴露哪些 API。
在渲染器程序调用api
尝试调用cmd 执行命令
notion image

模式 2:渲染器进程到主进程(双向)

双向 IPC 的一个常见应用是从渲染器进程代码调用主进程模块并等待结果。 这可以通过将 [ipcRenderer.invoke](<https://www.electronjs.org/zh/docs/latest/api/ipc-renderer#ipcrendererinvokechannel-args>) 与 [ipcMain.handle](<https://www.electronjs.org/zh/docs/latest/api/ipc-main#ipcmainhandlechannel-listener>) 搭配使用来完成。
示例代码写了一个命令执行工具,执行命令并显示在前端
在主程序创建对应函数
预加载,设置导出函数
渲染程序,执行对应程序并将结果返回到前端显示
可以成功执行代码,此时如果该软件存在xss漏洞,哪怕开了上下文、安全模式和沙箱也可以导致Rce
notion image

模式 3:主进程到渲染器进程

将消息从主进程发送到渲染器进程时,需要指定是哪一个渲染器接收消息。 消息需要通过其 [WebContents](<https://www.electronjs.org/zh/docs/latest/api/web-contents>) 实例发送到渲染器进程。 此 WebContents 实例包含一个 [send](<https://www.electronjs.org/zh/docs/latest/api/web-contents#contentssendchannel-args>) 方法,其使用方式与 ipcRenderer.send 相同。
参考代码https://github.com/electron/electron/tree/v25.2.0/docs/fiddles/ipc/pattern-3
  1. 使用 webContents 模块发送消息
对于此演示,我们需要首先使用 Electron 的 Menu 模块在主进程中构建一个自定义菜单,该模块使用 webContents.send API 将 IPC 消息从主进程发送到目标渲染器。
index.js (Main Process)
出于本教程的目的,请务必注意, click 处理函数通过 update-counter 通道向渲染器进程发送消息(1 或 -1)。
INFO
请确保您为以下步骤加载了 index.html 和 preload.js 入口点!
  1. 通过预加载脚本暴露 ipcRenderer.on
与前面的渲染器到主进程的示例一样,我们使用预加载脚本中的 contextBridge 和 ipcRenderer 模块向渲染器进程暴露 IPC 功能:
preload.js (Preload Script)
加载预加载脚本后,渲染器进程应有权访问 window.electronAPI.onUpdateCounter() 监听器函数。
preload.js (Preload Script)
但是,与通过 context bridge 暴露预加载 API 相比,此方法的灵活性有限,因为监听器无法直接与渲染器代码交互。
  1. 构建渲染器进程 UI
为了将它们联系在一起,我们将在加载的 HTML 文件中创建一个接口,其中包含一个 #counter 元素,我们将使用该元素来显示值:
index.html
最后,为了更新 HTML 文档中的值,我们将添加几行 DOM 操作的代码,以便在每次触发 update-counter 事件时更新 #counter 元素的值。
renderer.js (Renderer Process)
在上面的代码中,我们将回调传递给从预加载脚本中暴露的 window.electronAPI.onUpdateCounter 函数。 第二个 value 参数对应于我们传入 webContents.send 函数的 1 或 -1,该函数是从原生菜单调用的。
可选:返回一个回复
对于从主进程到渲染器进程的 IPC,没有与 ipcRenderer.invoke 等效的 API。 不过,您可以从 ipcRenderer.on 回调中将回复发送回主进程。
我们可以对前面例子的代码进行略微修改来演示这一点。 在渲染器进程中,使用 event 参数,通过 counter-value 通道将回复发送回主进程。
renderer.js (Renderer Process)
在主进程中,监听 counter-value 事件并适当地处理它们。
main.js (Main Process)

编译

因为安装Electron 的核心模块中没有捆绑任何用于打包或分发文件的工具,需要安装Electron Forge 打包
然后在执行即可
交叉编译
win打包:平台 --paltform=win32 | 架构 --arch=x64 | 图标 --icon=**.ico
mac打包:平台 --paltform=drawin | 架构 --arch=x64 | 图标 --icon=**.ico
交叉编译参考

反编译

将程序中的app.asar提取到本地 然后执行下面命令

安全风险

常用payload
electron 并不是存在Xss就可以Rce
这里主要关注三个配置选项
20以前版本sandbox默认关闭
12版本以后默认开启contextIsolation
nodeIntegration
contextIsolation
sandbox
FALSE
FALSE
FALSE
perload可控 = Rce (20以前版本sandbox默认关闭)
FALSE
FALSE
TRUE
无法rce
FALSE
TRUE
FALSE
考虑IPC
FALSE
TRUE
TRUE
考虑IPC
TRUE
FALSE
FALSE
xss = Rce
TRUE
FALSE
TRUE
考虑IPC
TRUE
TRUE
FALSE
考虑IPC
TRUE
TRUE
TRUE
考虑IPC

Rce: 开启nodeIntegration,关闭contextIsolation,关闭sanbox

这种情况只要存在xss ,直接就可以rce
notion image

Rce: perload覆盖

如果关闭了contextIsolation,可以通过覆盖perload中的特定方法 (In preload code or in Electron internal code)
通过覆盖perload成功改变逻辑,执行了exec
notion image

参考链接

 
技术分享
  • Pentesting
  • 安卓逆向实战-某加密算法CS反制-ddos
    目录