[鹤城杯 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 。

相关推荐
汤姆yu35 分钟前
Gemini 4 Argon模型综述:技术、能力与实际使用指南
网络·安全·web安全·ai·大模型
搭贝42 分钟前
上厕所的时间搭好一套系统:AI自动生成实测
开发语言·人工智能·低代码·ai·php·搭贝
智感子1 小时前
智能称重·数据上云:从仪表读数到可追溯的计量凭证
开发语言·php
Chengbei116 小时前
拒绝无效洞!蚂蚁Src榜一Clown 2.0 SRC SKill 第二代带状态闭环的白盒 & 黑盒审计 Skill
网络·人工智能·安全·web安全·网络安全·自动化·安全架构
2301_777998346 小时前
TCP协议:滑动窗口与流量控制
服务器·网络·网络协议·tcp/ip·php
XLYcmy7 小时前
PDF 论文处理器 — 优势与功能文档
大数据·python·网络安全·pdf·dify·rag·漏洞检测
一条破秋裤9 小时前
01_字符设备基本概念_从分类到LED控制链路
开发语言·php
唐青枫9 小时前
别只会给页面加 ROLE_ADMIN:Symfony Security 从登录到资源授权实战
php·symfony
xingpanvip10 小时前
星盘接口开发文档:推算星座接口指南
前端·php
白帽攻防录11 小时前
SRC 挖洞:V8 Turbofan 沙箱逃逸深度复盘,CVE-2026-6307 一根长矛怎么刺穿 Chrome 两道边界
网络·chrome·安全·网络安全·浏览器安全