Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions src/windows-hardening/active-directory-methodology/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.<sup>[[18]](#references)[[20]](#references)</sup>

Use authenticated LDAP enumeration to test the candidates and save successful TGTs. `ALL=True` expands testing beyond objects with the default `4128` filter.<sup>[[18]](#references)</sup>

```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/`.<sup>[[18]](#references)[[20]](#references)</sup>

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.<sup>[[19]](#references)[[20]](#references)</sup>

```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.<sup>[[20]](#references)</sup>

### Kerberoast

Kerberoasting involves obtaining **TGS tickets** used by services tied to user accounts and cracking their encryption—which is based on user passwords—**offline**.
Expand Down Expand Up @@ -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}}
Original file line number Diff line number Diff line change
Expand Up @@ -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).<sup>[[2]](#references)</sup>

### 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`.<sup>[[5]](#references)[[6]](#references)</sup>

Two variants exist:<sup>[[5]](#references)</sup>

- **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.<sup>[[5]](#references)[[6]](#references)</sup>

```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**.<sup>[[5]](#references)[[6]](#references)</sup>

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**.<sup>[[5]](#references)</sup>

### 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+):
Expand Down Expand Up @@ -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}}