1. 程式人生 > 實用技巧 >PHP程式碼審計分段講解(11)

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的這篇文章:https://www.smi1e.top/%E6%96%87%E4%BB%B6%E5%8C%85%E5%90%AB%E6%BC%8F%E6%B4%9E%E4%B8%8Ephp%E4%BC%AA%E5%8D%8F%E8%AE%AE/

這裡只擷取其中的一部分:

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