buu[HCTF 2018]WarmUp(代碼審計)
題目
訪問source.php
<?phphighlight_file(__FILE__);class emmm{public static function checkFile(&$page){$whitelist = ["source"=>"source.php","hint"=>"hint.php"];if (! isset($page) || !is_string($page)) {echo "you can't see it";return false;}if (in_array($page, $whitelist)) {return true;}$_page = mb_substr($page,0,mb_strpos($page . '?', '?'));if (in_array($_page, $whitelist)) {return true;}$_page = urldecode($page);$_page = mb_substr($_page,0,mb_strpos($_page . '?', '?'));if (in_array($_page, $whitelist)) {return true;}echo "you can't see it";return false;}}if (! empty($_REQUEST['file'])&& is_string($_REQUEST['file'])&& emmm::checkFile($_REQUEST['file'])) {include $_REQUEST['file'];exit;} else {echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";}
?>
分析
可以看到checkfile里面有4個if,第一個if不能進去進去就false;
后面三個if要進去一個,不然執行結束返回false;
下面的文件包含前的判斷條件要三個都為真才能包含
然后通過白名單可以知道有兩個文件,我們訪問一下hint.php
得到一個flag所在的文件
讓我們分析一下代碼:
if (! isset($page) || !is_string($page)) {echo "you can't see it";return false;}//這個if不進去很簡單
if (in_array($page, $whitelist)) {return true;}
//這個if進不去,我們傳的$page肯定不符合白名單
$_page = mb_substr($page,0,mb_strpos($page . '?', '?'));//這段代碼的意思就是 將第一個?之前的內容截取出來,注意不包括這個問號//而且可以發現的是這里不再是原封不動的$page拿來比較
if (in_array($_page, $whitelist)) {return true;}
//拿$_page去比較是否匹配白名單,注意這里是截取過.
//可以向辦法進入這個if
$_page = urldecode($page);$_page = mb_substr($_page,0,mb_strpos($_page . '?', '?'));//先將$page解碼再截取if (in_array($_page, $whitelist)) {return true;}//同樣這里可以想辦法進入這個if
echo "you can't see it";return false;//之前沒有進入任何if去返回值就失敗了
在這個URL中,http://url/source.php?file=hint.php?../../../../../ffffllllaaaagggg
,包含了兩個參數:file
和 ../../../../../ffffllllaaaagggg
。
通常,URL中的參數是用?
來分隔的,而參數之間則用&
符號來分隔。在這個URL中,file
是參數名,hint.php?../../../../../ffffllllaaaagggg
是參數值。
現在讓我們來解釋一下這個參數值 hint.php?../../../../../ffffllllaaaagggg
的含義:
hint.php
:這部分是文件名,表明了要訪問的文件是hint.php
。?
:在URL中,?
符號通常用來分隔參數名和參數值。在這個特定的情況下,?
可能被用來分隔文件名和查詢字符串,以向hint.php
傳遞額外的參數。../../../../../ffffllllaaaagggg
:這部分是查詢字符串,它以?
開頭。在UNIX和類似系統中,../
用來表示上級目錄,因此這個查詢字符串看起來是在嘗試向hint.php
傳遞參數ffffllllaaaagggg
,同時在路徑中向上跳了多個目錄。
總結一下,這個URL中的hint.php?../../../../../ffffllllaaaagggg
可能是嘗試訪問hint.php
文件,并向它傳遞了一個查詢字符串參數,同時嘗試在文件路徑中向上跳轉多層目錄。
需要注意的是,?
符號在URL中通常用來分隔參數名和參數值。在這個特定的情況下,?
后面的內容被認為是查詢字符串,它可能被hint.php
用來解析和處理。然而,具體的含義和行為取決于服務器端對URL的處理方式。
此題?應該是用來繞過白名單所加
網上有兩種解釋,結合起來看更容易理解
1、tips:include函數有這么一個神奇的功能:以字符‘/’分隔(而且不計個數),若是在前面的字符串所代表的文件無法被PHP找到,則PHP會自動包含‘/’后面的文件——注意是最后一個‘/’。
2、如果我們的file變量為source.php?../…/…/…/…/ffffllllaaaagggg,先截取 ? 號前字符串白名單驗證也就是 source.php,符合,返回ture,然后服務器訪問時訪問 source.php? 文件不存在,目錄穿越至ffffllllaaaagggg,得到我們要的flag。至于為什么需要四個…/,可以一個個增加多次嘗試。(source或hint都可)
方法一
一次編碼,進入第三個if
方法二
使用urldecode會出現一個問題,假如我將一個字符使用url編碼了兩遍然后傳入的時候,首先瀏覽器解碼了一遍,接下來才是urlencode解碼,所以使用兩次urlencode,繞過前面的if,進入第四個if