[鹤城杯 2021]EasyP

image-20240618003117756

分析一下源码

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
//post一个guess值如果等于secret则输出flag
if (isset($_POST['guess'])) {
$guess = (string) $_POST['guess'];
if ($guess === $secret) {
$message = 'Congratulations! The flag is: ' . $flag;
} else {
$message = 'Wrong. Try Again';
}
}

//检查$_SERVER['PHP_SELF']是否以utils.php结尾
if (preg_match('/utils\.php\/*$/i', $_SERVER['PHP_SELF'])) {
exit("hacker :)");
}

//检查$_SERVER['REQUEST_URI']中是否出现show_source
if (preg_match('/show_source/', $_SERVER['REQUEST_URI'])){
exit("hacker :)");
}

//如果show_source不为空,则高亮用basename从$_SERVER['PHP_SELF']中取出的文件
if (isset($_GET['show_source'])) {
highlight_file(basename($_SERVER['PHP_SELF']));
exit();
}else{
show_source(__FILE__);
}

注意的点

1
$_SERVER['PHP_SELF']指当前执行脚本的文件名,与 document root 有关。例如,在地址为 http://example.com/foo/bar.php 的脚本中使用 $_SERVER['PHP_SELF'] 将得到 /foo/bar.php。[__FILE__](https://www.php.net/manual/zh/language.constants.predefined.php) 常量包含当前(例如包含)文件的完整路径和文件名。 如果 PHP 以命令行模式运行,这个变量将包含脚本名。
1
$_SERVER['REQUEST_URI']比$_SERVER['PHP_SELF']多了参数部分
1
2
3
4
5
6
7
8
9
10
11
//basename() 函数返回路径中的文件名部分。
//一个例子:
<?php
$path = "/testweb/home.php";

//Show filename with file extension
echo basename($path) ."<br/>";

//Show filename without file extension
echo basename($path,".php");
?>

注意如果路径是”index.php/config.php/%bb”这样的,basename返回结果为”config.php”,会将路径中的非ascii码去掉且取出最后一个’/‘后的文件名

解题过程

第一段代码中的secret在文件中并没有定义,猜测在utils.php中,注意代码后半部分,有用highlight函数高亮文件,可以想到是文件包含漏洞,想办法让”highlight_file(basename($_SERVER[‘PHP_SELF’]))”显示出utils.php的文件源码。

首先我们要让show_source不为空,但是show_source会被匹配到,观察正则表达式,发现可用url编码绕过

1
2
payload
?show_%73ource=1

接下来要想办法让basename($_SERVER[‘PHP_SELF’])==”utils.php”,我们可以想到既然$_SERVER[‘PHP_SELF’]会取到域名后面的路径,可不可以让它为”utils.php”呢?答案是。。。不行。因为这里有两个问题,一个是前面正则匹配规定$_SERVER[‘PHP_SELF’]不能以utils.php结尾,另一个是在域名后面加utils.php会访问到utils.php导致无法执行题目的这段代码,但是我们注意到,basename函数还没有用到,并且这个函数会将路径中的最后一个文件名返回并去掉非ascii码,因此我们可以构造

1
2
payload
index.php/utils.php/%aa?show_%73ource=1

这既符合访问的页面是题目代码,又符合不以utils.php结尾,并且basename返回的文件名是utils.php,所以会得到utils.php中的内容

image-20240618010703253

因为直接在utils.php中给出flag,所以解题结束。

小结

夜深了,该睡觉了。