blue0x1/nim-winrm

GitHub: blue0x1/nim-winrm

纯 Nim 语言实现的 WinRM 客户端库,支持 NTLM/Kerberos 认证、PowerShell/CMD 远程执行、文件传输和内存中 .NET 程序集执行。

Stars: 1 | Forks: 0

winrm.nim

Nim 原生 WinRM 客户端库

版本 1.0.0 · 作者 Chokri Hammedi (blue0x1) · 许可证 MIT

NTLM Kerberos PSRP WinRS File Transfer Zero Dependencies

Documentation nimrm CLI

一个完整、无依赖的 WinRM 协议栈实现,包括 NTLM 认证、通过 GSSAPI 的 Kerberos、PSRP(PowerShell 远程处理协议)、WinRS(Windows 远程 Shell)、NTLM 消息加密、文件传输和 .NET 程序集执行。 ## 法律声明 本库仅用于合法管理、安全测试以及对您拥有或已获得明确访问权限的系统进行研究。作者不对本软件被误用或造成的损害承担责任。 ## 功能特性 | 领域 | 详情 | | --- | --- | | 认证 | NTLMv2 密码、NTLMv2 哈希传递、通过 `libgssapi_krb5` 的 Kerberos | | 传输 | HTTP、HTTPS/TLS、NTLM 消息加密(密封) | | PowerShell | PSRP 会话/runspace 管理、管道创建、输出解码 | | CMD | WinRS shell 创建、命令执行、二进制输出 | | 传输 | 带自适应重试的分块 Base64 上传、流式下载 | | 内存中 | PowerShell 脚本导入、托管 .NET 程序集检测和执行 | | 加密 | 原生 MD4、MD5、HMAC-MD5、RC4、NTLM 密钥派生(认证不使用 OpenSSL)| | 协议 | SOAP/WS-Management 信封构造、SPNEGO/ASN.1 DER 编码 | ## 环境要求 | 组件 | 要求 | | --- | --- | | Nim | `>= 1.6.0` | | Kerberos | `libgssapi_krb5.so.2`(Linux)或 `libgssapi_krb5.dylib`(macOS)| | TLS | OpenSSL(`-d:ssl`)| ## 安装 ### Nimble ``` nimble install winrm ``` ### 手动安装 将 `winrm.nim` 复制到您的项目中并导入: ``` import winrm ``` ## 快速开始 ### NTLM 认证 ``` 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) ``` ### 哈希传递 ``` 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 执行 ``` warmSmartShell(client) echo runCmdFast(client, "ipconfig /all", isCmd = true) deleteShell(client) ``` ### NTLM 加密(密封) ``` 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 参考 ### 类型 ``` 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 ``` ### 错误类型 ``` 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) ``` ### 客户端 | 过程 | 描述 | | --- | --- | | `newClient*(host, user, pass, ntHash, spn, domain, auth, ssl, port, msgEnc): WinRMClient` | 创建新的 WinRM 客户端 | | `warmSmartShell*(c)` | 初始化最佳 shell(PSRP 或 WinRS)| | `ensureShell*(c, waitOpened)` | 确保 PSRP shell/runspace 已就绪 | | `deleteShell*(c)` | 关闭并清理活动的 shell | | `closeNtlm*(c)` | 关闭 NTLM 套接字 | | `resetTransport*(c)` | 重置传输状态以重新连接 | ### 命令执行 | 过程 | 描述 | | --- | --- | | `runCmd*(c, cmd, isCmd, mergeStreams): string` | 通过 PSRP 执行并流式输出 | | `runCmdCollect*(c, cmd, isCmd, onChunk, mergeStreams): string` | 通过 PSRP 执行并收集完整输出 | | `runCmdFast*(c, cmd, isCmd): string` | 通过 WinRS CMD shell 执行 | | `runCmdFastCached*(c, cmd, isCmd, onChunk): string` | 通过缓存的 WinRS CMD shell 执行 | | `runCmdFastOrPsrp*(c, cmd, isCmd): string` | 先尝试 WinRS,失败则回退到 PSRP | ### 文件传输 | 过程 | 描述 | | --- | --- | | `uploadFileStream*(c, data, setup, total)` | 以分块 Base64 片段上传数据 | | `drawProgress*(label, current, total)` | 在终端渲染进度条 | ### 工具函数 | 过程 | 描述 | | --- | --- | | `genUuid*(): string` | 生成随机 UUID | | `encodePs*(cmd): string` | 将 PowerShell 命令进行 Base64 编码(UTF-16LE)| | `isManagedPe*(data): bool` | 检查二进制数据是否为托管 .NET PE | | `isConnectionLostMessage*(msg): bool` | 检查错误是否表示连接丢失 | | `psrpTextValue*(v): string` | 从 PSRP 值元素中提取文本 | | `psrpHexDecode*(text): string` | 解码 PSRP 十六进制编码的 Unicode 文本 | | `isRetryableFault*(faultCode): bool` | 检查 WS-Management 错误是否可重试 | | `secToDur*(seconds): string` | 将秒数格式化为人类可读的时长 | ### PSRP | 过程 | 描述 | | --- | --- | | `newPsrpDefragmenter*(): PsrpDefragmenter` | 创建 PSRP 消息解碎片器 | | `defragment*(d, base64Data): (complete, msgType, data)` | 输入一个碎片并检查是否完成 | | `fragmentMessage*(objectId, msg, maxSize): seq[string]` | 将 PSRP 消息分片为 Base64 块 | ### 常量 ``` 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 ``` ## 架构 该库在一个文件中实现了完整的 WinRM 协议栈: - **NTLM**:使用原生 MD4/MD5/HMAC-MD5/RC4 的 NTLMv2 协商/挑战/认证 - **Kerberos**:GSSAPI FFI 调用系统 `libgssapi_krb5`,使用 SPNEGO 包装 - **SOAP/WS-Man**:用于 shell 生命周期和命令执行的 XML 信封构造 - **PSRP**:PowerShell 远程处理协议,包含会话能力交换、runspace 管理、管道创建、消息分片/解碎片和输出解码 - **WinRS**:用于 CMD 执行的 Windows 远程 Shell - **NTLM 密封**:用于 HTTP 传输的消息加密/解密和签名 - **Kerberos 包装**:GSS-API `gss_wrap`/`gss_unwrap` 用于消息保护 ## 许可证 MIT。参见 [LICENSE](LICENSE)。
标签:GSSAPI, HTTP, .NET程序集执行, Nim, NTLM, NTLMv2, OpenCanary, PowerShell远程处理, PSRP, Red Team, SCADA, T1021, T1059, T1086, T1550, T1573, Windows管理, Windows远程管理, WinRM, WinRS, 加密通信, 哈希传递, 文件传输, 远程执行, 零依赖