前言 刷題地址:https://buuoj.cn/challenges 首先打開是一個笑臉,查看源代碼,如下圖發現了,一個文件 一.代碼分析 發現是一堆代碼,需要PHP代碼審計,全部代碼如下。 1 <?php 2 highlight_file(lxx_file); 3 class emmm 4 { ...
前言
刷題地址:https://buuoj.cn/challenges
首先打開是一個笑臉,查看源代碼,如下圖發現了,一個文件
一.代碼分析
發現是一堆代碼,需要PHP代碼審計,全部代碼如下。
1 <?php
2 highlight_file(__FILE__);
3 class emmm
4 {
5 public static function checkFile(&$page)
6 {
7 $whitelist = ["source"=>"source.php","hint"=>"hint.php"];
8 if (! isset($page) || !is_string($page)) {
9 echo "you can't see it";
10 return false;
11 }
12
13 if (in_array($page, $whitelist)) {
14 return true;
15 }
16
17 $_page = mb_substr(
18 $page,
19 0,
20 mb_strpos($page . '?', '?')
21 );
22 if (in_array($_page, $whitelist)) {
23 return true;
24 }
25
26 $_page = urldecode($page);
27 $_page = mb_substr(
28 $_page,
29 0,
30 mb_strpos($_page . '?', '?')
31 );
32 if (in_array($_page, $whitelist)) {
33 return true;
34 }
35 echo "you can't see it";
36 return false;
37 }
38 }
39
40 if (! empty($_REQUEST['file'])
41 && is_string($_REQUEST['file'])
42 && emmm::checkFile($_REQUEST['file'])
43 ) {
44 include $_REQUEST['file'];
45 exit;
46 } else {
47 echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
48 }
49 ?>
查看到了關鍵字眼hint.php
。
$whitelist = ["source"=>"source.php","hint"=>"hint.php"];
我們訪問這個文件查看,如下圖,發現flag在ffffllllaaaagggg
裡面
首先先看40-48行的內容! empty($_REQUEST['file']
的意思是傳參file
不能為空
is_string($_REQUEST['file']
的意思是傳參必須要字元串
emmm::checkFile($_REQUEST['file']
這句話的意思是要經過checkFile函數的檢查
如果都為真那麼就執行include $_REQUEST['file'];
包含文件
如果為否那麼就輸出滑稽圖片
由此可以總結
1.file傳參不能為空
2.file傳參必須要字元串
3.需要經過checkFile函數的檢測
40 if (! empty($_REQUEST['file'])
41 && is_string($_REQUEST['file'])
42 && emmm::checkFile($_REQUEST['file'])
43 ) {
44 include $_REQUEST['file'];
45 exit;
46 } else {
47 echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
48 }
接下來來看看,函數代碼為5-38行,首先來看第一個if語句issset()
函數判斷是否設置了$page
,或者如果$page
不是字元串就輸出you can't see it
然後返回為假。
第二個if語句判斷的是$page
是否在$whitelist
裡面,如果在那麼就返回true。
然後17行-21行是截取$page
?前面的東西mb_substr()
函數是截取,mb_strpos()
涵數是判斷字元串首次出現的位置就是,截取$page
0-?首次出現的位置的地方也就是截取?前面的東西
22-24行又判斷$page
是否在$whitelist
裡面如果有那麼就返回true
26行對傳參進行了一次url編碼解碼
27-31又進行了一次截取
32-34又進行了一次判斷是否在$whitelist
裡面,如果有那麼就返回true
總結來說
1.第一個if判斷是$是否設置了值或者是$page是否為字元串,如果不是返回false
2.第二個if判斷的是$page是否在$whitelist列表裡面如果在就返回true
3.第三個語句是截取$page問號前面的東西
4.第四個語句會對$page進行一次url編碼的解碼,加上瀏覽器就是兩次解碼
5.第五個語句還是截取$page問好前面的東西
6.最後一個語句判斷$page是否在$whitelist裡面
如果上面四個if語句都沒返回那麼就返回false
class emmm
4 {
5 public static function checkFile(&$page)
6 {
7 $whitelist = ["source"=>"source.php","hint"=>"hint.php"];
8 if (! isset($page) || !is_string($page)) {
9 echo "you can't see it";
10 return false;
11 }
12
13 if (in_array($page, $whitelist)) {
14 return true;
15 }
16
17 $_page = mb_substr(
18 $page,
19 0,
20 mb_strpos($page . '?', '?')
21 );
22 if (in_array($_page, $whitelist)) {
23 return true;
24 }
25
26 $_page = urldecode($page);
27 $_page = mb_substr(
28 $_page,
29 0,
30 mb_strpos($_page . '?', '?')
31 );
32 if (in_array($_page, $whitelist)) {
33 return true;
34 }
35 echo "you can't see it";
36 return false;
37 }
38 }
所以經過上面的判斷,payload應該是如下,測試其實不需要兩次編碼都可以,因為?
的解碼還是?
所以也可以直接/source.php?file=source.php?../../../../../../../../../../ffffllllaaaagggg
/source.php?file=source.php%253f../../../../../../../../../../ffffllllaaaagggg