[鹤城杯 2021]EasyP

鹤城杯 2021EasyP wp

参考博客:

basename()绕过小结

request导致的安全性问题分析

源码分析

首先进入题目,看到代码:

复制代码
<?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__);
}
?> 

其中第一段代码是让我们传入一个 GET 参数 guess 。这个参数值先会经过转义然后跟 secret 强比较。我没有办法绕过,也猜不到 secret 的值是多少,所以这段代码的作用相当于没有。

第二段代码对 $_SERVER['PHP_SELF'] 进行了正则匹配:
复制代码
if (preg_match('/utils\.php\/*$/i', $_SERVER['PHP_SELF'])) {
    exit("hacker :)");
}
$_SERVER['PHP_SELF']

$_SERVER 是一个包含了诸如头信息(header)、路径(path)、以及脚本位置(script locations)等等信息的数组。

PHP_SELF 获取当前执行脚本的文件名,与 document root 有关。

例如,在地址为 http://example.com/foo/bar.php 的脚本中使用 $_SERVER['PHP_SELF'] 将得到 /foo/bar.php。FILE 常量包含当前(例如包含)文件的完整路径和文件名。 如果 PHP 以命令行模式运行,这个变量将包含脚本名。

正则解读
复制代码
/utils\.php\/*$/i
  • /utils\.php\/*$/i : 正则表达式的开始和结束都有斜杠('/')表示正则表达式的开始和结束。
  • utils\.php : 该部分用于匹配字符串 'utils.php'。'.' 表示匹配点字符,点字符在正则表达式中具有特殊意义,因此需要转义。
  • \/*$ : 该部分用于匹配可选的斜杠('/')。'/*' 表示匹配零个或多个斜杠,'$' 表示匹配字符串的结尾。
  • i : 该部分表示在匹配时忽略大小写。

综上所述:就是匹配以 utils.php+0个或多个 / 结尾 的字符串。

第三段代码对 $_SERVER['REQUEST_URI'] 做了一个正则匹配:
复制代码
if (preg_match('/show_source/', $_SERVER['REQUEST_URI'])){
    exit("hacker :)");
}
REQUEST_URI

URI 用来指定要访问的页面。例如访问地址:http://www.baidu.com/index.html?a=1\&b=1

那么 $_SERVER['REQUEST_URI'] 获取到的值就是 /index.html?a=1&b=1

此外 $_SERVER['REQUEST_URI'] 在获取 URL 编码字符时不会进行 URL 解码。利用这一点可以进行绕过。

这里可以参考博客:

PHP中$_SERVER"QUERY_STRING"函数

正则解读

这段正则就是输入的 URL 链接中不能有 "show_source" 字符串。、

最后一段代码:
复制代码
if (isset($_GET['show_source'])) {
    highlight_file(basename($_SERVER['PHP_SELF']));
    exit();
}else{
    show_source(__FILE__);
}

获取一个 GET 参数 show_source ,将 $_SERVER['PHP_SELF'] 的值经过 basename 函数处理后显示出来。

basename() 函数

basename() 函数返回路径中的文件名部分。

语法

复制代码
basename(path,suffix)
参数 描述
path 必需。规定要检查的路径。
suffix 可选。规定文件扩展名。如果文件有 suffix,则不会输出这个扩展名。

举例

php 复制代码
<?php
$path = "/testweb/home.php";

//显示带有文件扩展名的文件名
echo basename($path);

//显示不带有文件扩展名的文件名
echo basename($path,".php");
?> 

输出:

undefined 复制代码
home.php
home
basename() 函数绕过

basename 函数有这样一个特性:在使用默认语言环境设置时,basename() 会删除文件名开头的非 ASCII 字符。

比如:

$_SERVER['PHP_SELF'] 获取到的值 basename() 函数处理后的结果
/dir/index.php index.php
/dir/%ffindex.php index.php
/dir/index.php/%ff index.php
/dir/index.php/%2b +

上面的 %ff 就是一个非 ASCII 字符。而当路径的最后为 ASCII 字符时,basename 函数就会返回该字符。

具体可以去看:basename()绕过小结

绕过

经过上面的分析,GET 传入的参数 show_source 会被匹配到,因此对 "show_source" 做一个 URL 编码后再传入。

此外,在页面请求时传入 /index.php/utils.php/大

服务器会认为请求的页面是 index.php ,因此可以正常返回页面;

$_SERVER['PHP_SELF'] 获取到的值是 /index.php/utils.php/大 ,因为不是以 utils.php/ 结尾,所以可以绕过正则;

因为中文是非 ASCII 字符,所以经过 basename 函数处理后得到的结果就是 utils.php ;

这样就可以读到 utils.php 文件的内容。

测试发现:直接传入 /utils.php/大 的话没有回显。

payload
复制代码
http://node4.anna.nssctf.cn:28806/index.php/utils.php/大?%73%68%6f%77%5f%73%6f%75%72%63%65=1

返回结果:

拿到 flag 。

相关推荐
聚铭网络1 小时前
智能时代 网安护航 | 聚铭网络精彩亮相2026南京市网络安全宣传周活动
网络安全
爱学习的程序媛3 小时前
ICMP协议详解
网络·网络协议·网络安全·通信协议·icmp·网络运维
菩提小狗3 小时前
每日安全情报报告 · 2026-09-14
网络安全·漏洞·cve·安全情报·每日安全
宁之明起(B服)3 小时前
struct2(vulhub靶场)指纹识别+沙箱绕过+反弹shell+webshell
web安全
aixingpan3 小时前
aixingpan.cn API开发文档:api_docs_bichart_natalvssolararc2接口指南
前端·php
三8444 小时前
Java 模板注入(FreeMarker)· 04 · 利用与绕过:payload 全集
java·web安全·freemarker·payload
三8446 小时前
云安全· 01 · 云计算与云安全基础
网络安全·云计算·云安全
执念WRD6 小时前
Fastjson 1.2.83 RCE 漏洞利用
网络·安全·网络安全
子非鱼a7 小时前
【WEB】WriteShell
php
慧都小妮子8 小时前
GB/T 44462.4-2026实施前,DataHub如何管好工业数据链路?
物联网·网络安全·数据安全·工业互联网·opc