目录

[鹤城杯 2021]EasyP

目录

[鹤城杯 2021]EasyP

 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
<?php
include 'utils.php';

// 检查是否设置了 POST 请求中的 'guess' 参数
if (isset($_POST['guess'])) {
    // 将 'guess' 参数转换为字符串
    $guess = (string) $_POST['guess'];

    // 检查是 $guess 否等于 $secret 变量
    if ($guess === $secret) {
        $message = 'Congratulations! The flag is: ' . $flag;
    } else {
        $message = 'Wrong. Try Again';
    }
}

// 检查当前 PHP 文件的路径是否以 'utils.php' 结尾,防止直接访问 utils.php 文件
if (preg_match('/utils\.php\/*$/i', $_SERVER['PHP_SELF'])) {
    exit("hacker :)");
}

// 检查请求 URI 是否包含 'show_source',防止直接访问 show_source 相关的页面
if (preg_match('/show_source/', $_SERVER['REQUEST_URI'])){
    exit("hacker :)");
}

// 检查是否设置了 GET 请求中的 'show_source' 参数
if (isset($_GET['show_source'])) {
    // 如果设置了 'show_source' 参数,高亮显示当前文件的源代码并退出
    highlight_file(basename($_SERVER['PHP_SELF']));
    exit();
} else {
    // 如果未设置 'show_source' 参数,显示当前文件的源代码并退出
    show_source(__FILE__);
}
?>

先看第一部分代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// 检查是否设置了 POST 请求中的 'guess' 参数
if (isset($_POST['guess'])) {
    // 将 'guess' 参数转换为字符串
    $guess = (string) $_POST['guess'];

    // 检查是 $guess 否等于 $secret 变量
    if ($guess === $secret) {
        $message = 'Congratulations! The flag is: ' . $flag;
    } else {
        $message = 'Wrong. Try Again';
    }
}

这部分代码让你去猜 secret 变量的内容,显然是个干扰项

再看第二部分代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// 检查当前 PHP 文件的路径是否以 'utils.php' 结尾,防止直接访问 utils.php 文件
if (preg_match('/utils\.php\/*$/i', $_SERVER['PHP_SELF'])) {
    exit("hacker :)");
}

// 检查请求 URI 是否包含 'show_source',防止直接访问 show_source 相关的页面
if (preg_match('/show_source/', $_SERVER['REQUEST_URI'])){
    exit("hacker :)");
}

// 检查是否设置了 GET 请求中的 'show_source' 参数
if (isset($_GET['show_source'])) {
    // 如果设置了 'show_source' 参数,高亮显示当前文件的源代码并退出
    highlight_file(basename($_SERVER['PHP_SELF']));
    exit();
} else {
    // 如果未设置 'show_source' 参数,显示当前文件的源代码并退出
    show_source(__FILE__);
}
  • 正则表达式 /utils\.php\/*$/i 检查 $_SERVER['PHP_SELF'] 是否以 utils.php 结尾

    • $:这是锚定字符,表示匹配的模式必须出现在字符串的末尾
  • 正则表达式 /show_source/ 匹配包含 “show_source” 字符串的文本

  • $_SERVER['PHP_SELF']:包含当前执行脚本的文件名,是相对于网站根目录的路径

  • $_SERVER['REQUEST_URI']:包含当前请求的完整 URI(包括传参内容)

  • basename():返回路径中的文件名部分,即去掉路径后的部分,只保留文件名

关于 $_SERVER['PHP_SELF']$_SERVER['REQUEST_URI']basename()

假设有以下 PHP 文件:index.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<?php
// 获取当前脚本文件的相对路径
$phpSelf = $_SERVER['PHP_SELF'];

// 获取当前请求的 URI
$requestUri = $_SERVER['REQUEST_URI'];

// 获取当前脚本文件的基本文件名
$baseName = basename($_SERVER['PHP_SELF']);

echo "PHP_SELF: $phpSelf<br>";
echo "REQUEST_URI: $requestUri<br>";
echo "basename: $baseName<br>";
?>

现在,如果通过浏览器访问 http://example.com/index.php?page=1,则输出将是:

1
2
3
PHP_SELF: /index.php
REQUEST_URI: /index.php?page=1
basename: index.php

关于basename()

1
2
3
4
5
6
7
<?php
echo "1) ".basename("/etc/sudoers.d").PHP_EOL;
echo "2) ".basename("/etc/passwd").PHP_EOL;
echo "3) ".basename("/etc/").PHP_EOL;
echo "4) ".basename(".").PHP_EOL;
echo "5) ".basename("/");
?>

以上例程会输出:

1
2
3
4
5
1) sudoers.d
2) passwd
3) etc
4) .
5) 

获得 flag 需满足 :

  1. 参数 show_source 得到传值
  2. URI ($_SERVER[‘REQUEST_URI’])不能包含:show_source
  3. basename($_SERVER['PHP_SELF']) 的结果是:utils.php
  4. 当前 PHP 文件的路径($_SERVER[‘PHP_SELF’])不能以:utils.php/ 结尾

同时满足1、2:用 [ . (空格) 来代替 _ ,即 show[source show source show.source

同时满足3、4:在 utils.php/ 后加一个非 ASCII 编码,例如:%88%ff

payload:index.php/utils.php/%88?show[source=1

https://pic.imgdb.cn/item/6552dee9c458853aefda4ebe.jpg

相关实验

网页代码:

 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
<?php
echo "\$_SERVER['REQUEST_URI']的值:".$_SERVER['REQUEST_URI'];
echo "<br>";
echo "\$_SERVER['PHP_SELF']的值:".$_SERVER['PHP_SELF'];
echo "<br>";
echo "basename(\$_SERVER['PHP_SELF'])的值:".basename($_SERVER['PHP_SELF']);
echo "<br>";

if (preg_match('/utils\.php\/*$/i', $_SERVER['PHP_SELF'])) {
    echo("匹配到正则:/utils\.php\/*$/i");
    echo "<br>";
}else{
    echo("绕过正则:/utils\.php\/*$/i");
    echo "<br>";
}
if (preg_match('/show_source/', $_SERVER['REQUEST_URI'])){
    echo("匹配到正则:/show_source/");
    echo "<br>";
}else{
    echo("绕过正则:/show_source/");
    echo "<br>";
}
if (isset($_GET['show_source'])) {
    echo("参数 show_source 得到传值");
    echo "<br>";
}
?>

https://pic.imgdb.cn/item/65521cf1c458853aef0aacaa.jpg