域渗透之 NTLM 学习
Drunkbaby Lv6

总算是要开始内网学习了,也是拖了很久了吧

  • 环境问题其实可以拿红日靶场,根本不需要自己弄七弄八,很容易踩很多坑。

0x01 前言

总算是要开始内网学习了,也是拖了很久了吧

  • 刚开始学习内网不免会涉及到很多概念性的东西,这些东西我会用我自己的理解方式帮师傅们认识一遍。

0x02 NTLM

  • 很多文章都没有特别说清楚关于 NTLM 的这一些基础东西,我这里再重新书写一下

NTLM 是什么

用一句话概括一下 NTLM 是什么

NTLM 是一种认证协议,它使用挑战/响应(challenge/response)协议来交换消息,并通过加密的密码 hash 来验证用户身份。它在 Windows NT 和 Windows 2000 Server(或更高版本)的工作组环境中使用。

  • NTLM 中的挑战/响应(challenge/response)协议是什么意思呢,我们可以用这一个例子来说明一下

1、客户端向服务器发送一个包含明文登录用户名的请求(Type 1 message)
2、服务器生成一个 16 位的随机数(Challenge),明文发送回客户端(Type 2 message)
3、客户端使用自己的密码哈希对 Challenge 进行加密,生成一个响应(Response),并发送给服务器(Type 3 message)
4、服务器验证客户端发送的 Response 是否正确,如果正确则认证成功,否则认证失败

第二步生成的随机数是用来防止重放攻击的,挑战/响应(challenge/response)协议也同样防止了重放攻击。

NTLM 本地认证流程

在 Windows 登录界面当中,实际上电脑调用了 winlogon.exe 这个程序,winlogon.exe 即 Windows Logon Process,是 Windows NT 用户登陆程序,用于管理用户登录和退出。

1、当用户注销、重启、锁屏后,操作系统会让 winlogon.exe 显示登陆界面
2、当 winlogon.exe 接收到账号密码输入之后,会将密码交给 lsass 进程,LSASS 进程用于微软 Windows 系统的安全机制。它用于本地安全和登陆策略。
3、将明文密码加密成 NTLM Hash
4、与 SAM 数据库比较认证

这一个认证过程实际上是将用户的输入进行某种加密算法,最后得到一个 hash 值,这个 hash 值会与电脑上的 hash 值相比较。所以我们电脑上存储的都是 hash 值,因为这样就算电脑被攻击,攻击者得到的也是 hash 值,难以进行复原。

获取存储的 hash

作为攻击者的角度,我们需要了解 hash 存放的地址,本机用户的密码文件自然是存放在 SAM 文件中。

文件位置在:%SystemRoot%\system32\config\SAM

在注册表中的存储位置为 hklm\sam\sam\domains\account\users\ 下(必须使用 SYSTEM 权限才能看到)

我这里无法获取到 SYSTEM 权限,并且实际情况当中获取 SYSTEM 权限的难度比较大,所以我们可以通过到处注册表的方式来获取 samsystem 数据库的备份

1
2
3
reg save hklm\sam sam.save
reg save hklm\system system.save
reg save hklm\security security.save

我们可以使用 impacket-secretdump.py 脚本来导出密码存储哈希(当然也可以直接使用 mimikatzLaZagne 等工具)

用 impacket 读

命令如下,注意这个 py 文件被调用需要是在 impacket/examples 下,另外一个文件夹里面的脚本跑不通;并且在运行之前需要将 system.save 等这一类文件放到同目录下。

1
python3 secretsdump.py -system system.save -sam sam.save -security security.save LOCAL

这里我们可以发现存储用户的密码的格式为: uid:rid:lmhash:nthash,关于 lmhashnthash 会在后面进行详细介绍

1
Administrator:500:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::

UID 即 Windows 的登录用户名,这个很好理解。RID 则是 SID 的一部分,500-999 为保留,一般是 Windows 内置的,标准用户 RID 从 1000 开始。

用 Mimikatz 读

使用注意事项:

  • 需要管理员权限
  • 当机器安装了KB2871997补丁或者系统版本大于 windows server 2012 时,系统的内存中就不再保存明文的密码,这样利用 mimikatz 就不能从内存中读出明文密码了。

爆密码的命令如下

1
mimikatz.exe ""privilege::debug"" ""sekurlsa::logonpasswords""

其中 NTLM 值与后文用到的 python 脚本运行生成的值一样

LM Hash

LM Hash 全称 LAN Manager Hash 是 Windows 使用的最古老的密码存储,其历史可追溯到 1980 年代的 OS / 2;LM Hash 将密码分成两个 7 个字符的部分,然后对每个部分进行散列,得到一个 16 字节的哈希值。LM Hash 的安全性很低,因为它不区分大小写,也不使用盐值或迭代。

由于 LM Hash 存在的问题微软在 1993 年引入了 NT Hash。在 Windows 2000 版本至 2003 的版本系统默认使用 LM Hash,当密码超过 14 位时,则使用 NT Hash 进行存储。而在 Windows Visita 后,默认情况下只存储 NT Hash,LM Hash 则不再使用。如果用户密码为空或者不存储 LM Hash 的话,我们抓到的 LM Hash 是 AAD3B435B51404EEAAD3B435B51404EE

  • 这里我们可以回顾一下之前通过 impacket 抓包解析的 hash 内容,LM Hash 为 aad3b435b51404eeaad3b435b51404ee,这并没有价值。

部分工具的参数需要填写固定格式 LM hash:NT hash,可以将 LM hash 填0 (LM hash 可以为任意值),即00000000000000000000000000000000:NT hash

  • 相关策略配置: 本地组策略→本地策略→安全选项→网络安全(不同 Windows 版本可能有一些差异)

在下一次更改密码时不存储 LAN 管理器哈希值

注册表位置: HKLM\SYSTEM\CurrentControlSet\Control\Lsa\NoLmHash

NTLM Hash

Vista 之后 Windows 系统使用的 Hash,它的前身是 LM Hash,两者相差不大,只是使用的加密算法不同。在 Visita 系统后默认使用。

NTLM Hash 加密方法

1、将用户输入的密码转换成十六进制。假设用户密码为 root,则转换后为 726f6f74
2、将其转换为 unicode 格式即为:277c740c8fdae5dd75e47312b56af866
3、使用 md4 加密值为329153f560eb329c0e1deea55e88a1e9

1
2
3
4
5
6
7
8
import binascii  
import hashlib

password = input("Your Password:")
print("Your password is : " + password)
hash = hashlib.new('md4' , password.encode("utf-16le")).digest()
hash_hex = binascii.hexlify(hash)
print("NTLM answer is : " + str(hash_hex, 'UTF-8'))

Net-NTLM hash

Net-NTLM Hash 通常是指在网络环境中在 NTLM 认证过程 Type3(响应阶段)中的 Response(NTProofStr)、Blob 和 Type2 阶段(质询阶段)的 ServerChallenge、用户名、请求的域名拼接而成的值。

格式为(Net-NTLM v2):

1
username::domain:server challenge:response(HMAC-MD5):blob

但 Response 通常有以下几种类型:

  • LM Response, 早期使用的响应类型
  • LMv2 Response,在启用 NTLM v2 系统上将替换 LM 响应。
  • NTLM v1 Response,基于 Windows NT 客户端,如 Windows 2000 、XP。
  • NTLM v2 Response,Windows NT Service Pack 4 引入的响应类型,在 NTLMv2 启用的系统上将替换 NTLM 响应。
  • NTLM2 Session Response, 用于在没有 NTLMv2 身份验证的情况下协商 NTLM2 会话安全性时,此方案会更改 LM NTLM 响应的语义。
  • Anonymous Response,当匿名上下文正在建立时使用; 没有提供实际的证书,也没有真正的身份验证。“存根”字段显示在类型 3 消息中。

这些响应可以在本地安全策略→本地策略→安全选项→网络安全:LAN 管理器身份验证级别中配置。

注册表位置为:HKLM\SYSTEM\CurrentControlSet\Control\Lsa\LmCompatibilityLevel

Value Options Description
0 发送 LM NTLM 响应 客户端使用 LM 和 NTLM 身份验证,而决不会使用 NTLMv2 会话安全;域控制器接受 LM、NTLM 和 NTLMv2 身份验证。
1 发送 LM 和 NTLM - 如果已协商,则使用 NTLMv2 会话安全 客户端使用 LM 和 NTLM 身份验证并在服务器支持时使用 NTLMv2 会话安全。 域控制器接受 LM、NTLM 和 NTLMv2 身份验证。
2 仅发送 NTLM 响应 客户端只使用 NTLM 身份验证并在服务器支持时使用 NTLMv2 会话安全。 域控制器接受 LM、NTLM 和 NTLMv2 身份验证。
3 仅发送 NTLMv2 响应 客户端只使用 NTLMv2 身份验证并在服务器支持时使用 NTLMv2 会话安全。 域控制器接受 LM、NTLM 和 NTLMv2 身份验证。
4 仅发送 NTLMv2 响应/拒绝 LM 客户端只使用 NTLMv2 身份验证并在服务器支持时使用 NTLMv2 会话安全。 域控制器拒绝 LM,而只接受 NTLM 和 NTLMv2 身份验证。
5 仅发送 NTLMv2 响应/拒绝 LM 和 NTLM 客户端只使用 NTLMv2 身份验证并在服务器支持时使用 NTLMv2 会话安全。 域控制器拒绝 LM 和 NTLM,而只接受 NTLMv2 身份验证。

各系统的默认值为:

  • Windows 2000 以及 Windows XP: 发送 LM & NTLM 响应
  • Windows Server 2003: 仅发送 NTLM 响应
  • Windows Vista、Windows Server 2008、Windows 7 以及 Windows Server 2008 R2 及以上: 仅发送 NTLMv2 响应

0x03 NTLM 身份认证流量分析

环境搭建

  • 搭个锤子环境,拿红日就完事儿。

最开始环境搭建的时候看其他师傅文章很不准确,导致踩坑踩了很久。。。

需要的虚拟机是 Win2012 以及一台 Win7

首先两台虚拟机都需要桥接,然后配置 IP,因为 Win2012 是域服务器,所以需要让 Win7 指向/归于 Win2012。

设置 IP 需要是和物理机处于同一网段下,这里之前被坑死了。

Win2012 (DC 域控)配置如下

IP:192.168.5.157
子网掩码:255.255.255.0
默认网关:192.168.5.1

首选 DNS:192.168.5.157
备用 DNS:8.8.8.8

Win7 (域内普通主机)配置如下

IP:192.168.5.158
子网掩码:255.255.255.0
默认网关:192.168.5.1

首选 DNS:192.168.5.157
备用 DNS:8.8.8.8

至此,用 Win7 是可以 ping 通 Win2012 的

win2012 域环境配置

配置完毕 IP 之后,在 win2012 的机器上添加 Windows 功能

  • Active Directory 域服务
  • DNS 服务器

安装完成后可以在左侧找到 AD DS 服务

接着下一步,安装,然后点 AD DS 这里,有一个 “将此服务器提升为域控制器”

添加新林:

将根域名设置为 drunkbaby.com

再自行设置域的还原密码,我这里是 root123!

之后一路保持默认即可,安装完毕后,系统会自动重启。接下来创建 AD 用户,打开服务器面板的工具——Active Directory 用户和计算机

选择 User 右键新建用户

输入密码后创建即可

至此,win2012 的域控配置已经完成,密码为 root123123!,同户名为 User

win7 域环境配置

配置完 IP 之后,进入到我的电脑/系统属性的地方,进入计算机名/域更改

输入之前的账号密码,即可。

重启后,配置生效。

可以看到这个时候 win7 已经加入了 drunkbaby.com 的域中

NTLM 流量分析

在 Win7 当中输入命令如下

1
net use \\192.168.5.157\ipc$ root123123! /user:User

在 atsud0 师傅的文章中说了如下一个场景,我觉得很好,就直接拿来用了 https://atsud0.me/2022/03/07/%E3%80%90%E5%9F%9F%E6%B8%97%E9%80%8F%E3%80%91%E6%B5%85%E6%B7%A1NTLM-%E5%86%85%E7%BD%91%E5%B0%8F%E7%99%BD%E7%9A%84NTLM%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/#%E8%AE%A4%E8%AF%81%E5%8E%9F%E7%90%86

来假设一个场景

有这么一个人,她叫”纯酱、”。她是某公司财务部的人员。某一天早晨,她登录了自己的办公电脑,正打算开始今天的工作。突然收到一封邮件。

Dear ….

由于近期xxx原因,微软官方于x年x月x日针对xxx发布了修复补丁。内部定义危险级别为严重,请各位员工立刻使用自己的内部帐号登录文件共享服务器10.1.1.5获取补丁进行更新。

信息技术部

“纯酱、”同事作为遵守公司规则制度的好员工,那肯定立刻就登录上文件共享服务器获取补丁了啊。然后”纯酱、”输入了自己的帐号密码登录 10.1.1.5 了。

那么这里的认证流程及本是这样工作的。

搞了很久,最后在 Win7 机子上装了 Wireshark,版本是 wireshark-2-0-4-32-bit

1、纯酱用户登录客户端电脑

2、在客户端上请求服务端服务,并输入服务器要求的帐号密码。本地将会计算并缓存输入的密码的NTLM Hash。

3、Type1阶段协商 客户端向服务器发送Type1消息,主要包含客户端支持和向服务器端请求的功能列表。(并不会发送明文用户名)

4、Type2阶段质询 服务器收到客户端Type1消息的请求,作为回应会发送Type2消息请求给客户端,主要包含Server Challenge和服务器的功能信息。(Challenge是随机生成的16位字符串)

5、Type3阶段身份验证 客户端收到服务器Type2消息后,将会从Type2消息里面提 Server Challenge,用输入的密码NTLM-hash和Server Challenge进行加密运算(根据Flags设置 加密方式亦有所不同),得到Response。然后客户端将会把Type3消息发送给服务器。

6、服务器收到Type3消息后。将根据用户名来做进一步判断,如果是本地用户的话,会在SAM数据库里面拿这个用户的NTLM Hash,在客户端发送的Response字段提取相关的字段,进行和客户端几乎一样的加密运算,得出一个Response,服务器将会拿这个Response和Type3消息 客户端生成的Response进行对比,如果一致就验证通过。如果是域用户的话,服务器将会通过netlogon协议建立安全通道,将ServerChallenge、UserName、Response消息转发给域控。域控再去ntds.dit判断用户存不存在,然后DC将进行验证工作并把返回结果给服务器,服务器再根据DC的响应返回给客户端。

所以请求的用户是本地用户还是域用户的区别在于Type3阶段之后服务器的处理方式。

下面就是介绍三个过程中的部分细节。不感兴趣就可以忽略。

Type 1 协商

这个过程主要就是客户端向服务端发送 type1 阶段的消息,以开启 NTLM 认证,并且通过一系列选项来设置身份验证规则,如果需要,它还可以告诉服务器客户端的工作站名称以及拥有的域(绝对不会发送明文用户名)。服务器可以用这些信息来确定客户端是否符合身份验证的条件。

阶段 1 的包文主要包含以下结构

Description Content
0 NTLMSSP Signature Null-terminated ASCII “NTLMSSP” (0x4e544c4d53535000)
8 NTLM Message Type long (0x01000000)
12 Flags long
(16) Supplied Domain (Optional) security buffer
(24) Supplied Workstation (Optional) security buffer
(32) OS Version Structure (Optional) 8 bytes
(32) start of data block (if required)

目前抓到的流量包是通过 Win7 机子登录得到的流量包,直接用 net use 命令是抓不到的

奇怪的是,我和 atsud0 师傅抓到的流量包并不是很相似,atsud0 师傅抓到了一个 NTLMSSP 的包,但是我这里没有抓到,可能是因为我抓的是 Win7 的登录包,是域中服务器的包,而 atsud0 师傅抓的是 Win2012 的包,然而最后抓了 Win2012 的包还是没成功,也可能是我环境的配置有问题,就先借用 atsud0 师傅的截图来分析了

抓包信息如下:

Signature (8 bytes): 8字节 必须包含字符数组:(‘N’, ‘T’, ‘L’, ‘M’, ‘S’, ‘S’, ‘P’, ‘\0’)

MessageType (4 bytes): 表示消息类型,值必须为 0x0000001

Negotiate Flags : NEGOTIATE结构体,相关的配置选项。结构体内的每个字段详细的含义都可以在https://docs.microsoft.com/zh-cn/openspecs/windows_protocols/ms-nlmp/99d90ff4-957f-4c8a-80e4-5bfe5a9a9832http://davenport.sourceforge.net/ntlm.html#theNtlmFlags了解。

Version字段取决于Negotiate Flags结构中的Negotiate Version的值。如果该值为0,则不会显示Version字段,并且该字段是否存在都不影响NTLM消息的处理。

如果该值为 1,Version 字段也会在包文中出现,并且内容基本上是为 winver.exe 的内容。

Version 字段结构

Description Content
0 Major Version Number 1 byte
1 Minor Version Number 1 byte
2 Build Number short
4 NTLMRevisionCurrent 0x0000000f

还有其他的字段解释:NEGOTIATE_MESSAGE

下面是一个十六进制Type1阶段的消息(关于Flag的值可以看这里:http://davenport.sourceforge.net/ntlm.html#theNtlmFlags):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
例子:
4e544c4d5353500001000000050288a000000000000000000000000000000000

0x4e544c4d53535000 NTLMSSP签名(固定格式)
0x01000000 消息类型,这里是阶段1的消息类型
0x050288a0 = 0xa0880205(以小端(低位在前)的字节排序)

05=Negotiate Unicode(0x00000001) + Request Target
(0x00000004)
02=Negotiate NTLM(0x00000200)
88=Negotiate NTLM2 Key(NEGOTIATE_EXTENDED_SESSIONSECURITY 0x00080000) + Negotiate Target Info(0x00800000)
a0=Negotiate 56(0x80000000) + Negotiate 128(0x20000000)

Flags的值中,没有表示设置了Negotiate Domain Supplied、Negotiate Workstation Supplied以及Version的值,所以后面没有SecurityBuffer、Version等字段

Type 2 质询

Type2 消息由服务器发送给客户端,响应Type1消息,主要包含服务器生成的Challenge,并且包含Type1消息协商时的相关信息。

阶段2的包文主要包含以下结构

Description Content
0 NTLMSSP Signature Null-terminated ASCII “NTLMSSP” (0x4e544c4d53535000)
8 NTLM Message Type long (0x02000000)
12 Target Name security buffer
20 Flags long
24 Challenge 8 bytes
(32) Context (Optional) 8 bytes (two consecutive longs)
(40) Target Information (Optional) security buffer
(48) OS Version Structure (Optional) 8 bytes
32 (48) (56) start of data block

Signature (8 bytes): 8字节 必须包含字符数组:(‘N’, ‘T’, ‘L’, ‘M’, ‘S’, ‘S’, ‘P’, ‘\0’)

MessageType (4 bytes): 表示消息类型,值必须为0x0000002。

Negotiate Flags(4 bytes) : NEGOTIATE结构体,相关的配置选项。和Type1消息的Negotiate Flags大致相同,不过是表示服务器支持的选项,如果有negotate_message则表示从客户端提供的选项做选择。

Target Name 包含身份验证目标的名称,通常是响应客户端在Type1消息中Flags中的Request Target选项。

ServerChallenge(8 bytes):随机生成的16位随机值。

Reserved (8 bytes):发送时必须设为0,接受时必须被忽略。

TargetInfoFields(8 bytes):值的内容通常取决于NTLMSSP_NEGOTIATE_TARGET_INFO标志有没有被设置(注:除Windows NT,Windows 2000,Windows XP和Windows Server 2003之外,始终发送TargetInfo字段。)。

要想理解每个字段的详细信息,还是建议去阅读:CHALLENGE_MESSAGE以及The Type 2 Message

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
例子
4e544c4d53535000020000000800080038000000050289a2dea8b919645716230000000000000000a200a200400000000601b11d0000000f4400430030003100020008004400430030003100010010005300450052005600450052003000310004001c006100740073007500640030002e006c00610062002e0063006f006d0003002e00530065007200760065007200300031002e006100740073007500640030002e006c00610062002e0063006f006d0005001c006100740073007500640030002e006c00610062002e0063006f006d000700080020b70cb6992bd80100000000

0x4e544c4d53535000 NTLMSSP签名

02000000 = 00000002 消息类型
0x0800 = 0x0008 TargetNameLen

0x0800 = 0x0008 TargetNameMaxLen

0x38000000 = 0x00000038 TargetNameBufferOffset

0x050289a2 = 0xa2890205 NegotiateFlags

05=Negotiate Unicode(0x00000001) + Request Target(0x00000004)

02=Negotiate NTLM(0x00000200)

89=Negotiate NTLM2 Key(NEGOTIATE_EXTENDED_SESSIONSECURITY 0x00080000) + Negotiate Target Info(0x00800000)+ Target Type Domain (0x00010000)

a2=Negotiate 56(0x80000000) + Negotiate 128(0x20000000)+ Version(0x02000000)

dea8b91964571623 Server Challenge(随机16位)

0000000000000000 Reserved

a200a20040000000 TargetInfoFields

a200 = 0x00a2 TargetInfoLen
a200 =0x00a2 TargetInfoMaxLen
40000000 = 0x00000040 TargetInfoOffset


0601b11d0000000f Version

06=0x06 Major Version
01=0x01 Minor Version
b11d=0x1db1 Build
000000 Reseved
0f = 0x0f NTLMRevisionCurrent


4400430030003100020008004400430030003100010010005300450052005600450052003000310004001c006100740073007500640030002e006c00610062002e0063006f006d0003002e00530065007200760065007200300031002e006100740073007500640030002e006c00610062002e0063006f006d0005001c006100740073007500640030002e006c00610062002e0063006f006d000700080020b70cb6992bd801
.....后面接着的payload信息就是TargetName、Targetinfo的信息

00000000 结束字段块

在服务器创建Type2消息后,将会将Type2消息发送给客户端。

Type 3 验证

Type3消息是身份验证的最后一步,该步骤是客户端对Type2消息的响应,客户端将使用输入的NTLM-Hash对服务器随机生成的Challenge值进行复杂的加密运算得到Response,将其作为Type3消息发送给服务器。

Response是最关键的部分是它向服务器证明了客户端知道用户的帐号密码。服务器收到客户端发送的Type3消息,会判断用户名是本地用户还是域用户名,如果是本地用户将会在SAM中找到这个用户的NTLM-Hash,并从客户端发送的Type3消息中提取相关字段,和客户端进行几乎一样的加密运算,最后得到的Response将会和客户端发送的Response进行比较,如果一致则认证通过。如果是在域用户的话,服务器会通过Netlogon安全通道,将Response、Username、ServerChallenge转发给域控,将验证工作交给去进行,DC将会返回结果给服务器,服务器再根据DC的响应返回给客户端。

Description Content
0 NTLMSSP Signature Null-terminated ASCII “NTLMSSP” (0x4e544c4d53535000)
8 NTLM Message Type long (0x03000000)
12 LM/LMv2 Response security buffer
20 NTLM/NTLMv2 Response security buffer
28 Target Name security buffer
36 User Name security buffer
44 Workstation Name security buffer
(52) Session Key (optional) security buffer
(60) Flags(optional) security buffer
(64) OS Version Structure (Optional) 8 bytes
52 (64) (72) start of data block

Signature (8 bytes): 8字节 必须包含字符数组:(‘N’, ‘T’, ‘L’, ‘M’, ‘S’, ‘S’, ‘P’, ‘\0’)

MessageType (4 bytes): 表示消息类型,值必须为0x0000003。

The LM/LMv2 and NTLM/NTLMv2 responses LM/LMv2 NTLM/NTLMv2这两个响应是客户端收到Type2消息用用户输入的密码hash对Challege生成的。

LmChallengeResponseFields(8 bytes),包含LmChallengeResponseLen(2 bytes)、LmChallengeResponseMaxLen(2 bytes)、LmChallengeResponseBufferOffset(4 bytes)字段。如果客户端不发送LmChallengeResponse,Len字段则为0。
NtChallengeResponseFields (8 bytes),包含NTChallengeResponseLen(2 bytes)、NTChallengeResponseMaxLen(2 bytes)、NTChallengeResponseBufferOffset(4 bytes)字段。如果客户端不发送NTChallengeResponse,Len字段则为0。

DomainNameFields (8 bytes),包含DomainNameLen(2 bytes)、DomainNameMaxLen(2 bytes)、DomainNameBufferOffset(4 bytes)字段。如果客户端不发送DomainName,Len字段应为0。

UserNameFields (8 bytes),,包含UserNameLen(2 bytes)、UserNameMaxLen(2 bytes)、UserNameBufferOffset(4 bytes)字段。如果客户端不发送UserName,Len字段应为0。

NegotiateFlags (4 bytes):这里表示的是客户端协商的配置。

这里细说下 NTChallengeResponse,NTChallengeResponse的结构为

Description Content
Response(ntlmssp.ntlmv2_response.ntproofstr)16bytes
NTLMv2_CLIENT_CHALLENGE

而NTLMv2_CLIENT_CHALLENGE(Blob)的结构是这样的

Description Content
0 Blob Signature 0x01010000
4 Reserved long (0x00000000)
8 Timestamp 表示自1月1日1601年1月1日以來微秒的十分之一
16 Client Nonce(NTLMv2 Client Challenge) 8 bytes(随机生成)
24 Unknown 4 bytes(0x00000000)
28 Target Information 从type2阶段来的目标信息块
Unknown 4bytes

想了解每个字段的含义还是得去看官方文档AUTHENTICATE_MESSAGE

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
例子:4e544c4d5353500003000000180018005a000000f000f0007200000000000000400000001a001a0040000000000000005a0000000000000062010000050288a0410064006d0069006e006900730074007200610074006f0072001a8e5080fb4a6f0a8bf3e0669eb146f37a735845757168659a792665c56f71be45ecbe9c7d7a99b0010100000000000020b70cb6992bd8017a7358457571686500000000020008004400430030003100010010005300450052005600450052003000310004001c006100740073007500640030002e006c00610062002e0063006f006d0003002e00530065007200760065007200300031002e006100740073007500640030002e006c00610062002e0063006f006d0005001c006100740073007500640030002e006c00610062002e0063006f006d000700080020b70cb6992bd80109001a0063006900660073002f00530045005200560045005200300031000000000000000000

4e544c4d53535000 NTLMSSP Signature

03000000 NTLM Message Type

180018005a000000 LM/LMv2 Respons
1800 = 0x0018 = 24 Len & MaxLen
5a000000 = 0x0000005a = 90 Offset LM/LMv2 Respons出现的位置是第90个字节的时候,长度为24。

f000f00072000000 NTLM/NTLMv2 Response
f000=0x00f0 = 240 Len & MaxLen
72000000 = 0x00000072 = 114 Offset NTLM/NTLMv2 Respons出现的位置是第240个字节的时候,Offset为114。

0000000040000000 Domain Name
0000=0x0000 Len为0 ,DomainName为空
40000000 = 0x00000040 Offset

1a001a0040000000 UserName
1a00 = 0x001a =26 Len & MaxLen
40000000 =0x00000040 offset username 长度26

000000005a000000 HostName
0000=0x0000 Len为0 ,空
5a000000 = 0x0000005a = 90 Offset

0000000062010000 SessionsKeys
0000=0x0000 Len为0 ,空
62010000 = 0x00000162 offset

050288a0 Flags 和Type1的相同


410064006d0069006e006900730074007200610074006f007200 Offset:64 长度26 A d m i n i s t r a t o r因为是unicode,所以长度是2倍



1a8e5080fb4a6f0a8bf3e0669eb146f37a73584575716865 Offset:90 长度24 LM/LMv2 Respons


9a792665c56f71be45ecbe9c7d7a99b0010100000000000020b70cb6992bd8017a7358457571686500000000020008004400430030003100010010005300450052005600450052003000310004001c006100740073007500640030002e006c00610062002e0063006f006d0003002e00530065007200760065007200300031002e006100740073007500640030002e006c00610062002e0063006f006d0005001c006100740073007500640030002e006c00610062002e0063006f006d000700080020b70cb6992bd80109001a0063006900660073002f00530045005200560045005200300031000000000000000000 NTLM/NTLMv2Response

Response 9a792665c56f71be45ecbe9c7d7a99b0
Blob 010100000000000020b70cb6992bd8017a7358457571686500000000020008004400430030003100010010005300450052005600450052003000310004001c006100740073007500640030002e006c00610062002e0063006f006d0003002e00530065007200760065007200300031002e006100740073007500640030002e006c00610062002e0063006f006d0005001c006100740073007500640030002e006c00610062002e0063006f006d000700080020b70cb6992bd80109001a0063006900660073002f00530045005200560045005200300031000000000000000000

Blob Signature 4bytes : 01010000 =0x01010000
Reserved 4 bytes : 00000000 = 0x00000000
Timestamp 8 bytes: 20b70cb6992bd801 = 0x20b70cb6992bd801
client nonce 8bytes : 7a73584575716865 = 0x7a73584575716865
end subblock: 00000000 = 0x00000000
target information: 020008004400430030003100010010005300450052005600450052003000310004001c006100740073007500640030002e006c00610062002e0063006f006d0003002e00530065007200760065007200300031002e006100740073007500640030002e006c00610062002e0063006f006d0005001c006100740073007500640030002e006c00610062002e0063006f006d000700080020b70cb6992bd80109001a0063006900660073002f005300450052005600450052003000310000000000
enbsubblock: 00000000

The NTLMv2 Response生成

这里注意NTLM/NTLMv2Response,我们可以发现NTLMv2Response里面前16 Bytes是一段HMAC-MD5生成的值。被称为Response,或者是NTProofStr。这一段值的生成方式比较复杂,受客户端和服务端Flags(参数)的影响。

简单的介绍下最基础的生成方式(根据Flags的设置 加密方式会有所不同(比如如果是NTLMv2SessionResponse计算方式就会和下面的不一样)

  1. 将明文密码转换为NTLM-Hash(前面有介绍NTLM Hash生成方式)
  2. 将用户名转换为大写,然后和域名(域名区分大小写,但是必须和Type3包文中显示的域名一致)拼接在一起,然后进行Unicode的十六进制编码转换.(这里编码始终使用Unicode即使Flags中设置了OEM).NTLM Hash作为Key 对其进行Hmac Md5加密:HMAC_MD5(((UserName).Upper()+domainName),NTLM Hash)得到ntlmV2Hash
  3. ServerChallenge和Blob进行拼接.使用第三步得到的ntlmV2hash对其进行加密:HMAC_MD5((ServerChallenge+Blob),ntlmv2hash)得到Response(NTProofStr)
  4. 将Response(NTProofStr)和Blob重新进行拼接 得到NTLMv2 Response.

Examples(案例来自:TheNTLMv2Response):

1
2
3
4
5
6
7
8
9
10
11
Target:DOMAIN
Username:user
Password:SecREt01
ServerChallenge:0x123456789abcdef
TargetInformation:0x02000c0044004f004d00410049004e0001000c005300450052005600450052000400140064006f006d00610069006e002e0063006f006d00030022007300650072007600650072002e0064006f006d00610069006e002e0063006f006d0000000000
Timestamp:0x0090d336b734c301
Client nonce:0xffffff0011223344

ServerChallenge+Blob:
0x0123456789abcdef01010000000000000090d336b734c301ffffff00112233440000000002000c0044004f004d00410049004e0001000c005300450052005600450052000400140064006f006d00610069006e002e0063006f006d00030022007300650072007600650072002e0064006f006d00610069006e002e0063006f006d000000000000000000

大致的 python 代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import binascii
import hashlib
import hmac

passwd="SecREt01"
unicode_hex_passwd = passwd.encode('utf-16le')
md4_passwd=hashlib.new("md4",unicode_hex_passwd).digest()
print(passwd,binascii.hexlify(md4_passwd))

username = "user".upper()
domain = "DOMAIN"

un_domain = username+domain
hex_undomain = un_domain.encode('utf-16le')
print("un_domain",binascii.hexlify(hex_undomain))

enc_res = hmac.new(md4_passwd,hex_undomain,hashlib.md5).digest()
print(binascii.hexlify(enc_res))

sc_blob=b"\x01\x23\x45\x67\x89\xab\xcd\xef\x01\x01\x00\x00\x00\x00\x00\x00\x00\x90\xd3\x36\xb7\x34\xc3\x01\xff\xff\xff\x00\x11\x22\x33\x44\x00\x00\x00\x00\x02\x00\x0c\x00\x44\x00\x4f\x00\x4d\x00\x41\x00\x49\x00\x4e\x00\x01\x00\x0c\x00\x53\x00\x45\x00\x52\x00\x56\x00\x45\x00\x52\x00\x04\x00\x14\x00\x64\x00\x6f\x00\x6d\x00\x61\x00\x69\x00\x6e\x00\x2e\x00\x63\x00\x6f\x00\x6d\x00\x03\x00\x22\x00\x73\x00\x65\x00\x72\x00\x76\x00\x65\x00\x72\x00\x2e\x00\x64\x00\x6f\x00\x6d\x00\x61\x00\x69\x00\x6e\x00\x2e\x00\x63\x00\x6f\x00\x6d\x00\x00\x00\x00\x00\x00\x00\x00\x00"
enc_res = hmac.new(enc_res,sc_blob,hashlib.md5).hexdigest()
print(enc_res)

最后得到的 Response 将会和 Blob 重新拼接.成为 NTLMv2 Response。

1
0xcbabbca713eb795d04c97abc01ee498301010000000000000090d336b734c301ffffff00112233440000000002000c0044004f004d00410049004e0001000c005300450052005600450052000400140064006f006d00610069006e002e0063006f006d00030022007300650072007600650072002e0064006f006d00610069006e002e0063006f006d000000000000000000

前面说到Response有六种格式,但是他们使用的加密流程都是一样,区别在于Challenge和加密算法不同,这里就不细展开说其他Response的生成方式了,感兴趣的还是去阅读推荐文章。(这里注意一下包文里的NTChallengeResponse并不等于net-ntlm hashv2)

而NTLM v1与NTLM v2区别就是Challenge与加密算法不同,共同点就是加密的都是NTLM Hash。
Net-NTLM Hash v1的格式为:

1
username::hostname:LM response:NTLM response:challenge

Net-NTLM Hash v2的格式为:

1
username::domain:challenge:NTproofstring:modifiedntlmv2response

手动获取NTLM加密

搜索ntlmssp

找到NTLMSSP_AUTH的请求包,找到SMB2/Security Blob层。

在这里我们可以看到认证的用户名、域名(我这里用的是工作组)。复制用户名和域名记录起来

1
2
UserName:Administrator
DomainName:NULL

接着继续找到NTLM Response部分,找到NTLMv2 Response和NTProofStr字段,将其以16进制字段复制,记录起来。

1
2
NTLMv2 Response:9a792665c56f71be45ecbe9c7d7a99b0010100000000000020b70cb6992bd8017a7358457571686500000000020008004400430030003100010010005300450052005600450052003000310004001c006100740073007500640030002e006c00610062002e0063006f006d0003002e00530065007200760065007200300031002e006100740073007500640030002e006c00610062002e0063006f006d0005001c006100740073007500640030002e006c00610062002e0063006f006d000700080020b70cb6992bd80109001a0063006900660073002f00530045005200560045005200300031000000000000000000
NTProofStr:9a792665c56f71be45ecbe9c7d7a99b0

将NTLMv2 Response开头和NTProofStr相同的部分值删掉

1
2
3
4
NTProofStr的值是 9a792665c56f71be45ecbe9c7d7a99b0 

删除之后的NTLMv2 Response字段是:
010100000000000020b70cb6992bd8017a7358457571686500000000020008004400430030003100010010005300450052005600450052003000310004001c006100740073007500640030002e006c00610062002e0063006f006d0003002e00530065007200760065007200300031002e006100740073007500640030002e006c00610062002e0063006f006d0005001c006100740073007500640030002e006c00610062002e0063006f006d000700080020b70cb6992bd80109001a0063006900660073002f00530045005200560045005200300031000000000000000000

接着过滤 ntlmssp.serverchallenge 的请求包

同样也是过滤SMB2/Security Blob层。找到NTLM Server Challenge值

1
NTLMServerChallenge:dea8b91964571623

然后按照以下字段组合在一起,保存到文本,然后就可以使用工具进行破解了。

1
2
3
username::domain:ServerChallenge:NTproofstring:modifiedntlmv2response

Administrator:::dea8b91964571623:9a792665c56f71be45ecbe9c7d7a99b0:010100000000000020b70cb6992bd8017a7358457571686500000000020008004400430030003100010010005300450052005600450052003000310004001c006100740073007500640030002e006c00610062002e0063006f006d0003002e00530065007200760065007200300031002e006100740073007500640030002e006c00610062002e0063006f006d0005001c006100740073007500640030002e006c00610062002e0063006f006d000700080020b70cb6992bd80109001a0063006900660073002f00530045005200560045005200300031000000000000000000

使用 john 进行破解

脚本获取NTLM加密

可以使用脚本,指定已经捕获了NTLM请求的pcap包进行获取。

然后可以使用hashcat进行破解:

1
hashcat -m 5600 hash.txt passwordlist.txt

SSP & SSPI

SSPI: Security Support Provider Interface 就是SSP的API接口,可以理解为该接口定义了很多安全有关的功能函数,但是没有具体的实现。然后SSP就是SSPI的实现。

SSP: Security Support Provider,直译为安全支持提供者,又名Security Package.可以理解为SSP就是一个DLL。微软实现了以下SSP,用于提供安全功能:

  1. NTLM SSP
  2. Kerberos
  3. Cred SSP
  4. Digest SSP
  5. Negotiate SSP
  6. Schannel SSP
  7. Negotiate Extensions SSP
  8. PKU2U SSP

在系统层面,SSP就是一个DLL用于实现身份验证功能,NTLM是基于Challenge/Response机制,Kerberos是基于ticket的身份验证。所以,我们也可以实现自己的SSP,让系统实现更多的身份验证方法,比如Mimikatz就自己实现了一个利用SSP机制的记录密码。

在抓包分析的时候,我们也能看见ntlmssp是在gssapi下面的。

因为sspi是gssapi的变体,这里出现gssapi是为了兼容。注册为SSP的好处就是,SSP实现了了与安全有关的功能函数,那上层协议(比如SMB)在进行身份认证等功能的时候,就可以不用考虑协议细节,只需要调用相关的函数即可。而认证过程中的流量嵌入在上层协议里面。不像kerbreos,既可以镶嵌在上层协议里面,也可以作为独立的应用层协议。ntlm是只能镶嵌在上层协议里面,消息的传输依赖于使用ntlm的上层协议。

HTTP是这样的:

0x04 NTLM Relay 攻击

在上面的认证过程中,我们知道了正常的 NTLM 认证流程是这样的:

如果这个时候有个中间人出现的话:

作为中间人,攻击者会将来自客户端的包转发给服务端,在将服务端的包转发给客户端,客户端生成 Response 后,再把 type3 包转发给服务端,服务端验证通过后,服务器将会授予攻击者访问的权限。

我自己由于环境一直起不来,目前这一部分的内容只能先行搁置了。

参考如下 【域渗透】浅淡NTLM(内网小白的NTLM学习笔记) (atsud0.me)

 评论