5.HCTF-2018-WarmUp

题目地址:

解题过程:

网页上打开就只有一个大滑稽,网页名是Document,所以是文件包含?提交file参数,一直是:you can’t see it。

题目标签是代码审计,我也没看到代码啊……

查看源代码看到source.php内心毫无波澜,后来查找才知道要访问它……(菜\1)*

好,访问source.php我终于看到代码了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<?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\" />";
}
?>

到目前为止还没有看到过这么长的代码审计(菜\2)*

先看与file有关的代码:

1
2
3
4
5
6
if (! empty($_REQUEST['file'])
&& is_string($_REQUEST['file'])
&& emmm::checkFile($_REQUEST['file'])
) {
include $_REQUEST['file'];
exit;

file要求是字符串且不为空,用emmm中的checkFile调用。file中的值传递给了page。checkFile中四个if语句,每个都有return。

第一个if:
1
2
3
4
5
$whitelist = ["source"=>"source.php","hint"=>"hint.php"];
if (! isset($page) || !is_string($page)) {
echo "you can't see it";
return false;
}

先设置了一个白名单数组,准许访问source.php和hint.php,hint.php中存放了flag的位置。第一个if语句要求page存在且为字符串,不符合则return false,退出程序。

第二个if:
1
2
3
if (in_array($page, $whitelist)) {
return true;
}

in_array()函数在page中查找是否有与whitelist中键值对应的字符串。有则return true,退出程序。

第三个if:
1
2
3
4
5
6
7
8
$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}

mb_strpos为page拼接了一个?,并返回其**第一次出现的位置**。mb_substr从开头显示字符至?所在的位置,处理后page再次进行比对。

那不是只能读source.php了?……$_page啊,那没事了……(菜\3)*

第四个if:
1
2
3
4
5
6
7
8
9
10
11
$_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;

先对page进行了url编码,再进行读取和对比的操作……

注意:PHP中$_GET、$_POST、$_REQUEST这类函数在提取参数值时会URL解码一次

这位师傅上面写第三个if不能利用,但逻辑理通之后我感觉也是可以利用的。

?一次编码为%3F,二次编码为%253F,那么第三个if的利用需要if的一次编码。

第三个if利用:

payload:?file=source.php%3F../../../../../../ffffllllaaaagggg(服务器找不到source.php%3F,就视为一个文件夹)

image-20201201140413227

成功出flag

第四个if利用:

自然,需要二次编码的’?‘。

payload:?file=source.php%253F../../../../../../ffffllllaaaagggg

image-20201201140836595

总算做了点实在事……

知识点总结:

补充https://www.feiniaomy.com/post/388.html

  • 关于路径符号的一些知识。
  • 服务器找不到XXXXXXX,就视为一个文件夹。

:D 一言句子获取中...