第6章:与SMB和NTLM交互

摘要

在前面的章节中,已经验证了包括原生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方言:

  1. 客户端发送 Negotiate Protocol 请求到服务器,消息中包含客户端支持的方言列表。
  2. 服务器响应 Negotiate Protocol 消息,该消息指明服务选择的方言。之后的消息都将使用该方言。响应中包含服务器支持的身份验证机制列表。
  3. 客户端选择一个支持的身份认证类型,例如 NTLMSSP,使用该信息创建并发送 Session Setup 请求消息到服务器。消息中含有一个封装的安全结构,表明它是一个NTLMSSP Negotiate 的请求。
  4. 服务器使用 Session Setup 响应消息回复。此消息表明需要进行更多处理,并包含服务器访问令牌。
  5. 客户端计算用户的 NTLM 哈希值(使用域名,用户名和密码作为输入),然后将其与服务器询问、随机客户端的询问和其他数据结合使用,生成询问响应。在客户端发送给服务器的新 Session Setup 请求消息中包含此内容。不像步骤3那样发送消息,封装的安全结构表明这是一个 NTLMSSP Authenticate 请求。这样,服务端能够区分这两个Session Setup SMB 请求。
  6. 服务器与可信的资源交互,例如使用域凭据进行身份验证的域控制器,以比较客户端提供的询问-响应信息与可信资源计算的值。如果相匹配,则对客户端进行身份验证。服务器发送 Session Setup 消息返回给客户端,表明登录成功。该消息中含有唯一的session id,客户端可用来追踪session状态。
  7. 客户端发送额外的消息来访问文件共享,命名管道,打印机等等;每个消息都包含 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通信需要克服的一些挑战。