1、靶场首页
首页是一个滑稽.jpg,打开源码可以看到有个source.php
2、查看source.php(部分已进行注释)
<?php
highlight_file(__FILE__); #对文件进行语法高亮显示
class emmm #定义emmm类
{
public static function checkFile(&$page) #将传入参数赋值给$page
{
$whitelist = ["source"=>"source.php","hint"=>"hint.php"]; #声明$whitelist数组
if (! isset($page) || !is_string($page)) { #如果$page不存在或者不为字符串
echo "you can't see it"; #打印"you can't see it"
return false; #返回false
}
if (in_array($page, $whitelist)) { #如果$whitelist数组存在$page变量
return true; #返回true
}
$_page = mb_substr( # mb_substr() 返回字符串的一部分
$page,
0,
mb_strpos($page . '?', '?') # mb_strpos() 查找字符串在另一个字符串中首次出现的位置
);
if (in_array($_page, $whitelist)) { #如果$whitelist数组存在$_page变量
return true; #返回true
}
$_page = urldecode($page); # 对$page进行url解码
$_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
3、/hint.php
提示:flag在 ffffllllaaaagggg 里面
4、接着回去对source.php进行一个代码的审计
if (! empty($_REQUEST['file']) # $_REQUEST['file']值非空
&& is_string($_REQUEST['file']) # $_REQUEST['file']值为字符串
&& emmm::checkFile($_REQUEST['file']) # $_REQUEST['file']通过checkfile校验
) {
include $_REQUEST['file']; # $_REQUEST['file']文件包含
exit;
} else {
echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />"; # 打印滑稽.jpg
}
可以看出如果 file值为非空且为字符串,可以通过emmm类的checkFile函数过滤,就执行文件包含,否则就打印滑稽表情。而需要被包含的文件就是hint.php提示的ffffllllaaaagggg。
5、回去查看emmm类下的checkfile函数
class emmm #定义emmm类
{
public static function checkFile(&$page) #将传入参数赋值给$page
{
$whitelist = ["source"=>"source.php","hint"=>"hint.php"]; #声明$whitelist数组
if (! isset($page) || !is_string($page)) { #如果$page不存在或者不为字符串
echo "you can't see it"; #打印"you can't see it"
return false; #返回false
}
if (in_array($page, $whitelist)) { #如果$whitelist数组存在$page变量
return true; #返回true
}
$_page = mb_substr( # mb_substr() 返回字符串的一部分
$page,
0,
mb_strpos($page . '?', '?') # mb_strpos() 查找字符串在另一个字符串中首次出现的位置
);
if (in_array($_page, $whitelist)) { #如果$whitelist数组存在$_page变量
return true; #返回true
}
$_page = urldecode($page); # 对$page进行url解码
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
echo "you can't see it";
return false;
}
}
可以看到函数内一共有4个if。
- 第一个if检验$page是否为字符串,否则返回false
- 第二个if判断$whitelist数组中是否存在$page,存在则返回true
- 第三个if判断$_page(即截取 $page . '?' 中 '?' 前部分得到的变量)是否存在于$whitelist数组中(即值为hint.php或source.php),存在则返回true
- 第四个if判断$_page(即url解码后再进行截取后得到的变量)是否存在于$whitelist数组中(即值为hint.php或source.php),存在则返回true
如果4个if语句均为返回值,则返回false。
有3个if语句可以返回true,可以从中寻找利用点。
- 第二个if直接判断$page,不可利用
- 第三个语句截取'?'前部分,由于?后部分被解析为get方式提交的参数,也不可利用
- 第四个if语句先进行url解码再截取。
因此我们可以将 ? 经过两次url编码。在服务器端(浏览器)提取参数时解码一次,checkFile函数中解码一次后,仍会解码为?,即可通过第四个if校验。而 ? 经过一次url编码为 %3f ,两次为 %253f
由于不知道ffffllllaaaagggg文件存放的具体位置,所以依次增加../即可拿到flag。
6、payload
http://xxxx:xxxx/source.php?file=source.php%253f../../../../../ffffllllaaaagggg