刷题地址:https://buuoj.cn/challenges
首先打开是一个笑脸,查看源代码,如下图发现了,一个文件
一.代码分析发现是一堆代码,需要PHP代码审计,全部代码如下。
1 <?php
2 highlight_file(__FILE__);
3 class emmm
4 {
5 public static function checkFile(&$page)
6 {
7 $whitelist = ["source"=>"source.php","hint"=>"hint.php"];
8 if (! isset($page) || !is_string($page)) {
9 echo "you can't see it";
10 return false;
11 }
12
13 if (in_array($page, $whitelist)) {
14 return true;
15 }
16
17 $_page = mb_substr(
18 $page,
19 0,
20 mb_strpos($page . '?', '?')
21 );
22 if (in_array($_page, $whitelist)) {
23 return true;
24 }
25
26 $_page = urldecode($page);
27 $_page = mb_substr(
28 $_page,
29 0,
30 mb_strpos($_page . '?', '?')
31 );
32 if (in_array($_page, $whitelist)) {
33 return true;
34 }
35 echo "you can't see it";
36 return false;
37 }
38 }
39
40 if (! empty($_REQUEST['file'])
41 && is_string($_REQUEST['file'])
42 && emmm::checkFile($_REQUEST['file'])
43 ) {
44 include $_REQUEST['file'];
45 exit;
46 } else {
47 echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
48 }
49 ?>
查看到了关键字眼hint.php
。
$whitelist = ["source"=>"source.php","hint"=>"hint.php"];
我们访问这个文件查看,如下图,发现flag在ffffllllaaaagggg
里面
首先先看40-48行的内容! empty($_REQUEST['file']
的意思是传参file
不能为空
is_string($_REQUEST['file']
的意思是传参必须要字符串
emmm::checkFile($_REQUEST['file']
这句话的意思是要经过checkFile函数的检查
如果都为真那么就执行include $_REQUEST['file'];
包含文件
如果为否那么就输出滑稽图片
由此可以总结
1.file传参不能为空
2.file传参必须要字符串
3.需要经过checkFile函数的检测
40 if (! empty($_REQUEST['file'])
41 && is_string($_REQUEST['file'])
42 && emmm::checkFile($_REQUEST['file'])
43 ) {
44 include $_REQUEST['file'];
45 exit;
46 } else {
47 echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
48 }
接下来来看看,函数代码为5-38行,首先来看第一个if语句issset()
函数判断是否设置了$page
,或者如果$page
不是字符串就输出you can't see it
然后返回为假。
第二个if语句判断的是$page
是否在$whitelist
里面,如果在那么就返回true。
然后17行-21行是截取$page
?前面的东西mb_substr()
函数是截取,mb_strpos()
涵数是判断字符串首次出现的位置就是,截取$page
0-?首次出现的位置的地方也就是截取?前面的东西
22-24行又判断$page
是否在$whitelist
里面如果有那么就返回true
26行对传参进行了一次url编码解码
27-31又进行了一次截取
32-34又进行了一次判断是否在$whitelist
里面,如果有那么就返回true
总结来说
1.第一个if判断是$是否设置了值或者是$page是否为字符串,如果不是返回false
2.第二个if判断的是$page是否在$whitelist列表里面如果在就返回true
3.第三个语句是截取$page问号前面的东西
4.第四个语句会对$page进行一次url编码的解码,加上浏览器就是两次解码
5.第五个语句还是截取$page问好前面的东西
6.最后一个语句判断$page是否在$whitelist里面
如果上面四个if语句都没返回那么就返回false
class emmm
4 {
5 public static function checkFile(&$page)
6 {
7 $whitelist = ["source"=>"source.php","hint"=>"hint.php"];
8 if (! isset($page) || !is_string($page)) {
9 echo "you can't see it";
10 return false;
11 }
12
13 if (in_array($page, $whitelist)) {
14 return true;
15 }
16
17 $_page = mb_substr(
18 $page,
19 0,
20 mb_strpos($page . '?', '?')
21 );
22 if (in_array($_page, $whitelist)) {
23 return true;
24 }
25
26 $_page = urldecode($page);
27 $_page = mb_substr(
28 $_page,
29 0,
30 mb_strpos($_page . '?', '?')
31 );
32 if (in_array($_page, $whitelist)) {
33 return true;
34 }
35 echo "you can't see it";
36 return false;
37 }
38 }
所以经过上面的判断,payload应该是如下,测试其实不需要两次编码都可以,因为?
的解码还是?
所以也可以直接/source.php?file=source.php?../../../../../../../../../../ffffllllaaaagggg
/source.php?file=source.php%253f../../../../../../../../../../ffffllllaaaagggg