Hack The Box - HTB Touch Writeup - Easy - Weekly - october 3th, 2026
Overview
- Target IP:
10.129.xx.xx - Attacker (VPN) IP:
10.10.xx.xx - Supplied credentials:
Jenny Crawford / KS7X2M
The box is themed around a fictional airline check-in kiosk ("HTB Airways"). The attack surface combines a device-management web portal (Nexion DeviceHub), a tightly restricted Windows kiosk session, and a locally running MySQL 8.0 instance that is ultimately turned into SYSTEM-level code execution through a User Defined Function (UDF).
1. Reconnaissance — Nmap
nmap -sV -sC 10.129.xx.xx
Starting Nmap 7.99 ( https://nmap.org ) at 2026-10-04 02:03 +0000
Nmap scan report for 10.129.xx.xx
Host is up (0.35s latency).
Not shown: 996 filtered tcp ports (no-response)
PORT STATE SERVICE VERSION
135/tcp open msrpc Microsoft Windows RPC
3389/tcp open ms-wbt-server Microsoft Terminal Service
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-title: Not Found
|_http-server-header: Microsoft-HTTPAPI/2.0
8443/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-cors: GET POST PUT OPTIONS
|_http-trane-info: Problem with XML parsing of /evox/about
| http-title: Nexion DeviceHub - Login
|_Requested resource was /login
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows
What the open ports tell us:
- 135 — MSRPC
- 3389 — RDP (Terminal Services)
- 5985 — WinRM (the banner reads as a generic HTTPAPI service, but this is the usual WinRM port)
- 8443 — a web application: the Nexion DeviceHub login page
Seeing RDP and WinRM exposed alongside a management web portal is a strong hint that the portal might hand us credentials or device details we can then reuse against the other services — the familiar HTB pattern of linking one service into the next.
2. Web Enumeration on Port 8443
Visiting https://10.129.xx.xx:8443 presents a Nexion DeviceHub login screen that expects a device password we don't yet possess.
Directory / Content Discovery
ffuf -u http://10.129.xx.xx:8443/FUZZ -w /usr/share/wordlists/dirb/common.txt
The first pass was almost entirely noise — every path returned a default 302 redirect (wildcard-style behaviour), so the output needed filtering:
ffuf -u http://10.129.xx.xx:8443/FUZZ -w /usr/share/wordlists/dirb/common.txt -fc 302
api [Status: 403, Size: 35, Words: 2, Lines: 1, Duration: 279ms]
favicon.ico [Status: 200, Size: 452, Words: 37, Lines: 1, Duration: 283ms]
login [Status: 200, Size: 3572, Words: 122, Lines: 3, Duration: 280ms]
An /api path that answered with 403 Forbidden (as opposed to 404) signalled that the endpoint is real but gated — it wants auth, or a more specific sub-path. That justified fuzzing a level deeper:
ffuf -u http://10.129.xx.xx:8443/api/FUZZ -w /usr/share/wordlists/dirb/common.txt -fc 302
[Status: 403, Size: 35, Words: 2, Lines: 1, Duration: 293ms]
scan [Status: 405, Size: 30, Words: 3, Lines: 1, Duration: 524ms]
status [Status: 200, Size: 116, Words: 3, Lines: 1, Duration: 414ms]
/api/scan→405 Method Not Allowed(GET is the wrong verb here — most likely a POST endpoint; not worth chasing since it needs auth anyway)/api/status→200 OK— and this one gives up data with no authentication at all
Unauthenticated Info Leak: /api/status
curl http://10.129.xx.xx:8443/api/scan | jq
{
"error": "Method not allowed"
}
curl http://10.129.xx.xx:8443/api/status | jq
{
"device": "Nexion DeviceHub DH-100",
"serial": "NX-DH-2024-B7042",
"firmware": "1.4.2",
"status": "online",
"uptime": 33838
}
Here's the flaw: an unauthenticated endpoint hands out the device serial number, and that serial doubles as the DeviceHub login password. Using a device identifier as a secret is a textbook "serial-as-password" mistake — anyone who can reach /api/status walks away with the credential to the admin portal.
Entering the serial NX-DH-2024-B7042 as the device password on /login succeeded, dropping us into the DeviceHub dashboard.
3. Exploring the DeviceHub Dashboard
Inside, the dashboard listed two managed devices, both active:
- Passport Scanner
- Boarding Pass Printer
The portal let us toggle these devices on and off remotely, and it also surfaced a stored credential pair tied to the kiosk hardware:
KioskUser : [REDACTED - KIOSKUSER PASSWORD]
Some context: a kiosk user is a restricted local account set up so an unauthenticated or limited person can use just one designated application (think of an airport check-in terminal). The name strongly suggests this credential belongs to a locked-down local Windows account rather than anything privileged.
4. Credential Validation — Testing for Reuse Across Services
Because Nmap had already shown WinRM (5985) and RDP (3389) listening, the obvious move was to see whether the leaked KioskUser credential had been reused on either. This is standard credential-reuse / stuffing testing; each attempt is shown below.
WinRM check
nxc winrm 10.129.xx.xx -u KioskUser -p '[REDACTED - KIOSKUSER PASSWORD]'
WINRM 10.129.xx.xx 5985 KIOSK-042 [*] Windows 11 / Server 2025 Build 26100 (name:KIOSK-042) (domain:KIOSK-042)
WINRM 10.129.xx.xx 5985 KIOSK-042 [-] KIOSK-042\KioskUser:[REDACTED - KIOSKUSER PASSWORD]
Outcome: rejected ([-]). WinRM turned the pair away — most likely because this local account isn't permitted to use WinRM, not because the password is wrong (confirmed via RDP shortly).
RDP check
nxc rdp 10.129.xx.xx -u KioskUser -p '[REDACTED - KIOSKUSER PASSWORD]'
RDP 10.129.xx.xx 3389 10.129.xx.xx [*] Probably old, doesn't not support HYBRID or HYBRID_EX (nla:False)
RDP 10.129.xx.xx 3389 10.129.xx.xx [-] None\KioskUser:[REDACTED - KIOSKUSER PASSWORD] (Server refused our connection request! Reason: SSL_NOT_ALLOWED_BY_SERVER)
This one failed on a TLS/NLA negotiation problem (SSL_NOT_ALLOWED_BY_SERVER) rather than a bad credential, so we switched from the NetExec check to a full RDP client.
Successful RDP login via xfreerdp3
xfreerdp3 /v:10.129.xx.xx /u:KioskUser /p:'[REDACTED - KIOSKUSER PASSWORD]' /cert:ignore /dynamic-resolution +clipboard
This connected and placed us in a graphical Windows session as KioskUser, proving the leaked credential was valid and that the earlier WinRM rejection was down to WinRM-specific restrictions, not a wrong password.
5. Kiosk Breakout — Forcing an Application Error to Reach a Shell
The RDP session dropped us into a heavily restricted kiosk application offering two paths:
- Self check-in — the first step accepted the supplied credentials (
Jenny Crawford / KS7X2M), but the second step demanded a passport scan (a physical action we couldn't perform). - Staff login — required scanning an employee badge (again, hardware we didn't have).
Neither flow could finish the normal way, which pointed straight at a classic kiosk-breakout idea: deliberately make the kiosk app throw an unhandled error, since the error handler often exposes an embedded browser (Edge/IE) or a file dialog that can be turned into a real desktop shell.
The crucial observation: the DeviceHub portal on 8443 let us power the Passport Scanner and Boarding Pass Printer off. If the kiosk relies on those devices being online to complete a scan, taking them offline should make the scan step fail with an error.
Breakout steps
- From the DeviceHub dashboard (8443), power off both the Passport Scanner and the Boarding Pass Printer.
- In the kiosk, pick Staff login → Scan badge. With the scanner now offline, this raises an application error dialog containing a clickable link/details.
- Click the link in the dialog — this opens Microsoft Edge.
- In Edge, hit Ctrl+O to summon the native Open File dialog — a common kiosk-escape trick, since the file picker is effectively a full Explorer window.
- Browse to
C:\Windows\System32\, findcmd.exe, and open it. - Owing to how the restricted shell treats the action, it first downloads
cmd.exeand then runs it — handing us a working Command Prompt inside the kiosk session.
This is the canonical kiosk/browser-restriction bypass: provoke an error → the handler launches a full browser → the browser's native file dialog becomes a side door into the filesystem → run cmd.exe from there.
6. Reverse Shell as KioskUser
With a Command Prompt in hand, we built a reverse shell and moved it onto the target.