[鹤城杯 2021]EasyP

考察PHP
题目源码

<?php
include 'utils.php';

if (isset($_POST['guess'])) {
    $guess = (string) $_POST['guess'];
    if ($guess === $secret) {
        $message = 'Congratulations! The flag is: ' . $flag;
    } else {
        $message = 'Wrong. Try Again';
    }
}

if (preg_match('/utils\.php\/*$/i', $_SERVER['PHP_SELF'])) {
    exit("hacker :)");
}

if (preg_match('/show_source/', $_SERVER['REQUEST_URI'])){
    exit("hacker :)");
}

if (isset($_GET['show_source'])) {
    highlight_file(basename($_SERVER['PHP_SELF']));
    exit();
}else{
    show_source(__FILE__);
}
?> 

关键代码

if (preg_match('/utils\.php\/*$/i', $_SERVER['PHP_SELF'])) {
    exit("hacker :)");
}

if (preg_match('/show_source/', $_SERVER['REQUEST_URI'])){
    exit("hacker :)");
}

if (isset($_GET['show_source'])) {
    highlight_file(basename($_SERVER['PHP_SELF']));
    exit();

先介绍三个函数
$_SERVER['PHP_SELF']获取当前页面的目录地址和脚本文件名
$_SERVER["REQUEST_URI"]函数获取当前页面的目录地址和脚本文件名,包括参数
basename函数用于从文件路径中提取文件名部分
示例
网址:http://yeran:6789/webphprce/test.php?a=1
$_SERVER['PHP_SELF'] 得到:/webphprce/test.php
$_SERVER['REQUEST_URI'] 得到:/webphprce/test.php?a=1
basename($_SERVER['PHP_SELF']) 得到 test.php

观察第一个if的正则匹配
检测 字符串结尾 ($) 是否是:
utils.php utils.php/ utils.php//...
严格匹配末尾
basename函数截取文件名
在使用默认语言环境设置时,会删除文件名开头的非 ASCII 字符和中文

所以在只要在utils.php后面加个非ASCII码的东西(实现utils.php加一个乱码)就可以绕过第一个if
所以利用basename函数可以恢复原来访问的utils.php

第二个if正则匹配:
出现show_source输出hacker
利用url编码绕过(还可以利用show[source或者show.source绕过)

最终payload

/index.php/utils.php/%ff?%73how_source=1
或者
/index.php/utils.php/%ff?%73%68%6f%77%5f%73%6f%75%72%63%65=1

payload前面需要加一个index.php
因为当传入/index.php/utils.php时请求的仍是index.php(在index.php页面触发漏洞)
而当basename()处理后,highlight_file()得到的参数为了utils.php,从实现任意文件包含

posted @ 2025-08-18 23:51  yeran烨染  阅读(15)  评论(0)    收藏  举报