官术网_书友最值得收藏!

2.2 命令執(zhí)行漏洞

通常情況下,在開(kāi)發(fā)者使用一些執(zhí)行命令函數(shù)且未對(duì)用戶輸入的數(shù)據(jù)進(jìn)行安全檢查時(shí),可以注入惡意的命令,使整臺(tái)服務(wù)器處于危險(xiǎn)中。作為一名CTFer,命令執(zhí)行的用途如下:技巧型直接獲取flag;進(jìn)行反彈Shell,然后進(jìn)入內(nèi)網(wǎng)的大門;利用出題人對(duì)權(quán)限的控制不嚴(yán)格,對(duì)題目環(huán)境擁有控制權(quán),導(dǎo)致其他隊(duì)伍選手無(wú)法解題,這樣在時(shí)間上會(huì)占一定優(yōu)勢(shì)。

在CTF中,命令執(zhí)行一般發(fā)生在遠(yuǎn)程,故被稱為遠(yuǎn)程命令執(zhí)行,即RCE(Remote Command Exec),也被稱為RCE(Remote Code Exec)。本節(jié)的RCE皆為遠(yuǎn)程命令執(zhí)行。

本節(jié)將闡述常見(jiàn)的RCE漏洞和繞過(guò)WAF的方案,再通過(guò)一些經(jīng)典題目讓讀者對(duì)CTF中的RCE題目有所了解。

2.2.1 命令執(zhí)行的原理和測(cè)試方法

下面介紹命令注入的基本原理,包括cmd.exe、bash程序在解析命令的時(shí)候會(huì)存在哪些問(wèn)題、在不同的操作系統(tǒng)中執(zhí)行命令會(huì)存在哪些異同點(diǎn)等,以及在CTF題目中應(yīng)該如何進(jìn)行測(cè)試,直到最終獲取flag。

2.2.1.1 命令執(zhí)行原理

在各類編程語(yǔ)言中,為了方便程序處理,通常會(huì)存在各種執(zhí)行外部程序的函數(shù),當(dāng)調(diào)用函數(shù)執(zhí)行命令且未對(duì)輸入做過(guò)濾時(shí),通過(guò)注入惡意命令,會(huì)造成巨大的危害。

下面以PHP中的system()函數(shù)舉例:

該代碼的正常功能是調(diào)用操作系統(tǒng)的echo程序,將從d參數(shù)接收的字符串作為echo程序的輸入,最終system()函數(shù)將echo程序執(zhí)行的結(jié)果返回在網(wǎng)頁(yè)中,其在操作系統(tǒng)執(zhí)行的命令為“echo for test”,最終在網(wǎng)頁(yè)顯示為“for test”,見(jiàn)圖2-2-1。

圖2-2-1

當(dāng)改變d參數(shù)為“for test%26%26 whoami”時(shí),網(wǎng)頁(yè)會(huì)多出whoami程序的執(zhí)行結(jié)果,這是因?yàn)楫?dāng)前在系統(tǒng)執(zhí)行的命令為“echo for test&&whoami”,見(jiàn)圖2-2-2。

圖2-2-2

通常為了解決URL中的歧義表達(dá),會(huì)將一些特殊字符進(jìn)行URL編碼,“%26”便是“&”的URL編碼。為什么注入“&&”字符就可以造成命令注入呢?類似的還有其他什么字符嗎?

在各類編程語(yǔ)言中,“&&”是and語(yǔ)法的表達(dá),一般通過(guò)如下格式進(jìn)行調(diào)用:

當(dāng)兩邊的表達(dá)式都為真時(shí),才會(huì)返回真。類似的語(yǔ)法還有or,通常用“||”表示。注意,它們存在惰性,在and語(yǔ)法中,若第一個(gè)表達(dá)式的結(jié)果為假,則第二個(gè)表達(dá)式不會(huì)執(zhí)行,因?yàn)樗銥榧佟Ecor語(yǔ)法類比,若第一個(gè)表達(dá)式為真,則第二個(gè)表達(dá)式也不會(huì)執(zhí)行,因?yàn)樗銥檎妗?/p>

所以,命令注入就是通過(guò)注入一些特殊字符,改變?cè)镜膱?zhí)行意圖,從而執(zhí)行攻擊者指定的命令。

2.2.1.2 命令執(zhí)行基礎(chǔ)

在測(cè)試前,我們需要了解cmd.exe、bash程序在解析命令時(shí)的規(guī)則,掌握Windows、Linux的異同點(diǎn)。

1.轉(zhuǎn)義字符

系統(tǒng)中的cmd.exe、bash程序執(zhí)行命令能夠解析很多特殊字符,它們的存在讓BAT批處理和bash腳本處理工作更加便捷,但是如果想去掉特殊字符的特殊意義,就需要進(jìn)行轉(zhuǎn)義,所以轉(zhuǎn)義字符即為取消字符的特殊意義。

Windows的轉(zhuǎn)義字符為“^”,Linux的轉(zhuǎn)義字符為“\”,分別見(jiàn)圖2-2-3和圖2-2-4。可以看到,原本存在特殊意義的“&”被取消意義,從而在終端中輸出。

圖2-2-3

圖2-2-4

2.多條命令執(zhí)行

在命令注入中通常需要注入多條命令來(lái)擴(kuò)大危害,下面是一些能夠構(gòu)成多條命令執(zhí)行的字符串:Windows下,&&、||、%0a;Linux下,&&、||、;、$()、``、%0a、%0d。圖2-2-5、圖2-2-6分別為Windows和Linux下的多條命令執(zhí)行。圖2-2-5中顯示了“noexist||echo pwnpwnpwn”,noexist程序本身不存在,所以報(bào)錯(cuò),但是通過(guò)注入“||”字符,即使前面報(bào)錯(cuò),還會(huì)執(zhí)行后面的“echo pwnpwnpwn”命令。

在上面的例子中,“&&”和“||”利用條件執(zhí)進(jìn)行多條命令執(zhí)行,“%0a”和“%0d”則是由于換行而可以執(zhí)行新的命令。另外,在Linux中需要注意,雙引號(hào)包裹的字符串“$()”或“``”中的內(nèi)容被當(dāng)作命令執(zhí)行,但是單引號(hào)包括的字符串就是純字符串,不會(huì)進(jìn)行任何解析,見(jiàn)圖2-2-7。

圖2-2-5

圖2-2-6

圖2-2-7

3.注釋符號(hào)

與代碼注釋一樣,當(dāng)合理利用時(shí),命令執(zhí)行能夠使命令后面的其他字符成為注釋內(nèi)容,這樣可以降低程序執(zhí)行的錯(cuò)誤。

Windows的注釋符號(hào)為“::”,在BAT批處理腳本中用得較多;Linux的注釋符號(hào)為“”,在bash腳本中用得較多。

2.2.1.3 命令執(zhí)行的基本測(cè)試

在面對(duì)未知的命令注入時(shí),最好通過(guò)各種Fuzz來(lái)確認(rèn)命令注入點(diǎn)和黑名單規(guī)則。一般命令的格式如下:

下面以ping-nc 1 www.baidu.com為例構(gòu)建Fuzz列表。

? 程序名:ping。

? 參數(shù):-nc。

? 參數(shù)值:1和www.baidu.com。

? 程序名與參數(shù)值之間的字符串:空格。

? 整個(gè)命令。

參數(shù)值有時(shí)較為復(fù)雜,可能是部分可控的,被雙引號(hào)、單引號(hào)包裹,這時(shí)需要注入額外的引號(hào)來(lái)逃逸。比如,構(gòu)造Fuzz列表:

再通過(guò)將Fuzz列表插入命令點(diǎn)后,通過(guò)查看自己服務(wù)器的Web日志來(lái)觀察是否存在漏洞。

2.2.2 命令執(zhí)行的繞過(guò)和技巧

本節(jié)介紹在CTF中解答命令執(zhí)行題目的技巧,命令執(zhí)行的題目需要把控的因素比較多,如權(quán)限的控制、題目接下來(lái)的銜接。但是命令執(zhí)行比較簡(jiǎn)單、粗暴,經(jīng)常存在技巧性繞過(guò)的考點(diǎn)。

2.2.2.1 缺少空格

在一些代碼審計(jì)中經(jīng)常會(huì)禁止空格的出現(xiàn)或者會(huì)將空格過(guò)濾為空,下面將講解如何突破。例如,對(duì)于如下PHP代碼:

將cmd參數(shù)中的空格過(guò)濾為空,導(dǎo)致執(zhí)行“echo pwnpwn”命令失敗,見(jiàn)圖2-2-8。

圖2-2-8

但是在命令中間隔的字符可以不只是空格(URL編碼為“%20”),還可以利用burp suite對(duì)%00~%ff區(qū)間的字符串進(jìn)行測(cè)試,可以發(fā)現(xiàn)還能用其他字符進(jìn)行繞過(guò),如“%09”“%0b”“%0c”等。

利用burp suite進(jìn)行Fuzz,見(jiàn)圖2-2-9。再次輸入“%09”字符,即“echo%09pwnpwnpwn”,就能發(fā)現(xiàn)可以繞過(guò)空格的限制,見(jiàn)圖2-2-10。

圖2-2-9

圖2-2-10

以上只是其中一種通用去Fuzz未知情況的方式。若將“%0a”“%0d”等不可見(jiàn)字符都禁止,還可以通過(guò)字符串截取的方式獲取空格。

1.Windows下

例如,命令如下:

其中,“”相當(dāng)于截取符,表示獲取環(huán)境變量%ProgramFiles%的值,一般為C:\Program Files。所以,以上命令表示,從第10個(gè)開(kāi)始且獲取一個(gè)字符串,也就是空格,見(jiàn)圖2-2-11。

圖2-2-11

2.Linux下

Linux中也有一些繞過(guò)空格執(zhí)行的方式:

bash有效,zsh、dash無(wú)效:

讀取文件時(shí):

$IFS$9:Linux存在IFS(Internal Field Separator)環(huán)境變量,即內(nèi)部字段分隔符,定義了bash shell的命令間隔字符,一般為空格。注意,當(dāng)只注入$IFS時(shí),即執(zhí)行的命令結(jié)果為echo$IFSaaa,可以發(fā)現(xiàn)解析后的$IFSaaa變量是不存在的,所以需要間隔符來(lái)避免,通常使用“$9”。“$9”表示為當(dāng)前系統(tǒng)Shell進(jìn)程的第9個(gè)參數(shù),通常是一個(gè)空字符串,即最終能成功執(zhí)行的命令為“echo$IFS$9aaa”。

當(dāng)然,還可以使用“${IFS}”進(jìn)行注入,或者在某些平臺(tái)下通過(guò)修改IFS變量為逗號(hào)來(lái)進(jìn)行注入,即“;IFS=,;”,見(jiàn)圖2-2-12。

圖2-2-12

2.2.2.2 黑名單關(guān)鍵字

在CTF比賽中,有時(shí)會(huì)遇上黑名單關(guān)鍵字,如對(duì)cat、flag等字符串進(jìn)行攔截,這時(shí)可以用下面的方式繞過(guò)。

1.利用變量拼接

其中,a變量為c,b變量為at,最終$a$b是cat。c變量為he,d變量為llo,最終${c}$w1jcj8o為hello,所以在這里執(zhí)行的命令是“cat hello”。

2.使用通配符

在通配符中,“?”代表任意一個(gè)字符串,“*”則代表任意個(gè)字符串。

可以看到,上面通過(guò)cat、type命令,結(jié)合通配符,實(shí)現(xiàn)了對(duì)黑名單字符串的繞過(guò)。

3.借用已有字符串

若是禁用“<>?”等字符串,則可以借用其他文件中的字符串,利用substr()函數(shù)截取出某個(gè)具體字符。繞過(guò)執(zhí)行結(jié)果見(jiàn)圖2-2-13。

圖2-2-13

2.2.2.3 執(zhí)行無(wú)回顯

在CTF中,我們經(jīng)常遇到命令執(zhí)行的結(jié)果不在網(wǎng)頁(yè)上顯示的情況,這時(shí)可以通過(guò)以下幾種方式獲取執(zhí)行結(jié)果。

在開(kāi)始前,推薦搭建一個(gè)VTest平臺(tái)https://github.com/opensec-cn/vtest,以便測(cè)試。搭建完成后,開(kāi)始測(cè)試,測(cè)試代碼如下:

1.HTTP通道

假設(shè)自己的域名為example.com,下面以獲取當(dāng)前用戶權(quán)限為例。

在Windows下,目前只能通過(guò)相對(duì)復(fù)雜的命令進(jìn)行外帶(如果未來(lái)Windows支持Linux命令,將更加方便數(shù)據(jù)外帶):

通過(guò)for命令,將echo hello執(zhí)行的結(jié)果保存在%x變量中,然后拼接到URL后。

以上命令執(zhí)行后,默認(rèn)瀏覽器會(huì)被系統(tǒng)調(diào)用打開(kāi)并訪問(wèn)指定的網(wǎng)站,最終可以在平臺(tái)上面獲取echo hello命令的執(zhí)行結(jié)果,見(jiàn)圖2-2-14。

圖2-2-14

但是其缺陷是調(diào)用瀏覽器后并不會(huì)關(guān)閉,并且遇上特殊字符、空格時(shí)會(huì)存在截?cái)鄦?wèn)題,所以可以借用powershell進(jìn)行外帶數(shù)據(jù)。在Powershell 2.0下,執(zhí)行如下命令:

這里是對(duì)echo hello的執(zhí)行結(jié)果進(jìn)行Base64編碼,然后通過(guò)Web請(qǐng)求將結(jié)果發(fā)送出去。

在Linux下,由于存在管道等,因此極其方便數(shù)據(jù)的傳輸,通常利用curlwget等程序進(jìn)行外帶數(shù)據(jù)。例如:

上面便是利用多條命令執(zhí)行中的“`”和“$()”進(jìn)行字符串拼接,最終通過(guò)curl、wget等命令向外進(jìn)行請(qǐng)求,從而實(shí)現(xiàn)了數(shù)據(jù)外帶,見(jiàn)圖2-2-15。

圖2-2-15

2.DNS通道

經(jīng)常我們會(huì)以ping來(lái)測(cè)試DNS外帶數(shù)據(jù),ping的參數(shù)在Windows與Linux下有些不同。如限制ping的個(gè)數(shù),在Windows下是“-n”,而在Linux下是“-c”。為了兼容性處理,可以聯(lián)合使用,即“ping-nc 1 test.example.com”。

在Linux下:

在Windows下相對(duì)復(fù)雜,主要利用delims命令進(jìn)行分割處理,最終拼接到域名前綴上,再利用ping程序進(jìn)行外帶。

<1>獲取計(jì)算機(jī)名:

<2>獲取用戶名:

3.時(shí)間盲注

網(wǎng)絡(luò)不通時(shí),可以通過(guò)時(shí)間盲注將數(shù)據(jù)跑出來(lái),主要借用“&&”和“||”的惰性;在Linux下可使用sleep函數(shù),在Windows下則可以選擇一些耗時(shí)命令,如ping-n 5 127.0.0.1

4.寫入文件,二次返回

有時(shí)會(huì)遇上網(wǎng)絡(luò)隔離的情況,time型讀數(shù)據(jù)將會(huì)極其緩慢,可以考慮將執(zhí)行命令結(jié)果寫入到Web目錄下,再次通過(guò)Web訪問(wèn)文件從而達(dá)到回顯目的。例如,通過(guò)“>”重定向,將結(jié)果導(dǎo)出到Web目錄http://www.nu1l.com/exec/3.php?cmd=whoami>test下,再次訪問(wèn)導(dǎo)出文件http://www.nu1l.com/exec/test,便可以得到結(jié)果,見(jiàn)圖2-2-16。

圖2-2-16

2.2.3 命令執(zhí)行真題講解

CTF比賽中單純考查命令注入的題目較為少見(jiàn),一般會(huì)將其組合到其他類型的題目,更多的考點(diǎn)偏向技巧性,如黑名單繞過(guò)、Linux通配符等,下面介紹一些經(jīng)典題目。

2.2.3.1 2015 HITCON BabyFirst

PHP代碼如下:

題目為每人創(chuàng)建一個(gè)沙盒目錄,然后通過(guò)正則“^\w+$”進(jìn)行字符串限制,難點(diǎn)在于正則的繞過(guò)。因?yàn)檎齽t“/^\w+$/”沒(méi)有開(kāi)啟多行匹配,所以可以通過(guò)“\n”(%0a)換行執(zhí)行其他命令。這樣便可以單獨(dú)執(zhí)行touch abc命令:

再新建文件1,內(nèi)容設(shè)置為bash反彈shell的內(nèi)容,其中192.168.0.9為VPS服務(wù)器的IP,23333為反彈端口。然后利用Python的pyftpdlib模塊搭建一個(gè)匿名的FTP服務(wù),見(jiàn)圖2-2-17。

圖2-2-17

最后使用busybox中的ftp命令獲取文件:

將IP轉(zhuǎn)換為十進(jìn)制,即192.168.0.9的十進(jìn)制為3232235529,可以通過(guò)ping驗(yàn)證最終請(qǐng)求的IP是否正確的。

轉(zhuǎn)換腳本如下:

服務(wù)器監(jiān)聽(tīng)端口情況見(jiàn)圖2-2-18。

圖2-2-18

最終整個(gè)解題過(guò)程如下。利用FTP下載反彈Shell腳本:

然后執(zhí)行Shell腳本:

2.2.3.2 2017 HITCON BabyFirst Revenge

PHP代碼如下:

上面的代碼中最關(guān)鍵的限制便是命令長(zhǎng)度限制,strlen($_GET['cmd'])<=5意味著每次執(zhí)行的命令長(zhǎng)度只能小于等于5。

解決方法是利用文件名按照時(shí)間排序,最后使用“ls-t”將其拼接。當(dāng)然,在拼接的過(guò)程中,可以利用“\”接下一行字符串,即將touch程序用“\”分開(kāi),見(jiàn)圖2-2-19。

最終,整個(gè)解題過(guò)程如下:寫入ls-t>g到_文件;寫入payload;執(zhí)行_,生成g文件;最后執(zhí)行g(shù)文件,從而反彈Shell。利用腳本如下:

圖2-2-19

其中生成g文件的內(nèi)容見(jiàn)圖2-2-20。

圖2-2-20

圖2-2-20

2.2.3.3 2017 HITCON BabyFirst Revenge v2

PHP代碼如下:

這就是之前BabyFirst Revenge的升級(jí)版本,限制命令長(zhǎng)度只能小于等于4。其中,ls>>_不能使用。

在Linux下,“*”的執(zhí)行效果類似“$(dir*)”,即dir出來(lái)的文件名會(huì)被當(dāng)成命令執(zhí)行。

t的順序是比s靠后,所以可以找到h并加在t前面,以提高這個(gè)文件名最后排序的優(yōu)先級(jí)。所以,在“*”執(zhí)行時(shí),其實(shí)執(zhí)行的命令為:

最終,v文件的內(nèi)容是:

接下來(lái)寫入一個(gè)rev文件,然后使用“*v”命令,因?yàn)橹挥衦ev、v兩個(gè)帶v的文件,所以其執(zhí)行的命令是“rev v”,再將逆轉(zhuǎn)的v文件內(nèi)容放入x文件。

最終,x文件的內(nèi)容是:

后面寫payload的方式與v1解題一樣。

主站蜘蛛池模板: 靖宇县| 永川市| 保山市| 迁西县| 墨玉县| 龙海市| 长岛县| 班玛县| 乌拉特后旗| 荣成市| 富顺县| 江达县| 南漳县| 同心县| 青阳县| 东乌| 黎城县| 重庆市| 高密市| 武冈市| 称多县| 龙海市| 都江堰市| 靖州| 黔西| 长沙市| 浠水县| 东莞市| 南丹县| 巴东县| 巴楚县| 永吉县| 安塞县| 且末县| 福贡县| 富平县| 连州市| 长沙县| 中宁县| 抚宁县| 威远县|