php中可以使用strpos函數與mb_strpos函數獲取指定的字符串在別一個字符串中首次出現的位置,也可以使用它們判斷一串字符串中是否包含別一個字符串.
PHP strpos() 函數
查找 "php" 在字符串中第一次出現的位置:<?php
echo strpos("You love php, I love php too!","php");
?>
運行結果:9
PHP mb_substr() 函數
定義和用法mb_substr() 函數返回字符串的一部分,之前我們學過 substr() 函數,它只針對英文字符,如果要分割的中文文字則需要使用 mb_substr()。注釋:如果 start 參數是負數且 length 小於或等於 start,則 length 為 0。
審計題目源碼##
"source.php","hint"=>"hint.php"]; if (! isset($page) || !is_string($page)) { /*2 為了返回 true 兩個條件必須滿足 1 page存在 2 page是字符串 , 這里和外層的判斷file 一致基本是再次判斷了一遍 */ echo "you can't see it"; return false; } /*3 in_array(search,array,type) 函數搜索數組中是否存在指定的值, 白名單過濾,需要返回了ture 所以這里我們傳入的page或者是經過截斷之后的page必須是soure.php或hint.php, 這里是正常的訪問,我們需要構造文件任意包含,所以這里傳入的不滿足條件,這里不是注意的點,往下繼續看 */ if (in_array($page, $whitelist)) { return true; } /* 這里mb_sustr 是個截斷,返回0到mb_strpos之間的內容,而mb_strps 則是查找第一次出現的位置, 所以基本可以理解為獲取page 兩個?之間的字符串, 也就是獲取file兩個?之間的字符串, 放到url中就是http://ip/?file=ddd?中的file=ddd */ $_page = mb_substr( $page, 0, mb_strpos($page . '?', '?') ); if (in_array($_page, $whitelist)) { //' 6 這里和上面類似 查看_page 是否在白名單中 return true; } $_page = urldecode($page); // 這里發現對_page進行了一次decode解碼, $_page = mb_substr(//獲取兩個??之間的內容 $_page, 0, mb_strpos($_page . '?', '?') ); // 這里是我們要繞過的點,從這里往上看 嘗試構造 if (in_array($_page, $whitelist)) {//白名單 return true; } echo "you can't see it"; return false; } } /*1 必須滿足if條件,才能包含file,這里也可以猜到可能考的是文件包含: 1 REQUEST['file']不為空 2 REQUEST['file']是字符串 3 checkFile($_REQUEST['file']) 為ture,回到checkFile 函數分析如何返回true */ if (! empty($_REQUEST['file']) && is_string($_REQUEST['file']) && emmm::checkFile($_REQUEST['file']) ) { include $_REQUEST['file']; exit; } else { echo "

"; } ?>
可以看到函數代碼中有四個if語句第一個if語句對變量進行檢驗,要求$page為字符串,否則返回false
第二個if語句判斷$page是否存在於$whitelist數組中,存在則返回true
第三個if語句判斷截取后的$page是否存在於$whitelist數組中,截取$page中'?'前部分,存在則返回true
第四個if語句判斷url解碼並截取后的$page是否存在於$whitelist中,存在則返回true
若以上四個if語句均未返回值,則返回false有三個if語句可以返回true,第二個語句直接判斷$page,不可用
第三個語句截取'?'前部分,由於?被后部分被解析為get方式提交的參數,也不可利用
第四個if語句中,先進行url解碼再截取,因此我們可以將?經過兩次url編碼,在服務器端提取參數時解碼一次,checkFile函數中解碼一次,仍會解碼為'?',仍可通過第四個if語句校驗。
只要這四個if語句有一個為true即可包含file,
關鍵點在_page 經過截斷后返回true.
('?'兩次編碼值為'%253f'),繞過前面的白名單過濾后構造url:
http://:/source.php?file=source.php%253f../ffffllllaaaagggg
無返回值,由於我們不知道ffffllllaaaagggg文件的具體位置,只能依次增加../,最終在http://:/source.php?file=source.php%253f../../../../../ffffllllaaaagggg中成功回顯flag
注:兩次url編碼,第一次是url傳入到服務器時解碼了一次,第二次是page傳給_page解碼了一次
參考鏈接:https://www.jianshu.com/p/36eaa95068ca
https://blog.csdn.net/wang_624/article/details/101433257