PHP程式碼審計分段講解(11)
後面的題目相對於之前的題目難度稍微提升了一些,所以對每道題進行單獨的分析
27題
<?php if(!$_GET['id']) { header('Location: index.php?id=1'); exit(); } $id=$_GET['id']; $a=$_GET['a']; $b=$_GET['b']; if(stripos($a,'.')) { echo 'Hahahahahaha'; return ; } $data = @file_get_contents($a,'r'); if($data=="1112 is a nice lab!" and $id==0 and strlen($b)>5 and eregi("111".substr($b,0,1),"1114") and substr($b,0,1)!=4) { require("flag.txt"); } else { print "work harder!harder!harder!"; } ?>
本題目修改自BugKu的Web中的 never give up 一題
需要我們使用GET方式輸入 id,a,b三個值
$id=$_GET['id']; $a=$_GET['a']; $b=$_GET['b'];
對傳遞的a進行了限制
if(stripos($a,'.')) { echo 'Hahahahahaha'; return ; }
而在這裡需要讀取$a中的檔案內容
$data = @file_get_contents($a,'r');
同時還有一個限制是:
$data=="1112 is a nice lab!"
所以我們很難通過搭建伺服器訪問txt檔案來傳輸這樣的一串資料,所以這裡使用PHP的偽協議
詳細的偽協議介紹和利用可以看Smi1e的這篇文章:
這裡只擷取其中的一部分:
php://input
php://input 是個可以訪問請求的原始資料的只讀流,可以讀取到post沒有解析的原始資料, 將post請求中的資料作為PHP程式碼執行。因為它不依賴於特定的 php.ini 指令。 注:enctype=”multipart/form-data” 的時候 php://input 是無效的。
我們這裡通過 input 使用POST方式傳輸a的值為:
1112 is a nice lab!
而對 id 進行的限制為:
if(!$_GET['id']) { header('Location: index.php?id=1'); exit(); }
同時還需要滿足
$id==0
也就是說 id 需要弱型別比較與 0 相等,又要不為0,如果為0,則會重定向至index.php
這裡可以直接使用字母繞過,在PHP程式碼審計分段講解(9)中,第25題 switch沒有break 字元與0比較繞過裡面,用到了一個點是:
PHP中非數字開頭字串和數字 0
比較==
都返回True
作者猜想應該是字串轉換成數字型別失敗,所以直接返回0
所以我們只需要讓 id=abc 這一類的字母就行
第三個引數 b 的限制條件為:
strlen($b)>5 and eregi("111".substr($b,0,1),"1114") and substr($b,0,1)!=4)
第一個長度問題很容易解決,簡單解釋一下三個限制條件:
-
strlen($b)>5 引數b的長度大於5
-
eregi("111".substr($b,0,1),"1114") 在111與引數b的第一位拼接後的結果,能夠在"1114" 字串中被找到
-
$b 的第一位不能是4
而我們知道eregi函式是存在%00截斷漏洞的,所以我們令$b=%0012345,這樣不僅滿足了 111能夠在1114中被找到,而且%00是不等於4的
同目錄下寫一個flag.txt檔案用來看效果
burpsuite抓包,結果為:
獲取flag