diff --git a/src/windows-hardening/active-directory-methodology/README.md b/src/windows-hardening/active-directory-methodology/README.md index b8c87f9d563..abf1585a0cc 100644 --- a/src/windows-hardening/active-directory-methodology/README.md +++ b/src/windows-hardening/active-directory-methodology/README.md @@ -350,6 +350,34 @@ Regarding [**ASREPRoast**](asreproast.md) you can now find every possible vulner > Even if this Enumeration section looks small this is the most important part of all. Access the links (mainly the one of cmd, powershell, powerview and BloodHound), learn how to enumerate a domain and practice until you feel comfortable. During an assessment, this will be the key moment to find your way to DA or to decide that nothing can be done. +### Predictable pre-created computer accounts -> gMSA password access + +Computer accounts staged for legacy joins can retain a predictable initial password. NetExec's `pre2k` module identifies the characteristic `userAccountControl` value `4128` (`WORKSTATION_TRUST_ACCOUNT | PASSWD_NOTREQD`) and attempts a Kerberos TGT with the first 14 characters of the lowercase computer name, without the trailing `$`. Treat this UAC value as a candidate selector rather than assuming that membership in **Pre-Windows 2000 Compatible Access** alone proves the password is weak.[[18]](#references)[[20]](#references) + +Use authenticated LDAP enumeration to test the candidates and save successful TGTs. `ALL=True` expands testing beyond objects with the default `4128` filter.[[18]](#references) + +```bash +netexec ldap dc.corp.local -u auditor -p 'Password!' -M pre2k +netexec ldap dc.corp.local -u auditor -p 'Password!' -M pre2k -o ALL=True + +# Validate a candidate explicitly with Kerberos +netexec ldap dc.corp.local -u 'APP01$' -p app01 -k +``` + +A failed default/NTLM bind does **not** invalidate this finding: test with `-k`, an FQDN that resolves to the DC, and a clock synchronized with the KDC. Successful module runs write candidate lists and acquired ccaches below `~/.nxc/modules/pre2k/`.[[18]](#references)[[20]](#references) + +After compromising the computer principal, graph its nested group memberships and outbound rights. In particular, principals named in a gMSA's `msDS-GroupMSAMembership` security descriptor can read `msDS-ManagedPassword`; NetExec's `--gmsa` output shows the allowed principals and returns the current NT hash when the authenticating computer is authorized.[[19]](#references)[[20]](#references) + +```bash +# Enumerate gMSAs and their password readers with the initial user +netexec ldap dc.corp.local -u auditor -p 'Password!' --gmsa + +# Re-query as the compromised computer through Kerberos +netexec ldap dc.corp.local -u 'APP01$' -p app01 -k --gmsa +``` + +Then evaluate the recovered gMSA like any other credential: inspect local/domain group membership, logon rights, SPNs, delegation, and reachable services before trying pass-the-hash. This ACL-based retrieval path is distinct from [Golden gMSA/dMSA](golden-dmsa-gmsa.md), which derives managed passwords after KDS root-key compromise.[[20]](#references) + ### Kerberoast Kerberoasting involves obtaining **TGS tickets** used by services tied to user accounts and cracking their encryption—which is based on user passwords—**offline**. @@ -1066,5 +1094,8 @@ If you want to detect common AD tradecraft, **do not rely only on operator-contr - [15] [From DA to EA with ESC5](https://specterops.io/blog/2023/05/16/from-da-to-ea-with-esc5/) - [16] [Escalating from child domain's admins to enterprise admins in 5 minutes by abusing AD CS, a follow up](https://www.pkisolutions.com/escalating-from-child-domains-admins-to-enterprise-admins-in-5-minutes-by-abusing-ad-cs-a-follow-up/) - [17] [An ACE Up the Sleeve: Designing Active Directory DACL Backdoors](https://specterops.io/assets/resources/an_ace_up_the_sleeve.pdf) +- [18] [NetExec pre2k module source](https://github.com/Pennyw0rth/NetExec/blob/main/nxc/modules/pre2k.py) +- [19] [Microsoft ADSchema - msDS-GroupMSAMembership attribute](https://learn.microsoft.com/en-us/windows/win32/adschema/a-msds-groupmsamembership) +- [20] [0xdf - HTB Pirate](https://0xdf.gitlab.io/2026/09/05/htb-pirate.html) {{#include ../../banners/hacktricks-training.md}} diff --git a/src/windows-hardening/active-directory-methodology/constrained-delegation.md b/src/windows-hardening/active-directory-methodology/constrained-delegation.md index b124eecb473..72709c9ec74 100644 --- a/src/windows-hardening/active-directory-methodology/constrained-delegation.md +++ b/src/windows-hardening/active-directory-methodology/constrained-delegation.md @@ -82,6 +82,34 @@ export KRB5CCNAME=Administrator_HOST.ccache If you prefer forging the user ST first (e.g., offline hash only), pair **ticketer.py** with **getST.py** for S4U2Proxy. `tgssub.py` is also handy when you already have a working ccache and only need to swap the service class for the same host. See the open Impacket issue #1713 for current quirks (KRB_AP_ERR_MODIFIED when the forged ST doesn't match the SPN key).[[2]](#references) +### SPN-jacking: redirecting a constrained-delegation target + +Classic constrained delegation authorizes an **SPN string** in `msDS-AllowedToDelegateTo`, not an immutable target SID. During S4U2Proxy, the KDC resolves the account that currently owns that SPN and encrypts the service ticket with that account's long-term key. Therefore, control of the delegating account plus `WriteSPN` over another service/computer account can redirect an unchanged delegation constraint without `SeEnableDelegationPrivilege`.[[5]](#references)[[6]](#references) + +Two variants exist:[[5]](#references) + +- **Ghost SPN-jacking:** the allowed SPN is orphaned because its former owner was deleted, renamed, or had the SPN removed. Add it directly to the desired target account. +- **Live SPN-jacking:** the SPN still belongs to a source account. Duplicate-SPN validation normally blocks the destination write, so `WriteSPN` is needed on both objects: remove it from the source, add it to the target, obtain the ticket, and restore the original registration. + +The following abstracted Linux flow moves an allowed SPN, runs S4U as the compromised delegating principal, and rewrites the ticket's service name to a useful service on the new target.[[5]](#references)[[6]](#references) + +```bash +# Omit this deletion for a ghost SPN +bloodyAD --host "$DC" -d "$DOMAIN" -u "$WRITER" -p "$PASSWORD" \ + msldap delspn "$SOURCE_DN" "$DELEGATED_SPN" + +bloodyAD --host "$DC" -d "$DOMAIN" -u "$WRITER" -p "$PASSWORD" \ + msldap addspn "$TARGET_DN" "$DELEGATED_SPN" + +getST.py -dc-ip "$DC_IP" -spn "$DELEGATED_SPN" \ + -impersonate Administrator -altservice "cifs/$TARGET_FQDN" \ + "$DOMAIN/$DELEGATING_ACCOUNT:$DELEGATING_PASSWORD" +``` + +`-altservice` is the second, separate primitive. The S4U2Proxy ticket was encrypted for the account that now owns `$DELEGATED_SPN`; because the ticket service name (`sname`) is outside the encrypted ticket body, tooling can substitute another service class/hostname whose service uses that same account key. SPN-jacking first changes **which account key** protects the ticket, while service-class substitution changes **where that ticket is presented**.[[5]](#references)[[6]](#references) + +For live jacking, reverse the two LDAP writes immediately after ticket acquisition to avoid breaking the legitimate service. On DCs with computer-account auditing enabled, hunt for Security event **4742** where `servicePrincipalName` is removed from one computer and shortly added to another, especially when the SPN hostname differs from the destination's `dNSHostName`. Correlate with event **4769**: S4U2Self presents the same account as client/service, while S4U2Proxy populates **Transited Services**.[[5]](#references) + ### Automating delegation setup from low-priv creds If you already hold **GenericAll/WriteDACL** over a computer or service account, you can push the required attributes remotely without RSAT using **bloodyAD** (2024+): @@ -158,5 +186,7 @@ Invoke-Mimikatz -Command '"kerberos::ptt TGS_Administrator@dollarcorp.moneycorp. - [2] [Abusing Delegation with Impacket (Part 2): Constrained Delegation (Black Hills, 2025)](https://www.blackhillsinfosec.com/abusing-delegation-with-impacket-part-2/) - [3] [Kerberos Constrained Delegation (ired.team)](https://www.ired.team/offensive-security-experiments/active-directory-kerberos-abuse/abusing-kerberos-constrained-delegation) - [4] [Kerberosity Killed the Domain: An Offensive Kerberos Overview (SpecterOps)](https://posts.specterops.io/kerberosity-killed-the-domain-an-offensive-kerberos-overview-eb04b1402c61) +- [5] [Elad Shamir - SPN-jacking: An Edge Case in WriteSPN Abuse](https://www.semperis.com/blog/spn-jacking-an-edge-case-in-writespn-abuse/) +- [6] [0xdf - HTB Pirate](https://0xdf.gitlab.io/2026/09/05/htb-pirate.html) {{#include ../../banners/hacktricks-training.md}}