PHP open_basedir 绕过

wen PHP项目 3

本文目录导读:

PHP open_basedir 绕过

  1. 目录导读
  2. open_basedir 是什么?——PHP 安全机制的基石
  3. 绕过场景解析:为什么它会失效?
  4. 五大经典绕过手法(含代码实例)
  5. 实战问答:开发者最关心的 5 个问题
  6. 防御策略:如何彻底锁死 open_basedir
  7. 安全是动态的博弈


PHP open_basedir 绕过全解析:从原理到防御的实战指南**


目录导读

  1. open_basedir 是什么?——PHP 安全机制的基石
  2. 绕过场景解析:为什么它会失效?
  3. 五大经典绕过手法(含代码实例)
    • 1 符号链接攻击(Symlink)
    • 2 软链接 + 目录穿越组合技
    • 3 ini_set 限制与 .user.ini 的博弈
    • 4 利用 realpath() 缓存漏洞
    • 5 通过 glob:// 协议探测文件结构
  4. 实战问答:开发者最关心的 5 个问题
  5. 防御策略:如何彻底锁死 open_basedir
  6. 安全是动态的博弈

open_basedir 是什么?——PHP 安全机制的基石

open_basedir 是 PHP 配置指令,用于限制 PHP 脚本可访问的文件系统路径,它通过将可访问范围限定在指定目录(及子目录)内,防止攻击者读取或写入系统关键文件(如 /etc/passwd)。但它的本质是一个“路径前缀匹配”机制,而非内核级沙箱,因此存在逻辑绕过空间。


绕过场景解析:为什么它会失效?

常见的失效场景包括:

  • 符号链接被允许:当 PHP 脚本所在目录允许创建符号链接时,攻击者可构造链接指向外部目录。
  • realpath() 缓存陷阱:PHP 内部缓存了文件路径的解析结果,若路径被 unlink 后重建,可能绕过检查。
  • ini_set 的时差漏洞:某些配置修改在请求生命周期内未立即生效。
  • 流包装器的利用glob://phar:// 等协议可绕过前缀匹配。

五大经典绕过手法(含代码实例)

1 符号链接攻击

symlink("/etc/passwd", "/tmp/evil_link");
include("/tmp/evil_link"); // 读取成功

原理:open_basedir 检查的是“路径字符串”,而不是最终解析的物理文件,若允许 symlink(),则可指向任意位置。

2 软链接 + 目录穿越组合技

若目标目录存在一个软链接指向外部,构造 ../../../../etc/passwd 时,PHP 仅对原始路径做前缀检查,而忽略链接目标。

3 ini_set 限制与 .user.ini 的博弈

在支持 .user.ini 的 CGI/FPM 模式下,攻击者可上传 .user.ini 设置 open_basedir = /tmp,但若代码中有 ini_set('open_basedir', '/var/www')部分版本存在时差:新配置只对后续脚本生效,攻击者可在同一请求中先执行文件操作再触发配置修改。

4 利用 realpath() 缓存漏洞

mkdir("/tmp/a");
symlink("/tmp/a", "/tmp/b");
phpinfo(); // 此时系统缓存了 /tmp/b 的路径
unlink("/tmp/b");
mkdir("/tmp/b");
// 后续访问 /tmp/b 时,PHP 可能仍按旧缓存解析

5 通过 glob:// 协议探测文件结构

glob:// 允许通配符匹配,尽管不能读取内容,但能确认文件是否存在,从而为后续攻击提供情报。


实战问答:开发者最关心的 5 个问题

Q1: 设置 open_basedir 后,为什么仍能读取 /etc/passwd
A: 最常见原因是符号链接未禁用,或使用了 realpath() 缓存漏洞,检查 allow_url_fopendisable_functions 是否同时配置。

Q2: 如何测试一个环境是否可绕过?
A: 尝试 symlink() 创建链接,使用 glob:// 进行目录探测,或者通过 ini_set 结合 .user.ini 验证配置生效时机。

Q3: open_basedir 能否阻止 PHP 包含远程文件?
A: 不能,它只针对本地文件系统,需配合 allow_url_include=Off 使用。

Q4: 最安全的配置组合是什么?
A: open_basedir + disable_functions(禁用 symlinkexec 等)+ 禁用危险流包装器(phar://expect://)+ 禁用 ini_set 中的动态修改。

Q5: 绕过后能否执行系统命令?
A: 通常不能直接执行命令,但可结合其他漏洞(如文件包含 + 日志投毒)提升为 RCE。


防御策略:如何彻底锁死 open_basedir

  1. 禁用危险函数
    disable_functions = symlink, exec, shell_exec, passthru, ini_set(除非业务必需)。
  2. 严格限制路径分隔符
    确保 open_basedir 路径使用绝对路径,并参考实时目录(pwd)而非相对路径。
  3. 关闭不必要的流包装器
    php.ini 中设置 allow_url_fopen = Off 并移除 phar 扩展。
  4. 升级 PHP 版本
    最新版已修复 realpath() 缓存漏洞(PHP 8.0+)。
  5. 使用更严格的沙箱
    若允许符号链接,可用 Kernel-level 沙箱(如 dockernsjail)替代,提供内核级隔离。

安全是动态的博弈

open_basedir 并非万能钥匙,而是 PHP 安全体系中的一环,开发者应始终结合 disable_functions、文件系统权限、流包装器管理和日志审计构建纵深防御。在攻防对抗中,没有一劳永逸的配置,只有不断更新的认知,定期审计代码路径,并模拟攻击测试,才能最大限度降低风险。

抱歉,评论功能暂时关闭!