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.
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.
| 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 |
| Component | Requirement |
|---|---|
| Nim | >= 1.6.0 |
| Kerberos |
libgssapi_krb5.so.2 (Linux) or libgssapi_krb5.dylib (macOS) |
| TLS | OpenSSL (-d:ssl) |
nimble install winrmCopy winrm.nim into your project and import it:
import winrmimport 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)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)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)warmSmartShell(client)
echo runCmdFast(client, "ipconfig /all", isCmd = true)
deleteShell(client)var client = newClient(
host = "192.168.1.10",
user = "CORP\\administrator",
pass = "Password123",
ntHash = "",
spn = "",
domain = "",
auth = amNtlm,
ssl = false,
port = 5985,
msgEnc = meAlways
)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* = objectWinRMError* # 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)| 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 |
| 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 |
| Proc | Description |
|---|---|
uploadFileStream*(c, data, setup, total) |
Upload data in chunked Base64 fragments |
drawProgress*(label, current, total) |
Render a progress bar to terminal |
| 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 |
| 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 |
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* = 60The 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_krb5with 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_unwrapfor message protection
MIT. See LICENSE.