[HCTF 2018]WarmUp
进去之后就是一个图 查看源码得到提示 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\" />";
}
?>
主程序
一个if语句检查了如下内容:
1.非空
2.是否为字符串
3.能够通过emmm类的checkFile函数
同时满足上述条件则通过include函数包含对应文件,否则就是滑稽脸的图片
emmm类checkFIle函数分析
上来在白名单内得到提示 看hint.php
flag not here, and flag in ffffllllaaaagggg
那就猜测flag应该在ffffllllaaaagggg.php页面 回到源码 进行分析
首先定义了白名单 包含了 source.php 和 hint.php
接下来就是四个 if 语句的判断和部分对参数的处理语句
part1
if (! isset($page) || !is_string($page)) {
echo "you can't see it";
return false;
}
先判断是否提交了$page变量以及是不是字符串 如果不是就返回false
part2
if (in_array($page, $whitelist)) {
return true;
}
判断上传内容是否在白名单内 若没有返回false
part3
$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);
用到两个函数从内往外为mb_strpos()函数和mb_substr()函数
整个语句的作用是先查找$page变量中第一次出现 ‘ ? ’的位置,再将第一位开始到第一次出现问号的部分进行截断返回剩余串
mb_strpos()
mb_strpos (haystack ,needle )
haystack:要被检查的字符串。
needle:要搜索的字符串。
返回值为目标串在被检查串第一次出现的位置
mb_substr()
截取函数mb_substr ( string $str , int $start [, int $length = NULL [, string $encoding = mb_internal_encoding() ]] ) : string
str 必需。从该 string 中提取子字符串。
start 必需。规定在字符串的何处开始。
正数 - 在字符串的指定位置开始
负数 - 在从字符串结尾的指定位置开始
0 - 在字符串中的第一个字符处开始
length 可选。规定要返回的字符串长度。默认是直到字符串的结尾。
正数 - 从 start 参数所在的位置返回
负数 - 从字符串末端返回
encoding 可选。字符编码。如果省略,则使用内部字符编码。
part4
if (in_array($_page, $whitelist)) {
return true;
}
再次判断剩余串是否在白名单内
part5
$_page = urldecode($page);
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
对$page变量进行url解码再执行一次截断
part6
if (in_array($_page, $whitelist)) {
return true;
}
再次进行判断剩余串是否在白名单内
part7
echo "you can't see it";
return false;
若以上判断都为false最终就返回false
构造payload绕过
符合函数要求的payload为?file=source.php
因为'?'在函数中进行了两次截取 所以第一个问号处不可利用,判断白名单也无法利用所以只能在第二次截断是绕过
用url编码 对 ' ? ' 进行两次编码 为%253f 则在页面提交时 解码为%3f在第二次截断时被解码为 ' ? ' 从而达到保留最后内容的目的。
payload 1.0:?file=source.php%253fffffllllaaaagggg
可是包含未成功,但是注意到没有了滑稽 说明有可能是文件路径不对 不在同一目录下 那就多返回几层目录试试
payload 2.0:?file=source.php%253f../../../../../ffffllllaaaagggg
成功绕过getflag