[鹤城杯 2021]EasyP

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

相关推荐
北漂Zachary5 小时前
PHP3.0:改变Web开发的里程碑
android·php·laravel
实在智能RPA5 小时前
Agent 如何处理流程中的异常情况?——2026企业级智能体稳定性架构深度拆解
开发语言·人工智能·ai·架构·php
aq55356005 小时前
PHP vs C++ vs 易语言:编程语言终极对比
开发语言·c++·php
星依网络6 小时前
紧急预警!Redis未授权访问漏洞利用与防护实战指南
网络安全
niucloud-admin6 小时前
PHP SAAS 框架常见问题——配置问题——绑定手机号时提示“failed to verify SmsSdkAppld“
php
农村小镇哥7 小时前
PDO介绍+PDO增删改查+PDO事物处理+DPO封装类
php
PinTrust SSL证书7 小时前
Geotrust企业型OV通配符SSL
网络协议·网络安全·小程序·https·云计算·ssl
Chengbei118 小时前
Fortify_SCA_26.1版下载(OpenText SAST(Fortify SCA)26.1 windows/Linux/Mac)全版本下载
运维·安全·web安全·macos·网络安全·系统安全·代码审计
niucloud-admin8 小时前
PHP SAAS 框架常见问题——配置问题——接口请求错误,请检查参数配置或伪静态配置
php
网络安全许木9 小时前
自学渗透测试第18天(Powershell与远程连接)
linux·网络安全·渗透测试·kali linux