前言 buuctf里web的第一道题,比较怀念,依然不会写。
正文 打开题目,是一个滑稽图 看不出什么,查看网页源代码,发现了source.php 访问source.php,发现以下source.php中的代码, 有一说一,我也看不懂是什么意思,看别人的题解知道,这是index.php的源代码
<?php highlight_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\" />" ; } ?>
发现hint.php,看一下,提示flag在/ffffllllaaaagggg里面,咱也不知道怎么访问,就跑去看看大佬的题解 看大佬题解知道接下来要分析代码,咱也不会,就看看大佬的分析过程
代码分析 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\" />" ; }
整体利用的漏洞就是代码最后的include函数,利用文件包含漏洞 因此,最后的if条件语句是关键,即需要满足 if(true && true && true) ,才会执行include函数,否则输出滑稽图。 ! empty($_REQUEST[‘file’]满足true简单 is_string($_REQUEST[‘file’]满足true简单 emmm::checkFile($_REQUEST[‘file’]满足true,需要执行emmm类中的checkFile函数,使得该函数最终返回true才可以
整体细节详解(checkFile函数的目标就是返回true):
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\" />" ; }
1 、定义了一个类emm2 、在类emm中定义了一个checkFile ()函数3 、不执行函数,先判断下面的if 语句:if (true && true && true )才能执行include函数,所以需要满足如下要求: (1 )$_REQUEST['file' ]不为空,!empty ($_REQUEST['file' ]才会返回true ; (2 )$_REQUEST['file' ]是字符串,is_string ($_REQUEST['file' ]才会返回true ; (3 )checkFile ($_REQUEST['file' ]返回true ,emmm::checkFile ($_REQUEST['file' ]才 会返回true ; 因此,满足这三个条件,最后才能执行include函数 4 、接下来看看checkFile ()函数中的内容(1 )第一个if 不能return flase,因为这里不能执行{}中的语句,因为不管return true 或者return false ,都会 终止当前函数的执行,所以需要满足if (false || false )才能继续执行下面的代码,即,$page存在并且是字符串; (2 )第2 个语句可以执行,返回true 那么,就需要$whitelist中存在$page 注:in_array函数是检查数组中是否存在某个值(找到true ;找不false ),特别注意这是在数组的键值中找,不包括键 5 、这样的话我们就可以构造payload (1 )测试payload1: http: 执行了source.php,输出了里面的内容 (2 )测试payload2: http: 我想得到ffffllllaaaagggg时就出问题了,因为ffffllllaaaagggg不在$whitelist数组的键值中,并且 继续执行代码后,下面$_page=source.php../../../../../../../ffffllllaaaagggg,第3 个if 语句false , urldecode后$_page=source.php../../../../../../../ffffllllaaaagggg,mb_substr后还是这个,第4 个if 语句还是false ,最后输出you can' t see it,还return false ,这还玩啥 该如何解决?我需要include ffffllllaaaagggg文件,而且需要使用../,怎样绕过? 注意到mb_strpos ($page . '?' , '?' )没,我们构造一个?即可 (3 )测试payload3: http: 构造?的话,第2 个if 语句就不能返回true 了,第3 个if 语句一样,也不能执行return 语句,第4 个if 语句需要满足if (true ),因为需要执行{}中的内容,最后使得checkFile ()函数返回的布尔类型为true (4 )payload3执行流程:此时file=source.php?../../../../../../ffffllllaaaagggg 第1 个if 返回false 第2 个if 返回false $_page=source.php 第3 个if 返回true ,退出checkFile函数,此时核心代码中已满足if (true &&true &&true ),即执行include函数 最后include (source.php?../../../../../../ffffllllaaaagggg)
分析得到payload如下
http://xxx/index.php?file=source.php%253f../../../../../ffffllllaaaagggg
访问即可得到flag。
执行流程:
第1 个if 返回false 第2 个if 返回false $_page=source.php%3f ../../../../../ffffllllaaaagggg 第3 个if 返回false urldecode执行后,$_page=source.php?../../../../../ffffllllaaaagggg 执行mb_substr后$_page=source.php return true 下面核心代码执行同理 最后include (source.php%253f ../../../../../ffffllllaaaagggg)
注意 (1)只要函数中return执行了,就会立即结束函数的执行,继续执行函数外的代码; (2)||表示任意||两边只要有一边是true,整体就返回true; (3)in_array函数是检查数组中是否存在某个值(找到true;找不false),特别注意这是在数组的键值中找,不包括键; (4)mb_strpos查找目标首次出现的位置,从0开始; (5)mb_substr返回字符串,特别注意的是:mb_strpos获取的数字,在mb_substr不是从0开始,而是代表返回的长度。
最后说一句 其实看了题解也没太看懂,存着,有空多看看,总有一天会看懂的。