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

Ghostlink

23 Jun 2026 · 24 min read · root access
Ghostlink - maquina de Hack The Box

Executive summary — Ghostlink (HTB Business CTF 2026, "Ghost Protocol Zero" theme) is a domain controller with a very unusual attack surface: an anonymous MQTT broker orchestrating health checks for internal infrastructure. The full chain strings together half a dozen very different techniques: poisoning a retained MQTT message to coerce NTLM authentication (SSRF → NTLM), relaying that NTLM back to an internal file-share through a custom authenticated HTTP proxy, a double URL-encoded path traversal leaking a KeePass database, CVE-2025-8110 in Gogs for authenticated RCE, cracking PBKDF2 within a search space narrowed by the organization's own password policy, and finally AD CS ESC11 combined with coercing the DC's own machine account to land DCSync.

PlatformHack The Box
Operating systemWindows Server 2019
DifficultyHard
StatusRetired
Target IP (edge)10.129.37.254

Attack map

[1883] MQTT broker (EMQX) — anonymous subscribe/publish
   │  poison a retained healthcheck message → NTLM coercion of SVC_CANARY
   ▼
[RELAY]  ntlmrelayx HTTP (persistent authenticated proxy) → internal file-share
   │  DOUBLE URL-encoded path traversal → db.zip (KeePass) → vroth's creds
   ▼
[Gogs]  CVE-2025-8110 (authenticated RCE, symlink+hook) → 'git' shell
   │  gogs.db → cracked PBKDF2 (rockyou trimmed to policy ≥20) → nvirelli (user.txt)
   ▼
[PIVOT]  chisel (only route to 172.16.20.0/24) → AD CS ESC11 (unencrypted ICPR/RPC)
   │  DFSCoerce (DC01$) + certipy relay → DC01$'s certificate
   ▼
[ROOT]  PKINIT → DC01$'s NT hash → DCSync → Administrator → root.txt

1. Reconnaissance

nmap -sT -p- --min-rate 3000 -T4 -Pn -oN allports.txt 10.129.37.254
nmap -sT -sCV -p80,88,135,139,389,445,1883,2179,5985 -Pn \
     --script "smb-os-discovery,ldap-rootdse" 10.129.37.254
53,88,135,139,389,445,464,593,636,3268,3269,9389   → Domain Controller
80/tcp    Microsoft IIS 10.0                        → "Ghost Protocol Zero" (landing)
1883/tcp  mqtt                                      → MQTT broker (anonymous)
2179/tcp  vmrdp                                     → Hyper-V VMRDP
5985/tcp  Microsoft HTTPAPI 2.0                     → WinRM
dnsHostName: dc01.ghostlink.htb
defaultNamingContext: DC=ghostlink,DC=htb
echo "10.129.37.254 dc01.ghostlink.htb ghostlink.htb DC01" | sudo tee -a /etc/hosts

Port 80's site is just a static landing page for a fictional APT group themed around "Ghost Protocol Zero", with no real functionality. This machine's genuine vector is MQTT — a publish/subscribe messaging protocol meant for IoT/telemetry, an unusual attack surface for a Windows/AD-focused CTF.

nmap already hints that the broker allows anonymous subscription (mqtt-subscribe) and exposes client-status topics ($SYS/brokers/client_status/..., client mqttui), typical of EMQX. With no MQTT client installed locally, a small paho-mqtt script is enough to dump every topic:

import paho.mqtt.client as mqtt, sys, time
seen=set()
def on_connect(c,u,f,rc,*a): c.subscribe("#"); c.subscribe("$SYS/#")
def on_message(c,u,m):
    p=m.payload.decode('utf-8','replace'); k=(m.topic,p[:80])
    if k in seen: return
    seen.add(k); print(f"[{m.topic}] {p[:400]}")
cl=mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="sub-%d"%int(time.time()))
cl.on_connect=on_connect; cl.on_message=on_message
cl.connect("10.129.37.254",1883,60); cl.loop_start(); time.sleep(20); cl.loop_stop()
python3 mqttsub.py | grep -v client_status
GhostProtocolZero/systems/node/domain/healthcheck       url: dc01.ghostlink.htb/healthcheck  ip 10.129.37.254
GhostProtocolZero/systems/node/repository/healthcheck   url: gpz-op26-toolkits.ghostlink.htb  ip 172.16.20.20
GhostProtocolZero/systems/node/secureshare/healthcheck  url: gpz-op26-secure.ghostlink.htb    ip 172.16.20.10

The topics reveal telemetry for critical-infrastructure "nodes", and with it, two internal hosts on the 172.16.20.0/24 subnet: gpz-op26-secure.ghostlink.htb (172.16.20.10, an NTLM-authenticated file-share) and gpz-op26-toolkits.ghostlink.htb (172.16.20.20, a Gogs repository).

The HTB VPN doesn't route that subnet (ping 172.16.20.1 fails). However, the DC's own IIS acts as a Host-header-based reverse proxy (ARR), which reaches internal HTTP with no pivoting needed yet:

curl -s -o /dev/null -w "%{http_code}\n" -H "Host: gpz-op26-toolkits.ghostlink.htb" http://10.129.37.254/   # 200
curl -s -i -H "Host: gpz-op26-secure.ghostlink.htb" http://10.129.37.254/ | head          # 401 WWW-Authenticate: NTLM
echo "10.129.37.254 gpz-op26-secure.ghostlink.htb gpz-op26-toolkits.ghostlink.htb" | sudo tee -a /etc/hosts

gpz-op26-toolkits turns out to be Gogs — the version hash in the HTML's gogs.min.css?v=5084b4a9... matches the commit pinning Gogs 0.13.3 (vulnerable to CVE-2025-8110, but it requires authentication → not yet exploitable at this point). gpz-op26-secure responds with 401 NTLM — a real domain identity is needed to access it.

🔒 Clearance required

This content is Root Access only. Everything else on the site — the free tier, the whole public library — stays open.

See Root Access plans

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