Two objectives: log into the admin panel, and find the hidden text file in the flags folder. That's the whole mission statement. What followed was considerably less simple, especially given my well-documented distaste for databases.


Enumeration

nmap -T4 -n -sC -sV -Pn -p- 10.146.148.157
nmap basic scan — ports 22 and 80 open

Port 22 and Port 80. Started with a site visit, and also ran the full vuln scan in parallel:

nmap -sS -Pn -sC -sV --script=vuln -T4 -A 10.146.148.157
vuln scan — CVEs, enumerated subdomains, discovered credentials, known exploits

The output of the above Nmap is a bit lengthy to post here. Why is it my favorite Nmap syntax? It lists all of the CVEs and CNVDs, their severity, and available exploits. In this case: possible HTTP access points, enumerated subdomains that felt like key evidence, discoverable credentials, and more known vulnerabilities than necessary. Filed away for later.


Site Reconnaissance

Target web app landing page — Olympics-themed

Most nav menu items were dead links. Two that weren't: /login and /adminLogin007.php — that second one surfaced during the vuln scan.

adminLogin007.php — restricted area

Restricted area. Any time I see a restricted area, it's like a button labeled "Don't Touch." I have honed the art of self-control.

login.php — standard login form

View Source on /login.php showed a client-side filter living at /script.js. That's the first real lead.

script.js — client-side filter blocking SQL keywords before POST

script.js blocked a specific keyword list — or, and, union, select, ", ' — before any POST request reached functions.php. Client-side only. The filter didn't exist server-side. That's the opening.

Ran Gobuster while planning the bypass:

gobuster dir -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt \
-x html,js,txt,php,db,json,log \
-u http://10.146.148.157
Gobuster running — directories and file types enumerated

SQLi — Login Bypass

Intercepted the login POST in Burp Suite and sent it to Repeater:

Burp Suite intercepted POST to functions.php

The client-side filter blocked OR — but the filter was JavaScript, not server-side. Burp bypasses it entirely. The payload that worked:

username=a' || 1=1; -- -&password=a&function=login

|| instead of OR. The original attempt with OR failed. That distinction matters — the server was doing some filtering of its own, just not catching the pipe operator.

Burp Repeater — SQLi payload in username field dashboard.php — authenticated

In. Gobuster hadn't finished yet, but mail.log was already visible in the results. Filed away.

Gobuster partial results showing mail.log

Database Manipulation — Recursive Filter Bypass

The dashboard had an editable leaderboard. Each edit generated a POST to /edit_leaderboards.php. The input was reaching the database — confirmed by updating medal counts and watching the changes propagate, including one that changed China's data instead of USA's, which was clarifying in its own way.

The real discovery came from testing what the server would actually accept. Strings worked — confirmed by updating a country name to "ME" and watching it stick. Look at me. I won all of these medals by myself. Very impressive, me.

Leaderboard showing country updated to ME — string injection confirmed

The server was filtering SQL keywords server-side as well. Standard payloads came back blank. The breakthrough was realizing the filter was doing a simple string match — so nesting the keyword inside itself bypassed it:

seSELECTlect

When SELECT was stripped by the filter, seSELECTlect collapsed into select. Plain sight obfuscation.

Recursive keyword bypass confirmed — seSELECTlect surviving filter Gobuster complete results

mail.log — Credential Recovery and Table Drop

mail.log contained the instruction to DROP the table — and the admin credentials. The recursive bypass made the final payload possible:

rank=1&country=&gold=22; DROP TABLE users -- -&silver=21&bronze=12345
DROP TABLE users payload sent via Burp

Database corrupted. Logged into the admin panel with the credentials from mail.log:

Admin login with mail.log credentials Admin dashboard — Flag 1 visible, database alterations confirmed

Flag 1. And my database alterations were still visible, which made it that much sweeter.

Gobuster had also confirmed a /flags directory:

Gobuster confirming /flags directory

SSTI — Twig CVE-2024-45411

The admin account had an additional nav item: Profile. A photo upload field — the kind that deserves immediate scrutiny.

Admin profile page with photo upload field

Tested for server-side template injection:

{{7x7}}
Profile field with {{7x7}} submitted Output: 49 — SSTI confirmed, input executed as code not treated as string

{{7x7}} was not treated as a string. It returned 49. That's SSTI confirmed.

Remember that massive vuln Nmap from the beginning? That's coming in handy right now. The web app runs Twig v2.14.0 — exploitable via CVE-2024-45411, a sandbox bypass vulnerability. The math really maths.

Twig v2.14.0 identified — CVE-2024-45411 sandbox bypass SSTI payload executing — www-data shell context confirmed

RCE achieved. From here the path to /flags is yours to find.

Terminal prompt — you know what to do from here

Full Attack Chain

nmap → ports 22 + 80, vuln scan surfaces CVEs and Twig version
→ /login.php client-side filter in script.js → Burp bypass
→ SQLi login: a' || 1=1; -- - → dashboard access
→ edit_leaderboards.php → string injection confirmed
→ recursive keyword bypass: seSELECTlect
→ mail.log → DROP TABLE users → admin credentials
→ admin login → Flag 1
→ Profile upload → {{7x7}} → SSTI confirmed
→ Twig CVE-2024-45411 sandbox bypass → RCE → /flags