0x00 前言
此題為 Web 基礎題,難度中低,需要的基礎知識有:HTML、PHP、HTTP 協議。
首先考查發現源碼的能力,其次重點考查 PHP 黑魔法的使用,相關鏈接如下:
0x01 攔截跳轉
點開解題鏈接,除了一句 never never never give up !!! 之外空空如也,直接查看源碼,發現一條注釋中有線索:
根據提示打開鏈接:http://120.24.86.145:8006/test/1p.html,發現跳轉回 Bugku 的主站,所以祭出 BurpSuite 進行抓包攔截。
請求數據包如下:
響應數據包如下:
0x02 三重解碼
根據響應內容中變量 Words
的值,容易得出是一段 URL 編碼后的數據:
1
|
%3Cscript%3Ewindow.location.href%3D%27http%3A//www.bugku.com%27%3B%3C/script%3E%20%0A%3C%21--JTIyJTNCaWYlMjglMjElMjRfR0VUJTVCJTI3aWQlMjclNUQlMjklMEElN0IlMEElMDloZWFkZXIlMjglMjdMb2NhdGlvbiUzQSUyMGhlbGxvLnBocCUzRmlkJTNEMSUyNyUyOSUzQiUwQSUwOWV4aXQlMjglMjklM0IlMEElN0QlMEElMjRpZCUzRCUyNF9HRVQlNUIlMjdpZCUyNyU1RCUzQiUwQSUyNGElM0QlMjRfR0VUJTVCJTI3YSUyNyU1RCUzQiUwQSUyNGIlM0QlMjRfR0VUJTVCJTI3YiUyNyU1RCUzQiUwQWlmJTI4c3RyaXBvcyUyOCUyNGElMkMlMjcuJTI3JTI5JTI5JTBBJTdCJTBBJTA5ZWNobyUyMCUyN25vJTIwbm8lMjBubyUyMG5vJTIwbm8lMjBubyUyMG5vJTI3JTNCJTBBJTA5cmV0dXJuJTIwJTNCJTBBJTdEJTBBJTI0ZGF0YSUyMCUzRCUyMEBmaWxlX2dldF9jb250ZW50cyUyOCUyNGElMkMlMjdyJTI3JTI5JTNCJTBBaWYlMjglMjRkYXRhJTNEJTNEJTIyYnVna3UlMjBpcyUyMGElMjBuaWNlJTIwcGxhdGVmb3JtJTIxJTIyJTIwYW5kJTIwJTI0aWQlM0QlM0QwJTIwYW5kJTIwc3RybGVuJTI4JTI0YiUyOSUzRTUlMjBhbmQlMjBlcmVnaSUyOCUyMjExMSUyMi5zdWJzdHIlMjglMjRiJTJDMCUyQzElMjklMkMlMjIxMTE0JTIyJTI5JTIwYW5kJTIwc3Vic3RyJTI4JTI0YiUyQzAlMkMxJTI5JTIxJTNENCUyOSUwQSU3QiUwQSUwOXJlcXVpcmUlMjglMjJmNGwyYTNnLnR4dCUyMiUyOSUzQiUwQSU3RCUwQWVsc2UlMEElN0IlMEElMDlwcmludCUyMCUyMm5ldmVyJTIwbmV2ZXIlMjBuZXZlciUyMGdpdmUlMjB1cCUyMCUyMSUyMSUyMSUyMiUzQiUwQSU3RCUwQSUwQSUwQSUzRiUzRQ%3D%3D--%3E
|
對其進行解碼,得到一條 Javascript 語句與一大段注釋,易看出注釋中的內容是一段 Base64 編碼后的數據:
1
2
|
<script>
window.location.href='http://www.bugku.com';</script>
<!--JTIyJTNCaWYlMjglMjElMjRfR0VUJTVCJTI3aWQlMjclNUQlMjklMEElN0IlMEElMDloZWFkZXIlMjglMjdMb2NhdGlvbiUzQSUyMGhlbGxvLnBocCUzRmlkJTNEMSUyNyUyOSUzQiUwQSUwOWV4aXQlMjglMjklM0IlMEElN0QlMEElMjRpZCUzRCUyNF9HRVQlNUIlMjdpZCUyNyU1RCUzQiUwQSUyNGElM0QlMjRfR0VUJTVCJTI3YSUyNyU1RCUzQiUwQSUyNGIlM0QlMjRfR0VUJTVCJTI3YiUyNyU1RCUzQiUwQWlmJTI4c3RyaXBvcyUyOCUyNGElMkMlMjcuJTI3JTI5JTI5JTBBJTdCJTBBJTA5ZWNobyUyMCUyN25vJTIwbm8lMjBubyUyMG5vJTIwbm8lMjBubyUyMG5vJTI3JTNCJTBBJTA5cmV0dXJuJTIwJTNCJTBBJTdEJTBBJTI0ZGF0YSUyMCUzRCUyMEBmaWxlX2dldF9jb250ZW50cyUyOCUyNGElMkMlMjdyJTI3JTI5JTNCJTBBaWYlMjglMjRkYXRhJTNEJTNEJTIyYnVna3UlMjBpcyUyMGElMjBuaWNlJTIwcGxhdGVmb3JtJTIxJTIyJTIwYW5kJTIwJTI0aWQlM0QlM0QwJTIwYW5kJTIwc3RybGVuJTI4JTI0YiUyOSUzRTUlMjBhbmQlMjBlcmVnaSUyOCUyMjExMSUyMi5zdWJzdHIlMjglMjRiJTJDMCUyQzElMjklMkMlMjIxMTE0JTIyJTI5JTIwYW5kJTIwc3Vic3RyJTI4JTI0YiUyQzAlMkMxJTI5JTIxJTNENCUyOSUwQSU3QiUwQSUwOXJlcXVpcmUlMjglMjJmNGwyYTNnLnR4dCUyMiUyOSUzQiUwQSU3RCUwQWVsc2UlMEElN0IlMEElMDlwcmludCUyMCUyMm5ldmVyJTIwbmV2ZXIlMjBuZXZlciUyMGdpdmUlMjB1cCUyMCUyMSUyMSUyMSUyMiUzQiUwQSU3RCUwQSUwQSUwQSUzRiUzRQ==-->
|
將注釋中的內容進行解碼,發現又是一大段 URL 編碼后的數據:
1
|
%22%3Bif%28%21%24_GET%5B%27id%27%5D%29%0A%7B%0A%09header%28%27Location%3A%20hello.php%3Fid%3D1%27%29%3B%0A%09exit%28%29%3B%0A%7D%0A%24id%3D%24_GET%5B%27id%27%5D%3B%0A%24a%3D%24_GET%5B%27a%27%5D%3B%0A%24b%3D%24_GET%5B%27b%27%5D%3B%0Aif%28stripos%28%24a%2C%27.%27%29%29%0A%7B%0A%09echo%20%27no%20no%20no%20no%20no%20no%20no%27%3B%0A%09return%20%3B%0A%7D%0A%24data%20%3D%20@file_get_contents%28%24a%2C%27r%27%29%3B%0Aif%28%24data%3D%3D%22bugku%20is%20a%20nice%20plateform%21%22%20and%20%24id%3D%3D0%20and%20strlen%28%24b%29%3E5%20and%20eregi%28%22111%22.substr%28%24b%2C0%2C1%29%2C%221114%22%29%20and%20substr%28%24b%2C0%2C1%29%21%3D4%29%0A%7B%0A%09require%28%22f4l2a3g.txt%22%29%3B%0A%7D%0Aelse%0A%7B%0A%09print%20%22never%20never%20never%20give%20up%20%21%21%21%22%3B%0A%7D%0A%0A%0A%3F%3E
|
進行 URL 解碼后,終於得到一段不完整的 PHP 核心源碼:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
";if(!$_GET['id'])
{
header('Location: hello.php?id=1');
exit();
}
$id=$_GET['id'];
$a=$_GET['a'];
$b=$_GET['b'];
if(stripos($a,'.'))
{
echo 'no no no no no no no';
return ;
}
$data = @file_get_contents($a,'r');
if($data=="bugku is a nice plateform!" and $id==0 and strlen($b)>5 and eregi("111".substr($b,0,1),"1114") and substr($b,0,1)!=4)
{
require("f4l2a3g.txt");
}
else
{
print "never never never give up !!!";
}
?>
|
其中各條核心語句的作用如下:
- 第 1 行:限制 URL 查詢字符串中必須有非空非零變量
id
- 第 9 行:限制變量
$a
中不能含有字符.
- 第 15 行:要滿足以下 5 條表達式才會爆 flag:
- 變量
$data
弱等於字符串bugku is a nice plateform!
- 變量
$id
弱等於整型數 0 - 變量
$b
的長度大於 5 - 字符串
1114
要與字符串111
連接變量$b
的第一個字符構成的正則表達式匹配 - 變量
$b
的第一個字符弱不等於整型數 4
- 變量
注意,源碼中已暴露出 flag 文件,有可能是出題人的失誤,也有可能是出題人故意用第 15 行復雜的語句迷惑你,實際上可以繞過。因此,直接訪問鏈接 http://120.24.86.145:8006/test/f4l2a3g.txt 即可獲得 flag。
不過,第 15 行的語句也是可解的(應該也是此題的本意),請繼續往下看。
0x03 PHP 黑魔法
本節分別針對源碼中 $id
、$a
、$b
三個變量需要滿足的條件進行講解。
PHP 弱類型比較
由上圖可知,變量 $id
若想滿足非空非零且弱等於整型數 0,則 $id
的值只能為非空非零字符串,這里假設 $id = "asd"
。
有關 PHP 類型比較的詳情可參考:PHP 類型比較表
PHP 偽協議
源碼中變量 $data
是由 file_get_contents()
函數讀取變量 $a
的值而得,所以 $a
的值必須為數據流。
在服務器中自定義一個內容為 bugku is a nice plateform!
文件,再把此文件路徑賦值給 $a
,顯然不太現實。因此這里用偽協議 php:// 來訪問輸入輸出的數據流,其中 php://input
可以訪問原始請求數據中的只讀流。這里令 $a = "php://input"
,並在請求主體中提交字符串 bugku is a nice plateform!
。
有關 PHP 偽協議的詳情可參考:支持的協議和封裝協議
eregi() 截斷漏洞
CTF 題做多了就知道 ereg()
函數或 eregi()
函數存在空字符截斷漏洞,即參數中的正則表達式或待匹配字符串遇到空字符則截斷丟棄后面的數據。
源碼中待匹配字符串(第二個參數)已確定為 "1114"
,正則表達式(第一個參數)由 "111"
連接 $b
的第一個字符組成,若令 substr($b,0,1) = "\x00"
,即滿足 "1114"
與 "111"
匹配。因此,這里假設 $b = "\x0012345"
,才能滿足以上三個條件。
有關 PHP 的各種黑魔法可參考:
0x04 構造 payload 爆 flag
分析出以上三個變量應該等於什么值后,接下來構造出對應的 payload 自然就 get flag 了。之所以將構造 payload 單獨拿出來講,是想分享筆者在構造 payload 過程中踩過的坑。
在構造變量 b
中的空字符時,過早將空字符 \x00
放入,在提交請求時導致請求頭截斷,繼而請求失敗,得不到響應。
因為 b
是 URL 查詢字符串中的變量,不應該在此放入空字符 \x00
,而應該為空字符的 URL 編碼 %00
。注意,雖然 b=%0012345
實際字符串長度為 8 字節,但在后台腳本讀入數據時,會將 URL 編碼 %00
轉換成 1 字節。所以說,空字符應該在后台腳本的變量中出現,而不是在 URL 查詢字符串變量中出現。
構造出正確的 payload 后,完成此題常規思路的做法: