open_basedir
介绍
open_basedir
是PHP设置中为了防御PHP跨目录进行文件(目录)读写的方法,所有PHP中有关文件读、写的函数都会经过open_basedir
的检查。open_basedir
实际上是一些目录的集合,在定义了open_basedir
以后,php可以读写的文件、目录都将被限制在这些目录中。
设置open_basedir
的方法,在linux下,不同的目录由”:”分割,如"/var/www/:/tmp/"
;在Windows下不同目录由”;”分割,如"c:/www;c:/windows/temp"
。这里我把它设成了/tmp
和/var/www/html/sandbox
两个目录,这时候我们无论是从sandbox
的文件读取或者是直接访问其他目录的文件,都是不行的。
r-cursive
这道题目好多个月前的了,不过那时候我太菜了,不知道这道题目的质量高,现在蓦然回首,发现很不错。题目代码如下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$token = sha1($_SERVER['REMOTE_ADDR']);
$dir = '../sandbox/'.$token.'/';
is_dir($dir) ?: mkdir($dir);
is_file($dir.'index.php') ?: file_put_contents($dir.'index.php', str_replace('#SHA1#', $token, file_get_contents('./template')));
switch($_GET['action'] ?: ''){
case 'go':
header('Location: http://'.$token.'.sandbox.r-cursive.ml:1337/');
break;
case 'reset':
system('rm -rf '.$dir);
break;
default:
show_source(__FILE__);
}
访问?action=go
之后,我们会自动跳到属于自己ip的沙盒中,打开题目,我们就能看到源码1
2
3
sha1($_SERVER['REMOTE_ADDR']) === 'f6e5575f93a408c5cb709c73eaa822cb09b4d0f7' ?: die();
';' === preg_replace('/[^\W_]+\((?R)?\)/', NULL, $_GET['cmd']) ? eval($_GET['cmd']) : show_source(__FILE__);
这个正则表达式是PHP中的一种递归模式,匹配形如a(b(c()))
的字符串,然后在最后加一个;
。题目还存在一个open_basedir
的限制,我就用我本地的环境来模拟。首先phpinfo()
肯定可以执行通过phpinfo
我们也能找到open_basedir
的相关信息接下来就要思考可以去执行什么命令,不能有参数,说明很多函数都是无法执行的。这里用的方法是eval(end(getallheaders()))
,其中end
可以替换为其他函数,反正getallheaders()
返回的是一个数组,就看你使用的header
在什么位置。然后就可以构造header
来进行任意命令执行。题目还仅用了执行系统命令,经过测试,系统命令是不受open_basedir
的限制的。由于限制的存在,当我们想列出上一个目录的时候,报错了。所以首先,我们需要绕过限制来列目录,参考了这篇文章用到的payload
是这样的$file_list = array();$it = new DirectoryIterator("glob:///*");foreach($it as $f) {$file_list[] =$f->__toString();}print_r($file_list);
成功列出根目录网站根目录假设我们的flag是网站根目录下的flag.php
,要怎么去读到他呢?
这时候我们要想到一个问题,它是怎么去设置open_basedir
的?在这道题目里面,每个ip都被分配到了一个根据你的ip sha1加密后的目录,都是独立的,如果这样的话,通过apache
静态配置是不可行的,只能用php去动态设置。这里它用到的方法是用auto_prepend_file
它利用auto_prepend_file
去载入/var/www/sandbox/init.php
来达到动态设置open_basedir
的目的。还可以发现,配置里使用了mod_vhost_alias
模块看一下文档里对这个模块的描述又因为题目里的Host
是长成这样的Host: 39093088bf9a9d33d5dd5b973cc1232e2145ee49.sandbox.r-cursive.ml
,联想到,有可能动态设置open_basedir
的时候是通过Host
去获取的,所以,这里把Host
头的39093088bf9a9d33d5dd5b973cc1232e2145ee49.sandbox
去掉,就达成了沙箱逃逸的目的。然后拿flag即可