// HackTheBox

Writeup

CVE-2019-9053 (CMS Made Simple <=2.2.9 unauth SQLi) → staff-group PATH hijack of run-parts

HackTheBoxEasyLinux Jul 21, 2026 3 min read

Recon

Port Service Version
22 SSH OpenSSH 9.2p1 Debian
80 HTTP Apache 2.4.25 (Debian); robots.txt → /writeup/

Two ports, and the web root gives up the lead itself: robots.txt disallows /writeup/, so that path is the first place to look. It hosts a CMS Made Simple install — the generator meta tag and a 2019 copyright date pin down both the software and roughly its version, which matters because CMS Made Simple has a well-known unauthenticated SQL-injection bug from that era.

Anti-scan daemon: one wrinkle first — aggressive nmap or directory brute-forcing (a flood of 404s) trips a defence that bans port 80 for ~30s. The way through is slow, single requests rather than parallel scanning. The SQLi itself hits a valid endpoint that returns 200, so it doesn’t trip the ban and works fine.

Foothold — CVE-2019-9053 (CMS Made Simple <=2.2.9 unauth SQLi)

CMS Made Simple 2.2.9 and earlier carry CVE-2019-9053, an unauthenticated SQL injection in the News module. It’s reachable without logging in via moduleinterface.php?mact=News,m1_,default,0, injecting through the m1_idlist parameter. The injection is boolean/time-blind — you can’t read data out of the response directly, so you infer it one character at a time by asking true/false questions (... like 0x<hex>25 ...) and, for the blind case, wrapping them in sleep() and timing the reply.

The public exploit is Python 2; porting it to Python 3 (exploit/cmsms_sqli3.py) lets it run on a modern box. Grinding the injection extracts a user record from the CMS database:

  • username jkr
  • salt 5a599ef579066807
  • password hash 62def4866937f08cc13bab43bb14e6f7

CMS Made Simple stores passwords as md5(salt + password), so the crack candidate for each wordlist entry is md5("5a599ef579066807" + word). Running that against rockyou.txt recovers the plaintext: raykayjay9.

The password turns out to be reused for the system account, so it works straight over SSH:

$ ssh jkr@10.129.42.53

Privilege Escalation — staff-group PATH hijack of run-parts

As jkr the key detail is group membership: jkr is in the staff group (gid 50). On Debian, staff is meant for local administration, and here it shows: /usr/local/bin is drwx-wsr-x root staff, i.e. group-writable by staff. And jkr’s PATH is /usr/local/bin:/usr/bin:/bin:/usr/games/usr/local/bin comes first, so a binary we drop there shadows the real one of the same name everywhere else.

The thing to shadow is run-parts. A periodic automated root SSH login happens on the box, and the login/MOTD flow invokes run-parts by bare name, resolved through PATH — which for that root session also searches /usr/local/bin first. So we plant our own run-parts there that makes a root-owned copy of bash with the SUID bit set:

$ cp /bin/bash /tmp/rootbash; chmod 4755

On the next root login (~1-2 min) the login flow runs our run-parts as root, creating /tmp/rootbash owned by root with SUID. Launching it with -p (so bash keeps the elevated effective UID instead of dropping privileges) gives a root shell: /tmp/rootbash -p → root.

← All writeups