Skip to content
Back to all posts

HTB: Mirai

· 16 min easy Linux Mirai

The Pi-hole admin panel is a deliberate distraction. Default Raspberry Pi credentials bypass the web surface entirely, passwordless sudo delivers root, and a deleted flag requires raw block device recovery with strings.

Overview

Mirai is a retired Easy-rated Linux machine that teaches a lesson most penetration testers learn the hard way: enumerate the operating system, not just the application. The box presents a Pi-hole v3.1.4 admin panel with a login form, API endpoints, and a queryads.php script that shells out to the blocklist. I spent time testing each of these surfaces and found nothing exploitable. The actual entry point is the host itself: default Raspberry Pi credentials (pi:raspberry) that were never changed after Pi-hole installation.

Privilege escalation is immediate. The pi user has NOPASSWD: ALL in sudoers, the Raspbian default. Root access takes one command. The root flag, however, introduces a forensic recovery step. It was deleted from a USB stick mounted at /media/usbstick/, and recovering it requires reading raw block device data. On a 10 MB ext4 filesystem with no subsequent writes, strings against the raw device is sufficient.

Three services, one real vulnerability, zero software exploits. The box rewards operators who check defaults before chasing web application bugs.

Reconnaissance

The target drops ICMP echo requests, so host discovery requires -Pn to skip the ping probe and treat the host as up:

nmap -Pn -sV -sC -p- --min-rate 5000 10.129.14.196
PortServiceProduct / VersionNotes
22SSHOpenSSH 6.7p1 DebianRaspbian-era OpenSSH
53DNSdnsmasq 2.76DNS forwarder for Pi-hole
80HTTPlighttpd 1.4.35Pi-hole admin interface

Three services. The SSH banner string contains Debian rather than Ubuntu, and the lighttpd web server combined with Pi-hole strongly indicates a Raspberry Pi running Raspbian. OpenSSH 6.7p1 maps to Debian 8 (Jessie), which reached end-of-life in June 2020. The DNS service is dnsmasq, the lightweight forwarder that Pi-hole wraps with its blocklist and web interface.

I chose a full port scan (-p-) with --min-rate 5000 because the three visible services are too few for a machine rated Medium. There could be a high-port service (a Docker API, a management console, a secondary web application). The full scan confirms: there is nothing else. The attack surface is genuinely limited to SSH, DNS, and HTTP.

Attack Surface Analysis

Pi-hole admin panel

lighttpd serves a Pi-hole v3.1.4 installation at /admin/. The login form accepts a single password field with no username. I tested 14 common defaults: pihole, raspberry, admin, password, 1234, changeme, and variations with capitalisation and common substitutions. All returned HTTP 401.

Pi-hole’s authentication model is worth understanding. The admin password is a SHA-256 double-hash stored in /etc/pihole/setupVars.conf. The login API (?login) compares the submitted password’s double-hash against the stored value and returns a session token on match. There is no username; the password alone authenticates. This design means brute-force attacks need only one dimension, but the double-hash (SHA-256 of SHA-256) slows offline cracking negligibly compared to bcrypt or argon2.

The unauthenticated API at /admin/api.php returns operational statistics: queries today, blocked percentage, top queried domains, top blocked domains. I reviewed each endpoint (?summary, ?topItems, ?getQueryTypes, ?getAllQueries) for information disclosure. The data is interesting from a network intelligence perspective (it reveals which domains the network’s clients are resolving), but none of it contains credentials or exploitable paths.

queryads.php command injection surface

queryads.php accepts a domain parameter and passes it to pihole -q to query the blocklist. This is a classic command injection candidate: user input flows into a shell command. I tested standard injection payloads:

domain=google.com;id
domain=google.com|id
domain=$(id)
domain=google.com%0aid
domain=`id`

All were rejected. The domain input is validated against a strict FQDN regex (/^[a-zA-Z0-9.-]+$/ or equivalent) before execution. The filter rejects special characters, whitespace, null bytes, and URL-encoded variants. I also tested double-URL encoding and Unicode normalisation bypasses; none succeeded. The input validation is adequate for this context.

Pi-hole v3.1.4 CVE research

I searched for known vulnerabilities in Pi-hole v3.1.4. The closest match is CVE-2020-8816, an authenticated RCE in the DHCP static lease functionality, but it affects Pi-hole v4.3.2 and requires valid admin credentials. No unauthenticated RCE exists for v3.1.4. The web surface is a dead end.

SSH default credentials

With the web application exhausted, I turned to the operating system. The Raspbian identification from the reconnaissance phase is the key observation. Raspberry Pi OS ships with a well-known default user pi with password raspberry. This is documented on the Raspberry Pi Foundation’s own website and has been the default since the original Model B in 2012. The Foundation added a first-boot password prompt in April 2022, but this box predates that change.

Vulnerability Analysis

AttributeValue
CWECWE-1393 (Use of Default Credentials)
CVSS 3.19.8 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H)
Root causeRaspberry Pi default password unchanged
ImpactFull system access via SSH
MITRE ATT&CKT1078.001 (Valid Accounts: Default Accounts)

This is not a software vulnerability in the traditional sense. No buffer overflow, no logic flaw, no missing authorisation check. It is a deployment misconfiguration that is endemic in IoT and home-lab environments. Operators install Pi-hole for its DNS filtering capability and never harden the underlying operating system. The Raspberry Pi Foundation’s own telemetry (prior to the 2022 change) suggested that a significant fraction of installations retained the default password.

The CVSS score is 9.8 because the attack requires no privileges, no user interaction, and no special conditions. Anyone who can reach port 22 and knows the default credentials has full access. The only mitigating factor is network reachability, which is not modelled in the CVSS base score.

Exploitation

Initial access

ssh [email protected]
# Password: raspberry

Login succeeds. The Pi-hole application, its admin panel, and the queryads.php injection surface were all irrelevant. I spent roughly 30 minutes on web enumeration before trying SSH defaults. The box is designed to punish this ordering.

id
# uid=1000(pi) gid=1000(pi) groups=1000(pi),4(adm),20(dialout),24(cdrom),27(sudo),29(audio),44(video),46(plugdev),60(games),100(users),105(netdev),999(input),1001(spi),1002(i2c),1003(gpio)

The pi user is a member of the sudo group, which on Debian-based systems grants sudo access by default. The adm group provides read access to /var/log/, useful for post-exploitation intelligence. The gpio, spi, and i2c groups confirm this is a Raspberry Pi (or emulating one).

cat /home/pi/Desktop/user.txt

User flag captured.

Privilege escalation

sudo -l
User pi may run the following commands on localhost:
    (ALL : ALL) NOPASSWD: ALL

The pi user has unrestricted passwordless sudo. This is the Raspbian default sudoers entry, configured during OS image creation. It exists because the Raspberry Pi was designed as an educational platform where administrative friction was considered counterproductive. In any deployment beyond a hobbyist workbench, this is a direct path from user compromise to full root.

sudo su -

Root shell obtained.

Root flag recovery

The root flag is not at /root/root.txt. Instead, /media/usbstick/ is mounted and contains a single file:

cat /media/usbstick/damnit.txt
Damnit! Sorry man I accidentally deleted your files off the USB stick.
Do you know if there is any way to get them back?

-James

I identified the underlying device and filesystem:

mount | grep usbstick
# /dev/sdb on /media/usbstick type ext4 (ro,nosuid,nodev,noexec,relatime,data=ordered)

fdisk -l /dev/sdb
# Disk /dev/sdb: 10 MB, 10485760 bytes

The device is a 10 MB ext4 filesystem mounted read-only. When a file is deleted on ext4, the filesystem zeroes the inode’s block pointers and marks the data blocks as free, but it does not overwrite the actual data. On a small, idle device with no subsequent writes, the flag’s data blocks are almost certainly intact on disk.

Full forensic recovery tools (extundelete, photorec, foremost) would work, but on a device this small, strings against the raw block device is faster and sufficient:

sudo strings /dev/sdb | grep -E "^[a-f0-9]{32}$"

This pipes the entire raw block device through strings, which extracts sequences of four or more printable ASCII characters. The grep filter matches exactly 32 lowercase hexadecimal characters on a line by themselves: the MD5 hash format that HTB uses for flags. On a 10 MB device, the false positive rate for this pattern is effectively zero.

Root flag captured.

Why strings works (and when it does not)

The strings | grep approach succeeds here because of three conditions:

  1. Known target format. The flag is 32 hex characters. This is a highly specific pattern that almost never appears in random data or filesystem metadata.
  2. Small device. At 10 MB, the entire device fits in memory and processes in under a second. On a 500 GB disk, strings would produce gigabytes of output and the grep would likely return false positives.
  3. No overwrites. The filesystem is mounted read-only and no writes occurred after deletion. If the blocks had been reallocated and partially overwritten, the flag would be fragmented or destroyed.

Alternative recovery methods

extundelete: recovers files by scanning the filesystem journal for recently deleted inodes. On ext4, the journal retains metadata about deleted files for a period after deletion. This is the correct forensic approach when the target format is unknown or when recovering binary files.

sudo extundelete /dev/sdb --restore-all

photorec: a signature-based file carver that scans raw blocks for known file headers (JPEG SOI markers, PDF headers, ZIP local file headers). It ignores the filesystem entirely and works across filesystem types. Overkill for a 32-character text string, but essential for recovering structured files where the content is not printable ASCII.

debugfs: the ext2/3/4 filesystem debugger can list deleted inodes directly and dump their data blocks if the block pointers have not been zeroed.

sudo debugfs /dev/sdb -R 'ls -d'

Each tool trades precision for generality. strings is the least precise but fastest. extundelete is filesystem-aware but ext-specific. photorec is filesystem-agnostic but slowest.

Post-Exploitation

A compromised Pi-hole is a network-level threat, not just a host-level one. Pi-hole controls DNS resolution for every client configured to use it (often the entire LAN via DHCP). The post-exploitation impact extends far beyond the Pi itself:

  • DNS poisoning: modify /etc/pihole/custom.list or the upstream resolver configuration to redirect arbitrary domains to attacker-controlled IPs. Clients trust the DNS response implicitly.
  • Credential harvesting: DNS query logs (/var/log/pihole.log) reveal every domain resolution on the network. This provides intelligence for targeted phishing: which banking sites, which email providers, which internal services the network’s users access.
  • Lateral movement: the Pi sits on the same subnet as all client devices. SSH keys in /home/pi/.ssh/, Wi-Fi credentials in /etc/wpa_supplicant/wpa_supplicant.conf, and any scripts or configuration files on the device may provide access to other hosts.
  • Persistent interception: unlike a compromised endpoint, a compromised DNS server affects all clients without touching their devices. The attacker maintains a man-in-the-middle position as long as clients use the Pi for resolution.

Defensive Analysis

Detection opportunities

PhaseMITRE ATT&CKDetection
Initial accessT1078.001SSH login with default credentials (failed login audit trail)
Privilege escalationT1548.003sudo to root from pi user (auth.log)
CollectionT1005Reads of raw block devices by non-backup processes
PersistenceT1565.001DNS configuration modifications (file integrity monitoring)

SSH monitoring: fail2ban or a similar rate-limiter would not prevent this attack (the credentials are correct on the first attempt), but logging successful SSH authentications with the pi username post-deployment is a strong signal. If the default password has been changed, the pi user should ideally be renamed or disabled entirely.

Sudo auditing: the auth.log entry for sudo su - from the pi user is distinctive. In a hardened deployment, pi would have restricted sudo (specific commands only, with password required), and any sudo su attempt would trigger an alert.

Block device access: any process running strings, dd, cat, or hexdump against a raw block device (/dev/sd*) outside of scheduled backup or forensic windows is anomalous. auditd rules on open() syscalls to /dev/sd* would catch this.

Remediation

PriorityActionEffortImpact
P0Change the default pi passwordLowCritical
P0Remove NOPASSWD ALL from sudoers for piLowCritical
P1Set a Pi-hole admin passwordLowHigh
P1Disable SSH password authentication (keys only)LowHigh
P1Rename or disable the pi user accountLowHigh
P2Deploy fail2ban for SSH rate limitingLowMedium
P2Use full-disk encryption on removable mediaMediumMedium
P3Monitor for raw block device access (auditd)LowLow
P3Upgrade from Debian 8 to a supported releaseHighHigh

The root cause is cultural rather than technical. Raspberry Pi was designed as an educational tool where ease of use trumped security. The default credentials and passwordless sudo reflect that design priority. When operators repurpose the Pi as network infrastructure (DNS server, VPN endpoint, home automation controller), they inherit a security posture designed for a classroom. The remediation is not just changing a password; it is treating the Pi as production infrastructure with the same hardening standards applied to any server.

For the deleted file recovery vector, the defence is encryption at rest. If the USB stick used LUKS or dm-crypt, strings against the raw device would return only ciphertext. Full-disk encryption prevents data recovery after deletion regardless of the recovery tool used.

Key Takeaways

  1. Enumerate the operating system, not just the application. The Pi-hole admin panel dominates the enumeration phase and consumes time with its login form, API, and queryads.php injection surface. The entry point is the host beneath it. When a scan reveals SSH alongside a web application, test default and common credentials before investing in web exploitation.

  2. Default credentials are the most reliable exploit class. No buffer overflow, no CVE, no complex chain. pi:raspberry provides root access (via passwordless sudo) on thousands of Raspberry Pi deployments worldwide. CISA’s Known Exploited Vulnerabilities catalogue does not track default credentials, but they account for a disproportionate share of real-world compromises.

  3. strings on raw block devices recovers deleted data. On small, idle filesystems where the target format is known, strings | grep is faster than full forensic suites. The technique fails on large disks (false positives), overwritten blocks (data destruction), and non-printable targets (binary files). Know the tool’s limitations before relying on it.

  4. Passwordless sudo eliminates the privilege boundary. The Raspbian default of NOPASSWD: ALL for the pi user collapses user compromise and root compromise into a single step. Any hardening effort that leaves sudoers unchanged is incomplete.

  5. A compromised DNS server is a network-wide threat. Pi-hole controls name resolution for every client that uses it. The blast radius of this compromise extends to every device on the network, not just the Pi. DNS infrastructure should receive the same security attention as domain controllers and authentication servers.