root@thehacksparrow:~/writeups$ SYSTEM ONLINE
root@sparrow:~/writeups$ cat holiday.md
// writeups

Holiday

2 Jun 2017 · 22 min read · root access
Holiday - maquina de Hack The Box

Executive summary — Holiday is a seven-link chain against a bespoke Node.js/Express booking application ("Booking Management") sitting behind a User-Agent-filtering WAF, with blacklist-based input validation at every following step. The login form hides a blind SQL injection against SQLite whose own oracle is poisoned by the WAF (it blocks the word select), forcing the boolean queries to be built without subqueries, leaning on rowid instead. Once inside, a stored XSS in the booking notes system — approved by an admin bot running PhantomJS, a browser unmaintained since 2018 that ignores the Content-Security-Policy header — becomes the vector for firing a command injection against the admin panel's export endpoint, already under the admin's authenticated session. The rest is classic lateral movement: a self-planted SSH key installed through the RCE grants access as algernon, and a misconfigured sudo rule over npm install hands over a trivial root escalation through npm's lifecycle scripts.

PlatformHack The Box
Operating systemLinux (Ubuntu 16.04)
DifficultyHard
StatusRetired
Target IP10.129.75.47
Services22 (OpenSSH 7.2p2), 8000 (Node.js Express — "Booking Management")

Attack map

[8000] curl -> 404 on EVERYTHING ── WAF filters by User-Agent
   │  real browser UA (Firefox) ──▶ "Booking Management" app appears (login)
   ▼
[SQLi] Injectable SQLite login ── the WAF blocks the word "select"
   │  boolean oracle built on rowid, no subqueries ──▶ RickA's MD5 hash
   ▼
[crack] hashcat -m0 + rockyou ──▶ RickA:nevergonnagiveyouup
   │  login ──▶ /agent (bookings) ──▶ /agent/addNote form
   ▼
[XSS] Note with String.fromCharCode (evades the quote filter)
   │  the PhantomJS admin bot approves it (~1 min) and ignores CSP
   ▼
[RCE] XSS (admin session) ──▶ command injection in /admin/export?table=
   │  lowercase-only filter; attacker IP in decimal (no dots)
   │  installs my public SSH key
   ▼
[algernon] (user.txt)
   │  sudo -l ──▶ NOPASSWD: /usr/bin/npm i *
   ▼
[ROOT] package.json with a "preinstall" script ──▶ chmod +s /bin/bash (root.txt)

1. Reconnaissance and the User-Agent WAF

nmap -sCV -p22,8000 10.129.75.47
# 22   OpenSSH 7.2p2 Ubuntu
# 8000 Node.js Express framework  (http-title: Error)

The "Error" title on port 8000 is the first hint: every normal curl request returns a generic 404.

curl -s http://10.129.75.47:8000/
404 Cannot GET …

And not just the root path: an exhaustive fuzz of over 62,000 routes and method combinations turned up nothing but that same 404.

When a massive fuzz fails to tell any route apart from the rest, the most likely explanation isn't an empty site — it's that something is intercepting the request before it reaches the application and always answering the same way: a web application firewall, a proxy, or middleware filtering on some property of the request itself. The next logical move is to vary that property, not the paths.

The obvious suspect is the User-Agent: curl advertises itself as curl/7.x, a trivially detectable and blockable value. Repeating the same request with a real browser UA:

UA="Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0"
curl -s -A "$UA" http://10.129.75.47:8000/
# → "Booking Management" (login)

Why it works: the application's middleware checks whether the User-Agent "looks like" a browser (likely a simple substring check such as contains("Mozilla")) and returns the generic 404 to any client that fails it — curl, nmap, and most scanners/fuzzers by default. This is a security-by-obscurity control (CWE-807): it authenticates nothing, it just hides the attack surface from anything that doesn't impersonate a browser. With the right UA, the real app shows up: a login form for "Booking Management", with /login, /agent and /admin routes.

🔒 Clearance required

Root Access unlocks the content you can't see — everything else on the site is already open.

See Root Access plans

No account? Create one free then upgrade from your console.