基础知识:
open_basedir 是php.ini 中的 一个配置选项。可以用作与 将用户访问文件的活动范围限制在指定的区域 , 假设 open_basedir=/var/www/html:/tmp/ , 那么通过 web 1 访问服务器的用户 就无法获取服务器上除了 /var/www/html/web1 和 /tmp 这两个目录 以外 的文件。
注意: open_basedir 指定的限制实际上是前缀 而不是 目录名,
举个例子, 若“open_basedir” = /dir/user 那么目录 /dir/user 和 /dir/user1 都是可以访问的。。
所以,如果要访问限制在仅为指定的目录,请用斜线结束路径名。例如 设置成:“open_basedir”
=/dir/user/
另外。 open_basedir 也可以同时设置多个目录。在windows中 用分号分割目录。
例如:
open_basedir=/home/wwwroot/home/web1/:/tmp/
下面说一下如何绕过 open_basedir:
利用命令执行函数绕过:
open_basedir 对命令执行函数没有限制,我们可以使用system()试一下。在前面代码加上。
确实能够访问的。且不受open_basedir限制:
一般情况下,system()等危险函数可能会被disable_functions 禁用,因此 运用场景不多
利用sysmlink()函数bypass:
符号链接:
1,符号链接又叫软连接,是一类特殊的文件,这个文件包含了另一个文件的路径名(绝对路径或者相对路径)
2,在对符号文件进行读或者写的 操作的时候,系统会自动把该操作转换为对源文件的操作。
3,但删除链接文件时,系统仅仅删除链接文件,而不删除源文件本身。
symlink()
symlink()函数创建一个从指定名称连接的现存目标文件开始的符号连接。如果成功,该函数返回TRUE。如果失败,则返回FALSE。
官方:symlink ( string $target
, string $link
) : bool
symlink() 对于已有的 target
建立一个名为 link
的符号连接。
target:
连接的目标。link
:连接的名称。
bypass:
readlink() 函数返回符号连接指向的目标。
注释:这不是一个HTML连接,而是一个文件系统中的连接。 类似windows的快捷方式,不过是文件和文件连在一起了。
利用方式:
保存后允许。
查看该php 文件后,后台便生成了两个目录 和一个名为exp 的链接符号:
我们可以试着在网页上访问一下 exp 。
这就轻松过滤掉 open_basedir 轻松访问到 /etc/passwd 了
原理 就是:创建一个链接文件7ea,用小队路径指向A/B/C/D,再创建一个链接文件exp 指向 7ea/../../../../etc/passwd。 其实指向的就是A/B/C/D/../../../../etc/passwd,其实就是/etc/passwd. 这时候删除7ea 再创一个7ea目录,但exp还是指向7ea/../../../etc/passwd,所以就成功跨到/etc/passwd了。
重点在这四句话:
symlink("A/B/C/D","7ea");symlink("7ea/../../../../etc/passwd","exp");unlink("7ea");mkdir("7ea");
是不是有被惊艳到。
注意:
pyload构造的注意点就是:要读的文件需要往前跨多少路径,就得创建多少层的子目录。然后输入多少个 ../来设置目标文件。
利用glob://伪协议绕过:
glob://伪协议。
glob:// 查找匹配的文件路径模式
glob://是php自5.3.0版本起开始生效的一个用来筛选目录的伪协议,其用法示例如下:
getFilename(), $f->getSize()/1024);}?>
Bypass
只是用glob://伪协议是无法直接绕过的,它需要结合其他函数组合利用,主要有以下两种利用方式,局限性在于它们都只能列出根目录下和open_basedir指定的目录下的文件,不能列出除前面的目录以外的目录中的文件,且不能读取文件内容。
方式1——DirectoryIterator+glob://
DirectoryIterator是php5中增加的一个类,为用户提供一个简单的查看目录的接口。
DirectoryIterator与glob://结合将无视open_basedir,列举出根目录下的文件:
__toString().'
');}?>
输入glob:///*
即可列出根目录下的文件,但是会发现只能列根目录和open_basedir指定的文件:
既然能列出 根目录内容,或许也已经不错了
方式2——opendir()+readdir()+glob://
opendir()函数为打开目录句柄,readdir()函数为从目录句柄中读取条目。
这里结合两个函数来列举根目录中的文件:
"; } closedir($b);}?>
效果和方式1是一样的,只能Bypass open_basedir来列举根目录中的文件,不能列举出其他非根目录和open_basedir指定的目录中的文件。
评价是有点鸡肋
利用chdir()与ini_set()组合bypass
基本原理:
这种利用方式跟open_basedir存在缺陷的处理逻辑有关
这里可以结合一道ctf题来练习。
先了解 一下 ini_set:
范例
Example #1 设置一个 ini 选项
echo ini_get('display_errors');
if (!ini_get('display_errors')) {
ini_set('display_errors', '1');
}
echo ini_get('display_errors');
?>//ini_set 其实就是设置一个选项的值。
注意,不是所有的选项都是可以 用此函数改变的。
其次也最为关键的是:open_basedir的设置范围不是随便的,它是“收紧”的,而不是拓宽的。意思你只能在open_basedir()
所限制的范围中选择更详细的范围来设置(也就是收紧、缩小范围)
任何一个目录其实都包含有 . 和 .. 这两个目录:
通过 ini_set('open_basedir', '..') 的设置,就可以全区允许访问 . . 这个目录,众所周知 。。 这个目录就是上级目录,既然允许我们访问上级目录那就通过 chdir () 不断的访问上一级,就可以到达根目录。
结合一道CTF题:
error_reporting(0);
highlight_file(__FILE__);
eval($_POST[1]);
这个是题目源码。
先传个1=phpinfo();
看看有没有禁用什么函数。
这题应该用 反弹shell 应该是可以做出来的。
但是我们要理解的是open_basedir()
再看看open_basedir :
只允许访问 /var/www/html
那我们就可以 通过 ini_set 来设置 open_basedir 了。
pyload:
1=mkdir('a');chdir('a');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');print_r(scandir('.'));
先在当前目录下创建 a目录,然后cd到a目录。设置 open_basedir 为 .. 然后 cd 四次 .. 其实可以多cd几次 确保到达根目录。最后打印当前目录 print_r(scandir('.'));
得到根目录的flag文件
最后用readfile('/ctfshowflag'); 读取内容。
别忘了 还要iniset('open_basedir', '/ ') 才能全局使用 /
参考文章:浅谈几种Bypass open_basedir的方法 - Hookjoy - 博客园 (cnblogs.com)
来源地址:https://blog.csdn.net/snowlyzz/article/details/126310439