
scan4all 中的 masterzen/winrm用 Go 通过 WinRM 远程执行 Windows 命令的原理与实战【免费下载链接】scan4allOfficial repository vuls Scan: 15000PoCs; 23 kinds of application password crack; 7000Web fingerprints; 146 protocols and 90000 rules Port scanning; Fuzz, HW, awesome BugBounty( ͡° ͜ʖ ͡°)...项目地址: https://gitcode.com/GitHub_Trending/sca/scan4all本篇以 vendored 依赖github.com/masterzen/winrm的官方 README 为主体系统讲解这个纯 Go 的 WinRM/WinRS 客户端库如何在目标 Windows 机器上配置 WinRM 服务以支持 Basic / Kerberos 认证如何通过NewEndpoint、NewClient、Parameters.TransportDecorator等 API 执行远程命令含 NTLM、Kerberos、SSH 隧道、mTLS 客户端证书等进阶用法并结合 scan4all 仓库源码说明该库如何被pkg/hydra暴力破解模块集成用于对 5985/5986 端口的 WinRM 服务做弱口令验证。读完后你应能独立调用该库完成远程命令执行并理解 scan4all 中 WinRM 凭据爆破的完整调用链。一、库定位纯 Go 的 WinRM 远程命令执行器READMEvendor/github.com/masterzen/winrm/README.md对库的定位很明确这是一个通过 WinRM/WinRS 在 Windows 机器上远程执行命令的 Go 库。几个关键事实认证模型是可插拔的原生支持本地账户的 Basic 认证也可以通过TransportDecorator换成 Negotiate/NTLM例如连接 Azure 原生虚拟机或 Kerberos域账户认证README 开头的 Note 指出该库的主目标场景是在 EC2 Windows 机器上执行远程命令且明确说明它不支持 GSSAPI不直接支持域用户的默认协商路径——这一点在使用时务必注意该库已经去除了对 Gokogiri 等 C 扩展的依赖是纯 Go 实现无需 CGO 环境即可交叉编译版本要求README 中不同章节分别提到 Golang 1.5 与 1.7以当前仓库为准scan4all 通过 go.mod 固定依赖为github.com/masterzen/winrm v0.0.0-20220917170901-b07f6cb0598d属于较新的提交快照。vendored 源码目录 vendor/github.com/masterzen/winrm 下的文件结构也印证了这些能力endpoint.go端点配置、client.go/shell.go/command.go会话与命令、http.goHTTP 传输、ntlm.goNTLM 认证、kerberos.goKerberos 认证、soap/SOAP/WS-Management 报文等。二、准备远程 Windows 机器WinRM 自 Windows Server 2008 起可用。README 给出了两种认证模式下在远程主机上以管理员身份运行 PowerShell 的完整配置步骤。2.1 Basic 认证本地账户在远程主机的 PowerShellRun as Administrator中依次执行winrm quickconfig y winrm set winrm/config/service/Auth {Basictrue} winrm set winrm/config/service {AllowUnencryptedtrue} winrm set winrm/config/winrs {MaxMemoryPerShellMB1024}README 同时给出三条重要注意事项N.B.Windows 防火墙必须处于开启状态否则winrm quickconfig无法正常工作参见 Microsoft KB #2004640不要禁用 Negotiate 认证winrm命令自身内部就依赖 Negotiate禁用它可能导致整个系统的winrm命令彻底不可用MaxMemoryPerShellMB在部分 Windows 2008 R2 系统上因 WinRM 自身 bug 不生效如果需要执行占用超过 150MB 内存的命令需安装 Microsoft KB #2842230 描述的 hotfix。2.2 Kerberos 认证域账户winrm quickconfig y winrm set winrm/config/service {AllowUnencryptedtrue} winrm set winrm/config/winrs {MaxMemoryPerShellMB1024}注意与 Basic 模式的区别Kerberos 模式不需要打开Auth {Basictrue}。README 强调 Basic 模式一节中的所有 N.B. 注意事项同样适用。三、核心 APIEndpoint 与 Parameters结合 vendored 源码可以把 README 示例中出现的两个核心构造函数拆解开。3.1NewEndpoint的 8 个参数endpoint.go 中的Endpoint结构体定义了全部字段NewEndpoint(host, port, https, insecure, Cacert, cert, key, timeout)的语义如下参数含义备注host主机名或 IPport端口常规值 5985HTTP/ 5986HTTPSWinRM 也可自定义监听端口https是否 HTTPS为 true 时 URL scheme 为 httpsinsecure是否跳过 SSL 证书校验自签证书场景常用CacertCA 证书 PEM 字节用于校验服务器证书cert客户端证书mTLS 客户端认证用key客户端私钥与 cert 配对timeout底层 TCP/HTTP 连接超时传 0 时默认为 60 秒源码中的默认值scan4all 的调用中即传 0 依赖该默认值最终请求 URL 由url()方法生成为http(s)://host:port/wsman。3.2Parameters与DefaultParametersparameters.go 定义了会话级元数据Timeout默认PT60SSOAP 请求超时ISO8601 时长格式Locale默认en-USEnvelopeSize默认153600字节150KBSOAP 报文大小上限TransportDecorator返回Transporter的工厂函数是切换 NTLM / Kerberos 等传输实现的挂载点Dial自定义拨号函数是打通 SSH 隧道等任意net.Dial语义通道的挂载点。README 也明确警告该库的 API 可能随时变动在生产代码中应锁定依赖版本scan4all 的 go.mod 正是这样做的。四、库使用示例继承自 README逐例讲解4.1 最简用法Basic 认证执行命令HTTP 传输endpoint : winrm.NewEndpoint(host, 5986, false, false, nil, nil, nil, 0) client, err : winrm.NewClient(endpoint, Administrator, secret) if err ! nil { panic(err) } ctx, cancel : context.WithCancel(context.Background()) defer cancel() client.RunWithContext(ctx, ipconfig /all, os.Stdout, os.Stderr)这是快速版接口一步创建 client 并执行命令局限是无法向命令发送 stdin 输入。4.2 带 stdin 输入的执行需要给命令喂输入时改用RunWithContextWithInputREADME 中同时给出了不带 ctx 的RunWithInput写法endpoint : winrm.NewEndpoint(localhost, 5985, false, false, nil, nil, nil, 0) client, err : winrm.NewClient(endpoint, Administrator, secret) if err ! nil { panic(err) } ctx, cancel : context.WithCancel(context.Background()) defer cancel() _, err client.RunWithContextWithInput(ctx, ipconfig, os.Stdout, os.Stderr, os.Stdin) if err ! nil { panic(err) }返回值是命令退出码0 表示成功这也是 scan4all 弱口令判定所依赖的语义见第五节。4.3 NTLM/Negotiate 认证如 Azure 原生虚拟机通过Parameters.TransportDecorator注入 NTLM 传输endpoint : winrm.NewEndpoint(localhost, 5985, false, false, nil, nil, nil, 0) params : winrm.DefaultParameters params.TransportDecorator func() winrm.Transporter { return winrm.ClientNTLM{} } client, err : winrm.NewClientWithParameters(endpoint, test, test, params) if err ! nil { panic(err) } _, err client.RunWithInput(ipconfig, os.Stdout, os.Stderr, os.Stdin) if err ! nil { panic(err) }4.4 Kerberos 认证域账户同样经由TransportDecorator把传输换成ClientKerberos其字段包含Username、Password、Hostname、Realm、Port、Proto、KrbConf、SPNendpoint : winrm.NewEndpoint(srv-win, 5985, false, false, nil, nil, nil, 0) params : winrm.DefaultParameters params.TransportDecorator func() winrm.Transporter { return winrm.ClientKerberos{ Username: test, Password: s3cr3t, Hostname: srv-win, Realm: DOMAIN.LAN, Port: 5985, Proto: http, KrbConf: /etc/krb5.conf, SPN: fmt.Sprintf(HTTP/%s, hostname), } } client, err : winrm.NewClientWithParameters(endpoint, test, s3cr3t, params) if err ! nil { panic(err) } ctx, cancel : context.WithCancel(context.Background()) defer cancel() _, err client.RunWithContextWithInput(ctx, ipconfig, os.Stdout, os.Stderr, os.Stdin) if err ! nil { panic(err) }对应 vendored 源码 kerberos.go 中的ClientKerberos实现。4.5 自定义 Dial通过 SSH 隧道打 WinRM当目标 Windows 不直连、但可达一台跳板 Linux 时可以用golang.org/x/crypto/ssh的Client.Dial直接赋给Parameters.DialsshClient, err : ssh.Dial(tcp, localhost:22, ssh.ClientConfig{ User: ubuntu, Auth: []ssh.AuthMethod{ssh.Password(ubuntu)}, HostKeyCallback: ssh.InsecureIgnoreHostKey(), }) endpoint : winrm.NewEndpoint(other-host, 5985, false, false, nil, nil, nil, 0) params : winrm.DefaultParameters params.Dial sshClient.Dial client, err : winrm.NewClientWithParameters(endpoint, test, test, params) if err ! nil { panic(err) } ctx, cancel : context.WithCancel(context.Background()) defer cancel() _, err client.RunWithContextWithInput(ctx, ipconfig, os.Stdout, os.Stderr, os.Stdin) if err ! nil { panic(err) }这个示例在 scan4all 这类内网渗透场景中有直接价值经堡垒机/跳板对 Windows 资产做 WinRM 探测时无需开放额外端口。4.6 直接使用 Shell/Command 级 APIREADME 还给出了绕过Run*便利方法、直接操作shell与command的更复杂示例适合需要精细控制流的场景stdin : bytes.NewBufferString(ipconfig /all) endpoint : winrm.NewEndpoint(localhost, 5985, false, false, nil, nil, nil, 0) client, err : winrm.NewClient(endpoint, Administrator, secret) if err ! nil { panic(err) } shell, err : client.CreateShell() if err ! nil { panic(err) } ctx, cancel : context.WithCancel(context.Background()) defer cancel() var cmd *winrm.Command cmd, err shell.ExecuteWithContext(ctx, cmd.exe) if err ! nil { panic(err) } go io.Copy(cmd.Stdin, stdin) go io.Copy(os.Stdout, cmd.Stdout) go io.Copy(os.Stderr, cmd.Stderr) cmd.Wait() shell.Close()从源码结构看shell.go提供CreateShell/Execute会话能力command.go提供Command的 stdin/stdout/stderr 管道与Wait/Stop生命周期控制Run*系列只是对其的封装。4.7 HTTPS mTLS 客户端证书不校验 CAclientCert, err : ioutil.ReadFile(/home/example/winrm_client_cert.pem) if err ! nil { log.Fatalf(failed to read client certificate: %q, err) } clientKey, err : ioutil.ReadFile(/home/example/winrm_client_key.pem) if err ! nil { log.Fatalf(failed to read client key: %q, err) } winrm.DefaultParameters.TransportDecorator func() winrm.Transporter { return winrm.ClientAuthRequest{} } endpoint : winrm.NewEndpoint( 192.168.100.2, // host to connect to 5986, // winrm port true, // use TLS true, // Allow insecure connection nil, // CA certificate clientCert, // Client Certificate clientKey, // Client Key 0, // Timeout ) client, err : winrm.NewClient(endpoint, Administrator, ) if err ! nil { log.Fatalf(failed to create client: %q, err) } ctx, cancel : context.WithCancel(context.Background()) defer cancel() _, err client.RunWithContext(ctx, whoami, os.Stdout, os.Stderr) if err ! nil { log.Fatalf(failed to run command: %q, err) }关键点insecuretrue表示不校验服务器证书而双向身份靠ClientAuthRequest传输 客户端证书/私钥完成此时密码字段可以传空字符串。4.8 关于 Context 取消的语义重要易错点README 特别提醒传给各 API 的context.Context被取消时并不会取消正在进行的 HTTP 请求本身而是通过调用command.Stop()让远程机器上的命令被中止。也就是说 ctx 控制的是远端命令生命周期而非客户端网络请求超时——网络层的超时由Endpoint.Timeout默认 60s负责。写批量扫描代码时必须区分这两者否则可能误判连接慢与命令慢的原因。五、构建与开发README 说明的构建方式git clone https://github.com/masterzen/winrm cd winrm make开发侧还要求Go 1.5README 后文另处写 1.7个别二阶依赖需要 Mercurial 与 Bazaar 工具make test跑测试make format按 Go 规范格式化make updatedeps更新依赖。vendored 目录中同样保留了 Makefile。对 scan4all 使用者而言这些仅具参考意义——库已经以依赖形式固化在 vendor 目录中正常构建 scan4all 即可。六、scan4all 中的实际应用WinRM 弱口令爆破scan4all 把该库集成进了pkg/hydra多协议爆破模块用于在发现开放的 WinRM 端口后验证弱口令。调用链如下端口发现阶段pkg/hydra/doNmapResult.go 解析 nmap 结果当检测到 5985/5986 端口且服务指纹包含 microsoft 字样时触发CheckWeakPassword(ip, winrm, port)把 WinRM 纳入弱口令检测协议集协议注册pkg/hydra/hydra.go 的ProtocolList中包含winrmCracker.Run()的 switch 分支将协议winrm映射到WinrmCracker随后由线程池按字典下发任务认证验证pkg/hydra/cracker.go 中的WinrmCracker对每一组user:pass调用winrm.WinrmAuth成功则把该凭据写入结果底层实现pkg/hydra/winrm/winrm.go 是整个集成的核心只有 20 余行func WinrmAuth(host, user, pass string, port int) (result bool, err error) { result false endpoint : winrm.NewEndpoint(host, port, false, false, nil, nil, nil, 0) client, err : winrm.NewClient(endpoint, user, pass) if err ! nil { //log.Println(WinrmAuth ,err) } res, err : client.Run(echo ISOK, os.Stdout, os.Stderr) if res 0 { result true } return result, err }可以看出它严格对应 README 的最简用法NewEndpoint使用 HTTP、不跳过证书校验、零值参数走默认 60s 超时NewClient以 Basic 认证用户名密码建连然后执行一条无副作用的echo ISOK命令以退出码 0 作为凭据有效的判据。这正好利用了 4.2 节所述Run*返回退出码的语义也是该库用于探测/验证而非真正命令执行时的标准姿势。文件头注释还留了两条渗透测试参考pentestlab.blog 的 WinRM 标签页与 WinRM 渗透测试文章及 nmap 探测命令nmap -p 5985 -sV说明作者参考的资料来源。从源码结构看scan4all 只使用了库的 Basic/HTTP 路径未使用TransportDecorator因此其 WinRM 爆破能力与 README 一致地受限于目标端已开启 Basic 认证且允许未加密传输即第二节winrm set ... AllowUnencryptedtrue的配置这恰是内网 Windows 弱口令场景中的常见暴露面。七、要点小结masterzen/winrm 是纯 Go 的 WinRM/WinRS 客户端NewEndpoint8 参数timeout 传 0 默认 60sNewClient/NewClientWithParametersRun*/CreateShell两级 API 覆盖绝大多数场景服务端必须先用 PowerShell 完成winrm quickconfig等配置Basic 与 Kerberos 两条路径的配置差异仅在于是否开启Auth BasictrueNTLM、Kerberos、SSH 隧道、mTLS 全部通过Parameters的TransportDecorator/Dial两个扩展点注入无需改动核心代码ctx 取消 远端command.Stop()不等于取消 HTTP 请求网络超时另由 Endpoint 超时控制scan4all 以退出码 0 即弱口令命中的方式复用该库形成 nmap 端口发现 → hydra 协议分发 → WinrmAuth 认证的完整 WinRM 弱口令检测链路。【免费下载链接】scan4allOfficial repository vuls Scan: 15000PoCs; 23 kinds of application password crack; 7000Web fingerprints; 146 protocols and 90000 rules Port scanning; Fuzz, HW, awesome BugBounty( ͡° ͜ʖ ͡°)...项目地址: https://gitcode.com/GitHub_Trending/sca/scan4all创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考