当前位置: 首页 > news >正文

PHP无参RCE

CTF WriteUp:easy - phplimit (PHP无参RCE深入解析)

0x01 题目代码与分析

<?phpif(';'===preg_replace('/[^\W]+\((?R)?\)/','',$_GET['code'])){eval($_GET['code']);}else{show_source(__FILE__);}?>

核心正则分析:/[^\W]+\((?R)?\)/

这个正则是整道题的关键,我们拆解来看:

  • [^\W]+:匹配一个或多个“非非单词字符”,即匹配字母、数字、下划线(等同于\w+)。这里主要是匹配函数名。
  • \(\):匹配左右括号。
  • (?R)?:核心中的核心!?R代表递归匹配整个正则表达式,?表示可选(0次或1次)。

正则的作用:
它只匹配纯字母加括号组成的无参函数调用,且允许函数嵌套。
例如:a(b(c()))会被匹配,替换为空后,剩余;,通过判断进入eval

限制条件:

  1. 不能传入参数:括号里不能有字符串、数字、变量(如a('1')a($b)都会被正则拒绝)。
  2. 只能使用无参函数嵌套

解题核心思路:
要想执行任意代码(如system('ls')),我们必须找到一个返回值可控的无参函数,将它作为内层函数的返回值传给外层函数。


0x02 解法一:利用 HTTP 请求头 (Apache / PHP >= 7.3)

1. 核心函数:getallheaders()

getallheaders()会获取当前请求的所有 HTTP 头信息,返回一个数组。由于 HTTP 头(如 User-Agent、Cookie 等)是我们可以完全控制的,这就变相突破了“不能传参”的限制。

2. Payload 构造

GET ?code=eval(next(getallheaders())); HTTP/1.1 Host: xxx User-Agent: phpinfo(); ...
  • getallheaders():获取所有请求头数组。
  • next():将数组内部指针向后移动一位,并返回当前元素的值。由于不同服务器对请求头的排序可能不同,通常next()可以跳过默认的Host字段,指向我们可以控制的User-Agent等字段。
  • eval():执行next()返回的字符串(即我们设置的phpinfo();)。

⚠️ 关键知识点:Nginx 与 Apache 的环境差异(你提出的问题)

  • 传统认知(PHP < 7.3)getallheaders()是 Apache (mod_php) 的专属函数,在 Nginx (php-fpm) 下调用会报错Call to undefined function。因此老 WriteUp 说 Nginx 下不能用。
  • 当前现状(PHP >= 7.3)从 PHP 7.3 开始,getallheaders()被移植到了 FastCGI/FPM 模式中!所以现在在 Nginx + PHP 7.3+ 的环境下,getallheaders()是可以正常使用的。
  • 结论:如果你的 Nginx 靶机 PHP 版本 >= 7.3,用这个方法完全没问题;如果版本低,就会报错。

0x03 解法二:利用全局变量 (全环境通用,无视版本)

如果getallheaders()被禁用或者 PHP 版本低于 7.3 导致 Nginx 下不可用,我们就需要找其他返回值可控的函数。最经典的就是get_defined_vars()

1. 核心函数:get_defined_vars()

该函数返回由所有已定义变量组成的数组,包括$_GET,$_POST,$_COOKIE,$_SERVER等。由于我们可以控制 GET 传参,这就相当于我们有了一个可控的数据源。

2. 数组结构分析

当我们发送?code=eval(...);&b=phpinfo();时,get_defined_vars()的返回值大致如下:

Array([0]=>Array// 这是 $_GET 数组([code]=>eval(...);[b]=>phpinfo();)[1]=>Array// 这是 $_POST 数组...)

我们的目标是取到最内层的phpinfo();这个字符串。

3. Payload 构造

GET ?code=eval(next(current(get_defined_vars())));&b=phpinfo(); HTTP/1.1
  • get_defined_vars():获取所有变量大数组。
  • current():获取当前指针元素,默认指向第一个元素,即$_GET数组。
    (注:PHP 7.3 前用current,PHP 8.1 后current对内部指针行为有变化,部分环境可能需要用resetarray_pop等)
  • next():将$_GET数组的指针从code移动到b,并返回b的值,即字符串phpinfo();
  • eval():执行该字符串。

0x04 解法三:纯目录遍历读取 (无需注入代码)

有时候eval被禁用,或者我们不需要执行系统命令,只需要读取 Flag 文件,可以使用纯文件操作函数的嵌套。

1. 核心思路

利用scandir()列目录,配合数组操作函数找到 flag 文件,最后用readfile()file_get_contents()读取。

2. Payload:读取当前目录倒数第二个文件

通常目录结构为['.', '..', 'flag.php', 'index.php']。倒数第二个往往是 flag。

?code=readfile(next(array_reverse(scandir(getcwd()))));
  • getcwd():获取当前工作目录路径。
  • scandir():列出目录中的文件和目录。
  • array_reverse():将数组反转,原来的倒数第二变成正数第二。
  • next():跳过第一个(原最后一个index.php),指向第二个(原倒数第二flag.php)。
  • readfile():读取并输出文件内容。

3. Payload:读取上级目录的 flag

如果 flag 在上一级目录,需要结合chdir()改变当前目录,因为scandir()接受目录路径参数。

?code=readfile(next(array_reverse(scandir(dirname(chdir(dirname(getcwd())))))));
  • 这里的巧妙之处在于chdir()成功返回1(true),失败返回false,但它确实改变了工作目录。嵌套在dirname()中,dirname(1)会返回当前目录.或配合改变后的路径继续向上。

0x05 总结与提炼

这道题是 PHP 无参 RCE 的母题,掌握它就掌握了一大类题。请记住以下核心应对策略:

场景可用 Payload备注
有请求头控制权限eval(end(getallheaders()));(修改最后请求头)
eval(next(getallheaders()));(修改User-Agent等)
Apache全版本可用;Nginx需 PHP >= 7.3。
无请求头控制/老版本Nginxeval(next(current(get_defined_vars())));&1=phpinfo();
eval(end(get_defined_vars()));(用POST传参)
最通用,无视服务器类型和PHP版本。
只需读文件,无注入点readfile(next(array_reverse(scandir(getcwd()))));利用数组指针操作函数(next,end,array_pop,array_rand)。
需要跳目录读文件readfile(array_rand(array_flip(scandir(dirname(chdir(dirname(getcwd())))))));array_flip交换键值配合array_rand随机读取也是常见绕过姿势。

划重点:做题时,优先尝试getallheaders(),因为构造简单;如果报错未定义函数,立刻切换思路使用get_defined_vars(),这是保底解法!

http://www.jsqmd.com/news/882269/

相关文章:

  • 医疗物联网异常检测:八种机器学习算法实战对比与选型指南
  • Armv9 SME指令集:矩阵运算加速原理与优化实践
  • 量子生成模型:原理、优势与应用场景解析
  • 终极指南:3种简单方法快速重置JetBrains IDE试用期
  • 大麦网抢票神器终极指南:告别黄牛票的Python自动化解决方案
  • ARM ETE协议异常处理与指令追踪技术解析
  • 3分钟快速修复:洛雪音乐六音音源终极解决方案
  • 增强采样与力匹配结合:高效构建高精度粗粒化分子动力学模型
  • 3分钟快速修复洛雪音乐播放问题:六音音源完整指南
  • 音频输入系统——第二周
  • 直接去偏机器学习:用Bregman散度统一因果推断与协变量平衡
  • 基于CNN的遥感影像土地利用分类:从原理到斐济城市扩张监测实践
  • JMeter压测8大实战陷阱:从线程模型到SLA验证
  • 嘉兴GEO优化公司2026年度深度评测选型指南 - 品牌报告
  • 卷积神经网络(CNN)与深度学习视觉应用综述
  • 我用 GPT-5.5 跑了一周行政工作:会议纪要、邮件整理,到底能省多少时间?
  • Windows Audio服务启动失败?除了疑难解答,你还需要检查这些容易被忽略的设置
  • 机器学习优化活性粒子信息引擎:突破热力学极限的非平衡控制
  • 苏州评价高的宠物基地口碑推荐榜单 - 品牌排行榜
  • 基于BERT与LSTM的抽取式新闻摘要实战:从原理到实现
  • BetterJoy:让Switch手柄在PC上完美工作的终极适配工具
  • 2024终极指南:如何用微信红包助手快速抢到所有红包
  • Python Pickle安全新方案:基于源码分析的机器学习模型安全加载实践
  • 数据集上新:柬埔寨环境健康入户调查
  • DownKyi终极指南:5步轻松下载B站高清视频的完整解决方案
  • Week 1:机器学习入门与核心框架
  • 阿里云服务器CPU 100%排查指南:识别伪装挖矿病毒的三步法
  • C166微控制器复位向量重定位技术详解
  • FPGA在遥感机器学习中的优势与优化实践
  • 告别误报!用SCTransNet+Transformer搞定红外小目标检测(附PyTorch实战代码)