任意命令執行原因:
當應用需要調用一些外部程序去處理內容的情況下,就會用到一些執行系統命令的函數。如PHP中的system、exec、shell_exec等,當用戶可以控制命令執行函數中的參數時,將可以注入惡意系統命令到正常命令中,造成命令執行攻擊。
腳本語言(如PHP)優點是簡潔、方便,但也伴隨着一些問題,如速度慢、無法接觸系統底層,如果我們開發的應用(特別是企業級的一些應用)需要一些除去WEB的特殊功能時,就需要調用一些外部程序。
在PHP中可以調用外部程序的常見函數:
system、exec、shell_exec、passthru、popen、proc_popen
應用在調用這些函數執行系統命令的時候,如果將用戶的輸入作為系統命令的參數拼接到命令行中,又沒有過濾用戶的輸入的情況下,就會造成命令執行漏洞。
漏洞分類:
代碼層過濾不嚴格:
一些商業應用需要執行命令,商業應用的一些核心代碼可能封裝在二進制文件中,在web應用中通過system函數來調用:system("/bin/program --arg $arg");
系統的漏洞造成命令執行:
bash破殼漏洞(CVE-2014-6271),如果我們控制執行的bash的環境變量,就可以通過破殼漏洞來執行任意代碼。
調用第三方組件存在代碼執行漏洞:
典型的就是WordPress中,可以選擇使用ImageMagick這個常用的圖片處理組件,對用戶上傳的圖片進行處理(默認是ImageMagick庫),造成命令執行。
JAVA中的命令執行漏洞(structs2、ElasticsearchGroovy等)
危害:
繼承WEB服務程序的權限,執行系統命令
繼承WEB服務程序的權限,讀寫文件
反彈shell
控制整個網站
甚至控制整個服務器
可以進一步的內網滲透
等等
漏洞利用:
<?php system($_GET['cmd']); ?>
http://127.0.0.1:8080/?cmd=id
· system("$arg"); 可控點直接是待執行的程序
如果我們能直接控制$arg,那么就能執行任意命令
· system("/bin/prog $arg"); 可控點是傳入程序的整個參數
我們能夠控制的點是程序的整個參數,我們可以直接用 && 或 | 等,利用與、或、管道命令來執行其他命令
當 $arg 被 escapeshellcmd 處理之后,我們不能越出這個外部程序的范圍,我們可以看這個程序自身是否有“執行外部命令”的參數或功能,比如 LINUX 下的 sendmail 命令自帶讀寫文件功能,可以用來寫 webshell。
· system ("/bin/prog -p $arg"); 可控點是傳入程序的某個參數的值(無引號包裹)
可控制的點是一個參數,同樣可以使用 與、或、管道來執行其他的任意命令
· system("/bin/prog --p=\"$arg\""); 可控點是傳入程序的某個參數的值(有雙引號包裹)
因為有引號包裹,首先要分析引號是否被轉義
如果沒有被轉義,先閉合引號,然后利用方法同上
如果被轉義,雙引號內的變量依然會被解析,利用反引號執行任意命令`id`
· system("/bin/prog --p='$arg'"); 可控點是傳入程序的某個參數的值(有單引號包裹)
單引號內只是一個字符串,所以只能閉合單引號,才可利用
修復方案:
1.能使用腳本解決的工作,不要利用其他程序處理。盡量少用執行命令的函數,並在 disable_functions 中禁用
2.對於可控點是程序參數的情況,使用 escapeshellcmd 函數進行過濾 // escapeshellcmd() 除去字符串中的特殊符號
3.對於可控點是程序參數的值得情況,使用 escapeshellarg 函數進行過濾 // escapeshellarg() 將給字符串增加一個單引號並且能引用或者轉碼任何已經存在的單引號,這樣以確保能夠直接將一個字符串傳入 shell 函數,並且還是確保安全的
4.參數的值盡量使用引號包裹,並在拼接前調用 addslashes 函數進行轉義
任意命令執行的前提:
代碼中存在調用系統命令的函數
函數中存在我們可控的點
這個點沒有過濾,或過濾不嚴格