← back to writeups
Vulnhub

Vulnhub: Matrix 2

Matrix 2 is about reading hints literally. A robots.txt entry and an unauthenticated POST leak two usernames, a crackable .htpasswd hash gives a password, a passphrase hidden in plain sight (a name styled bold and red) unlocks a steghide-embedded secret, and the box ends on a sudo-runnable gawk — a GTFOBins instant win.

Attack chain at a glance

  • Recon — HTTP on 80 plus four unusual HTTP ports (1337, 12320-12322); 1337 and 12320 are credential-gated.
  • Leak — dirb finds a robots.txt pointing at a blank PHP page; an unauthenticated curl --insecure POST to it returns two usernames (n30, testuser) — information disclosure.
  • Foothold — testuser:testuser opens a web shell; browsing its filesystem finds a .htpasswd hash that John cracks to Tr1n17y.
  • Pivot — those creds unlock port 1337, which serves hidden.jpg; the bold-red n30 hint is the steghide passphrase, extracting a password.
  • Root — login as n30; linpeas shows n30 can run /usr/bin/Morpheus (which calls gawk) as root — the gawk GTFOBins trick drops a root shell.
Techniques in play: content discovery (dirb, robots.txt), unauthenticated info disclosure, offline hash cracking (John), steganography (steghide) with a cleverly-signalled passphrase, and a sudo-runnable interpreter (gawk) — a GTFOBins classic.

Matrix 2 chains a robots.txt hint and an unauthenticated POST to leak usernames, a crackable .htpasswd hash, a steghide-protected image whose passphrase is hidden in plain sight, and finally a gawk sudo rule for root.

Reconnaissance

Matrix 2 VM booted from Vulnhub
The Matrix 2 VM running.

netdiscover locates the target.

netdiscover showing the target IP 192.168.0.118
Target identified as 192.168.0.118.

An nmap scan shows HTTP on 80 plus four unusual HTTP ports.

nmap results showing ports 80, 1337, 12320, 12321, 12322
Port 80 is open alongside 1337, 12320, 12321 and 12322, all serving HTTP.

Enumerating the web services

Browsing each page first turns up nothing obvious.

Default pages across the web ports
Nothing useful on the landing pages.

Port 1337 prompts for a username and password.

Port 1337 basic-auth prompt
Port 1337 is behind HTTP basic auth.

Port 12320 is a web shell that also needs credentials, so it is set aside for now.

Web shell login on port 12320
Port 12320 — a login-gated web shell.

Port 12322 mirrors port 80 with nothing immediately useful, so a dirb scan looks for hidden paths.

dirb directory scan against port 12322
A dirb scan of the service.

The scan flags a robots.txt, worth a look.

robots.txt discovered by dirb
robots.txt stands out in the results.

It disallows a specific PHP page, which is exactly where to go next.

robots.txt disallowing a PHP page
The disallowed PHP endpoint named in robots.txt.

The page renders blank — suspicious — so a POST request is sent to it with curl --insecure (the service uses a self-signed certificate).

Blank PHP page in the browser
A blank page that clearly does more than it shows.

The response leaks information and two usernames, n30 and testuser. Back at the web shell, testuser:testuser is worth a try.

Foothold via the web shell

Web shell access as testuser
testuser:testuser gets into the web shell.

From the shell the filesystem is browsable, and a folder named p4ss stands out.

Listing files including a p4ss folder
A promising p4ss directory.

Inside is a .htpasswd file containing a hash.

A .htpasswd file holding a password hash
.htpasswd — a hash to crack.

The hash is copied to Kali and fed to John the Ripper.

Saving the hash to a file on Kali
The hash saved locally.
John the Ripper cracking the hash to Tr1n17y
John recovers the password Tr1n17y.

Pivot: steghide & the hidden passphrase

Those credentials unlock the basic-auth prompt on port 1337.

Logging in on port 1337 with the cracked password
Authenticated on port 1337.

The page shows an image, hidden.jpg, which is downloaded. On the main page the name n30 is styled bold and red — a strong hint it is a passphrase.

hidden.jpg and the highlighted n30 hint
hidden.jpg, and n30 highlighted as a likely passphrase.

Running steghide with n30 as the passphrase extracts an embedded password.

steghide extracting data with the n30 passphrase
steghide gives up a hidden password.

Privilege escalation

The extracted password, with username n30, grants access.

Logging in as n30 with the extracted password
Access as n30.

linpeas is pulled onto the target to hunt for escalation paths.

Running linpeas on the target
linpeas staged and running.

It flags a suspicious permission: n30 can run /usr/bin/Morpheus as root.

linpeas highlighting a sudo-runnable Morpheus binary
n30 may execute /usr/bin/Morpheus as root.

Running it shows it invokes gawk; the classic gawk BEGIN{system("/bin/sh")} trick drops a root shell.

gawk spawning a root shell via Morpheus
Abusing gawk through Morpheus for a root shell.

With root, /root holds flag.txt.

flag.txt in the root directory
The root flag in /root/flag.txt.
Box completed
Box complete.
Matrix 2 rewards reading the hints literally — the disallowed page, the colour-coded n30, and GTFOBins-style knowledge that a sudo-runnable gawk is game over.

Defender's notes

  • robots.txt advertises paths — never use it to “hide” sensitive endpoints, and don't leave a debug endpoint that dumps usernames (sensitive data exposure).
  • Store passwords with a slow, salted hash so a leaked .htpasswd isn't trivially cracked.
  • Steganography is obscurity, not security; and don't telegraph the passphrase in the page.
  • Never let a non-admin run an interpreter (gawk, awk, perl, vim) via sudo — it is equivalent to granting root.