进去之后只有一个大滑稽,右键查看源码,发现source.php
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title></head><body><!--source.php--><br><img src="https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg" /></body></html>
得到代码:
<?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\" />";}?>
在44行发现include $_REQUEST['file'];,存在文件包含漏洞,但是需要满足上面的三个条件,分别为:
empty($_REQUEST['file'],file参数中的内容不为空。is_string($_REQUEST['file'],file参数中的内容是字符串。emmm::checkFile($_REQUEST['file'],checkFile返回True。
前两个就不用再说了,重点是第三个。
第7行开始,声明了一个whitelist:
$whitelist = ["source"=>"source.php","hint"=>"hint.php"];
13行,进行一次in_array判断:
if (in_array($page, $whitelist)) {return true;}
只有在whitelist中才会返回true。
接着程序考虑到了问号存在的情况,提取问号之前的字符串:
$_page = mb_substr($page,0,mb_strpos($page . '?', '?'));
如果截断后的字符串在whitelist中就返回true。
linux环境的题目下到这里其实就存在漏洞了,也就是说现在传递的参数中加上一个source.php?或者hint.php?,之后再在?后面加上需要包含的文件即可。
payload:
index.php?file=source.php?../../../../../../../../../../etc/passwd
但是在windows环境下不可以这样,因为windows下将?当作保留字符,出现在路径中会报错,继续往下分析:
$_page = urldecode($page);$_page = mb_substr($_page,0,mb_strpos($_page . '?', '?'));
可以看到假如前面的都没有通过,那么$_page会经过一次urldecode。那么将?编码两次,即可成功绕过。
index.php?file=source.php%253f../../../../../../../../../../etc/passwd
之所以为什么编码两次,是因为参数发送到服务器时,就会进行一次url解码,如果是一次编码,那么最后包含文件时还是会出错,所以需要进行两次编码。
