摘要
在前面的章节中,已经验证了包括原生TCP,HTTP 和 DNS 这几种常用的网络通信协议。对于攻击者来说,这些协议都有有趣的用例。尽管存在大量其他网络协议,但我们将通过检查 Server Message Block(SMB)来结束对网络协议的讨论,这个协议被证明是Windows后开发中最有用的协议。
SMB 可能是本书中最复杂的协议。它有多种用途,但是 SMB 通常用于分享资源,像文件,打印机和网络串口。对于有攻击想法的读者,SMB允许分布式网络节点通过命名管道进行进程间通信。换言之,可以在远程主机上执行任意的命令。这基本上就是PsExec的工作原理,PsExec是一个在本地执行远程命令的Windows工具。
SMB还有其他几个有趣的用例,特别是由于它处理NT LAN Manager (NTLM)身份验证的方式,这是Windows网络上大量使用的质问-响应安全协议。用于包括远程密码猜测,基于hash认证(或哈希加密),SMB中继和NBNS/LLMNR欺骗。完全讲解这些攻击需要用整本书的篇幅。
在本章的开头,将详细讲解如何在Go中实现SMB。然后,运用SMB包执行远程密码猜测,使用“哈希加密”技术,通过只使用密码的哈希,并破解密码的NTLMv2哈希,从而成功地验证自己的身份。
SMB 包
写这本书时,还没有官方发布的Go版本的 SMB 包,但是可以在 https://github.com/bhg/ch-6/smb/ 上找和本书中配套的相应版本。尽管在本章中不会展开该包的所有细节,但为了创建“说SMB”所必需的二进制通信,扔要学习执行SMB规范的基础知识,不像前面的章节那样,只是简单地重复使用完全兼容的软件包。在这将学习如何使用反射,在运行时检查接口数据类型和定义任意Go结构体中的字段标签来解编码复杂的,任意的数据,同时维护未来的消息结构和数据类型可伸缩性。
虽然我们构建的SMB库只允许基本的客户端通信,但代码库相当广泛。会有SMB包相关的例子,以便能完全理解像SMB认证这样的通信和任务是如何工作的。
理解SMB
和HTTP一样,SMB属于应用层的协议,可以和其他网络节点通信。不像HTTP 1.1那样使用可读的ASCII文本,SMB是一种二进制协议,它结合了固定长度和可变长度、位置和小端字段。SMB有几个版本,也称为方言,即版本2.0、2.1、3.0、3.0.2和3.1.1。每种方言都比其前身表现得更好。由于处理和需求因方言的不同而不同,因此客户端和服务器必须提前就使用哪种方言达成一致。在初始信息交换期间执行此操作。
通常,Windows系统支持多种方言,并选择服务端和客户端都支持的最新的方言。Microsoft提供了表6-1,列出了在协商期间Windows版本选择的方言。(Windows 10和WS 2016(图中没有显示)协商SMB 3.1.1版本。)
表6-1:由Windows版本协商的Smb方言
Operating system | Windows 8.1 WS 2012 R2 | Windows 8 WS 2012 | Windows 7 WS 2008 R2 | Windows Vista WS 2008 | Previous versions |
---|---|---|---|---|---|
Windows 8.1 WS 2012 R2 | SMB 3.02 | SMB 3.0 | SMB 2.1 | SMB 2.0 | SMB 1.0 |
Windows 8 WS 2012 | SMB 3.0 | SMB 3.0 | SMB 2.1 | SMB 2.0 | SMB 1.0 |
Windows 7 WS 2008 R2 | SMB 2.1 | SMB 2.1 | SMB 2.1 | SMB 2.0 | SMB 1.0 |
Windows Vista WS 2008 | SMB 2.0 | SMB 2.0 | SMB 2.0 | SMB 2.0 | SMB 1.0 |
Previous versions | SMB 1.0 | SMB 1.0 | SMB 1.0 | SMB 1.0 | SMB 1.0 |
本章使用SMB 2.1方言,因为多数现代 Windows版本支持。
理解SMB安全令牌
SMB 消息中含有安全令牌来认证网络中的用户和机器。非常像选择SMB方言的过程,通过一系列会话设置消息来选择身份验证机制,使客户端和服务器就相互支持的身份验证类型达成一致。Active Directory域通常使用NTLM安全支持提供者(NTLMSSP),这是一种二进制位置协议,它结合使用NTLM密码哈希和问-答令牌,以便跨网络对用户进行身份验证。问-答令牌类似于一个问题的加密回答;只有知道正确密码的实体才能正确回答这个问题。虽然本章只关注NTLMSSP,但Kerberos是另一种常见的身份验证机制。
将身份验证机制与SMB规范分离,给予SMB根据域和企业安全需求以及客户端-服务器支持,在不同的环境中使用不同的身份验证方法。然而,分离身份验证机制和SMB规范使得在Go中实现更加困难,因为身份验证令牌是经过编码的抽象语法符号1 (ASN.1)。对于本章,不需要对 ASN.1 了解太多——只了解是一种二进制编码格式,和一般地在SMB中使用的位置二进制编码不同。这种混合编码增加了复杂性。
理解 NTLMSSP 对于实现 SMB 至关重要,该实现足够智能,可以选择性地对消息字段进行编码和解码,同时考虑到相邻字段(在单个消息中)可能会以不同的方式编码或解码。Go中有二进制和ASN.1编码的标准包,但是Go的ASN.1包不是为通用用途而构建的;所以必须考虑到一些细微的差别。
搭建SMB Session
客户端和服务器执行以下步骤,能成功地设置SMB 2.1会话并选择NTLMSSP方言:
- 客户端发送 Negotiate Protocol 请求到服务器,消息中包含客户端支持的方言列表。
- 服务器响应 Negotiate Protocol 消息,该消息指明服务选择的方言。之后的消息都将使用该方言。响应中包含服务器支持的身份验证机制列表。
- 客户端选择一个支持的身份认证类型,例如 NTLMSSP,使用该信息创建并发送 Session Setup 请求消息到服务器。消息中含有一个封装的安全结构,表明它是一个NTLMSSP Negotiate 的请求。
- 服务器使用 Session Setup 响应消息回复。此消息表明需要进行更多处理,并包含服务器访问令牌。
- 客户端计算用户的 NTLM 哈希值(使用域名,用户名和密码作为输入),然后将其与服务器询问、随机客户端的询问和其他数据结合使用,生成询问响应。在客户端发送给服务器的新 Session Setup 请求消息中包含此内容。不像步骤3那样发送消息,封装的安全结构表明这是一个 NTLMSSP Authenticate 请求。这样,服务端能够区分这两个Session Setup SMB 请求。
- 服务器与可信的资源交互,例如使用域凭据进行身份验证的域控制器,以比较客户端提供的询问-响应信息与可信资源计算的值。如果相匹配,则对客户端进行身份验证。服务器发送 Session Setup 消息返回给客户端,表明登录成功。该消息中含有唯一的session id,客户端可用来追踪session状态。
- 客户端发送额外的消息来访问文件共享,命名管道,打印机等等;每个消息都包含 session id 作为引用,服务器可以通过该引用验证客户机的身份验证状态。
现在可能觉得SMB是多么复杂,并开始理解它为什么既没有一个标准也没有一个第三方Go包来实现SMB规范。而不是采取全面的方法,讨论我们创建的库的每一个细微差别,让我们专注几个结构,消息,或可以帮助您实现自己版本的定义良好的网络协议的独特方面。本章没有讨论大量的代码清单,而是只讨论好的内容,避免了信息过载。
可以使用以下相关规范作为参考,但不必一一阅读。通过谷歌搜索可以找到最新的版本。
MS-SMB2 我们试图遵循的SMB2规范。这是需要关注的主要规范,并封装了用于执行身份验证的Generic Security Service Application Programming Interface (GSS-API)结构。
MS-SPNG and RFC 4178 GSS-API规范含有封装MS-NLMP数据。该结构被ASN.1编码。
MS-NLMP 该规范用于理解NTLMSSP身份验证令牌结构和询问-响应格式。它包含用于计算诸如NTLM哈希和身份验证响应令牌等内容的公式和细节。与外部的GSS-API容器不同,NTLMSSP数据不是ASN.1编码的。
ASN.1 使用ASN.1格式编码数据的规范。
在讨论包中的代码片段之前,应该了解为了实现SMB通信需要克服的一些挑战。