winrm.nim
Native WinRM client library for Nim
Version 1.0.0 ·
Author Chokri Hammedi (blue0x1) ·
License MIT
A complete, dependency-free implementation of the WinRM protocol stack including NTLM authentication, Kerberos via GSSAPI, PSRP (PowerShell Remoting Protocol), WinRS (Windows Remote Shell), NTLM message encryption, file transfers, and .NET assembly execution.
Legal Notice
This library is intended for lawful administration, security testing, and research on systems you own or have explicit permission to access. The author is not responsible for misuse or damage caused by this software.
Features
| Area |
Details |
| Authentication |
NTLMv2 password, NTLMv2 pass-the-hash, Kerberos via libgssapi_krb5 |
| Transport |
HTTP, HTTPS/TLS, NTLM message encryption (sealing) |
| PowerShell |
PSRP session/runspace management, pipeline creation, output decoding |
| CMD |
WinRS shell creation, command execution, binary output |
| Transfers |
Chunked Base64 upload with adaptive retry, streamed download |
| In-Memory |
PowerShell script import, managed .NET assembly detection and execution |
| Crypto |
Native MD4, MD5, HMAC-MD5, RC4, NTLM key derivation (no OpenSSL for auth) |
| Protocol |
SOAP/WS-Management envelope construction, SPNEGO/ASN.1 DER encoding |
Requirements
| Component |
Requirement |
| Nim |
>= 1.6.0 |
| Kerberos |
libgssapi_krb5.so.2 (Linux) or libgssapi_krb5.dylib (macOS) |
| TLS |
OpenSSL (-d:ssl) |
Installation
Nimble
Manual
Copy winrm.nim into your project and import it:
Quick Start
NTLM Authentication
import winrm
var client = newClient(
host = "192.168.1.10",
user = "CORP\\administrator",
pass = "Password123",
ntHash = "",
spn = "",
domain = "",
auth = amNtlm,
ssl = false,
port = 5985
)
warmSmartShell(client)
let output = runCmd(client, "whoami", isCmd = false)
echo output
deleteShell(client)
Pass-the-Hash
import winrm
var client = newClient(
host = "192.168.1.10",
user = "CORP\\administrator",
pass = "",
ntHash = "aad3b435b51404eeaad3b435b51404ee:0123456789abcdef0123456789abcdef",
spn = "",
domain = "",
auth = amNtlm,
ssl = false,
port = 5985
)
warmSmartShell(client)
echo runCmd(client, "hostname", isCmd = false)
deleteShell(client)
Kerberos
import winrm
# Set KRB5CCNAME=FILE:/tmp/user.ccache before running
var client = newClient(
host = "dc01.corp.local",
user = "",
pass = "",
ntHash = "",
spn = "",
domain = "CORP.LOCAL",
auth = amKerberos,
ssl = false,
port = 5985
)
warmSmartShell(client)
echo runCmd(client, "Get-ADUser -Filter * | Select-Object Name", isCmd = false)
deleteShell(client)
CMD Execution
warmSmartShell(client)
echo runCmdFast(client, "ipconfig /all", isCmd = true)
deleteShell(client)
NTLM Encryption (Sealing)
var client = newClient(
host = "192.168.1.10",
user = "CORP\\administrator",
pass = "Password123",
ntHash = "",
spn = "",
domain = "",
auth = amNtlm,
ssl = false,
port = 5985,
msgEnc = meAlways
)
API Reference
Types
AuthMethod* = enum amNtlm, amKerberos
MessageEncryption* = enum meAuto, meAlways, meNever
WinRMClient* = object
host, username, password, ntHash, spn, domain: string
auth: AuthMethod
msgEnc: MessageEncryption
useSSL: bool
port: int
shellId*: string
remoteCwd*: string
cmdShellDenied*: bool
# ... internal fields
ChunkCallback* = proc(chunk: string)
PsrpDefragmenter* = object
Error Types
WinRMError* # Base error
WinRMAuthorizationError* # Authentication failure
InvalidShellError* # Shell no longer valid
WinRMWSManFault* # WS-Management fault (faultCode, faultDescription)
WinRMSoapFault* # SOAP fault (code, subcode, reason)
WinRMWMIError* # WMI error (errorCode, error)
WinRMHTTPTransportError* # HTTP transport error (statusCode)
Client
| Proc |
Description |
newClient*(host, user, pass, ntHash, spn, domain, auth, ssl, port, msgEnc): WinRMClient |
Create a new WinRM client |
warmSmartShell*(c) |
Initialize the optimal shell (PSRP or WinRS) |
ensureShell*(c, waitOpened) |
Ensure a PSRP shell/runspace is ready |
deleteShell*(c) |
Close and clean up the active shell |
closeNtlm*(c) |
Close the NTLM socket |
resetTransport*(c) |
Reset transport state for reconnection |
Command Execution
| Proc |
Description |
runCmd*(c, cmd, isCmd, mergeStreams): string |
Execute via PSRP with streaming output |
runCmdCollect*(c, cmd, isCmd, onChunk, mergeStreams): string |
Execute via PSRP and collect full output |
runCmdFast*(c, cmd, isCmd): string |
Execute via WinRS CMD shell |
runCmdFastCached*(c, cmd, isCmd, onChunk): string |
Execute via cached WinRS CMD shell |
runCmdFastOrPsrp*(c, cmd, isCmd): string |
Try WinRS first, fall back to PSRP |
File Transfer
| Proc |
Description |
uploadFileStream*(c, data, setup, total) |
Upload data in chunked Base64 fragments |
drawProgress*(label, current, total) |
Render a progress bar to terminal |
Utilities
| Proc |
Description |
genUuid*(): string |
Generate a random UUID |
encodePs*(cmd): string |
Base64-encode a PowerShell command (UTF-16LE) |
isManagedPe*(data): bool |
Check if binary data is a managed .NET PE |
isConnectionLostMessage*(msg): bool |
Check if error indicates connection loss |
psrpTextValue*(v): string |
Extract text from a PSRP value element |
psrpHexDecode*(text): string |
Decode PSRP hex-encoded Unicode text |
isRetryableFault*(faultCode): bool |
Check if a WS-Management fault is retryable |
secToDur*(seconds): string |
Format seconds as human-readable duration |
PSRP
| Proc |
Description |
newPsrpDefragmenter*(): PsrpDefragmenter |
Create a PSRP message defragmenter |
defragment*(d, base64Data): (complete, msgType, data) |
Feed a fragment and check for completion |
fragmentMessage*(objectId, msg, maxSize): seq[string] |
Fragment a PSRP message into Base64 chunks |
Constants
RESOURCE_URI_CMD* = "http://schemas.microsoft.com/wbem/wsman/1/windows/shell/cmd"
RESOURCE_URI_POWERSHELL* = "http://schemas.microsoft.com/powershell/Microsoft.PowerShell"
WSManMaxEnvelope* = 153600
WSManOperationTimeout* = 60
Architecture
The library implements the full WinRM protocol stack in a single file:
- NTLM: NTLMv2 negotiate/challenge/authenticate with native MD4/MD5/HMAC-MD5/RC4
- Kerberos: GSSAPI FFI to system
libgssapi_krb5 with SPNEGO wrapping
- SOAP/WS-Man: XML envelope construction for shell lifecycle and command execution
- PSRP: PowerShell Remoting Protocol with session capability exchange, runspace management, pipeline creation, message fragmentation/defragmentation, and output decoding
- WinRS: Windows Remote Shell for CMD execution
- NTLM Sealing: Message encryption/decryption with signing for HTTP transport
- Kerberos Wrapping: GSS-API
gss_wrap/gss_unwrap for message protection
License
MIT. See LICENSE.