认证
注 : 笔记中拓扑图 drawio 与 xmind 源文件在其图片目录下
大纲
-
本地认证
- LM-Hash
- NTLM-Hash
- 本地认证流程
- DPAPI
-
网络认证
- LM
- NTLM
- Challenge/Response
- NTLMv2
- Net-NTLM hash
- 域环境中NTLM认证方式
- SSP & SSPI
- Signing
- Negotiation
- MIC
- EPA
- LmCompatibilityLevel
-
域认证
- MSCACHE
- Kerberos
- 简要概括认证过程
- 详细概括认证过程
- PAC
- SPN
- 委派
- 约束委派
- 基于资源的约束委派
本地认证
在 Windows 系统中本机的用户密码以 hash 形式存储在 %SystemRoot%\system32\config\sam
数据库文件中。sam 的简称是Security Account Manager,安全账户管理器。被保存的 hash 分为 LM Hash
和 NTLM hash
;微软在 Windows NT 4.0 中引入 SYSKEY 对 SAM
文件加密。而域内用户的密码 Hash 是存在域控的 NTDS.DIT
文件里面。
这个 SAM 文件中保留了计算机本地所有用户的凭证信息,可以理解为是一个数据库。登录系统的时候,系统会自动地读取 SAM
文件中的密码与键入的密码进行比对,如果相同,则认证成功。
操作系统启动之后,SAM
文件将同时被锁定。这意味着操作系统运行之时,用户无法打开或复制 SAM
文件。除了锁定,整个 SAM
文件还经过加密,且不可见。
哈希(hash)
Windows 本身不保存明文密码,只保留密码的 Hash。为了保证存储的不是明文,从而采用 Hash,但是密码 Hash 也需要特定的生成算法以及表现形式。
Hash 就是使用一种加密函数进行计算后的结果。这个加密函数对一个任意长度的字符串数据进行一次数学加密函数运算,然后返回一个固定长度的字符串。现在已经有了更新的 NTLMv2 以及 Kerberos 验证体系。Windows 加密过的密码口令,我们称之为 hash,Windows 的系统密码 hash 默认情况下一般由两部分组成:第一部分是 LM-hash,第二部分是 NTLM-hash。
LM-Hash
LAN Manager(LM)哈希是 Windows 系统所用的第一种密码哈希算法,是一种较古老的 Hash,在 LAN Manager 协议中使用,非常容易通过暴力破解获取明文凭据。它只有唯一一个版本且一直用到了 NT LAN Manager(NTLM)哈希的出现,在 Windows Vista/Windows 7/Windows Server 2008 以及后面的系统中,LM 哈希算法是默认关闭的,LM 算法是在 DES 基础上实现的,不区分字母大小写,由 IBM 设计。
生成原理
- 用户的密码转换为大写,密码转换为16进制字符串,不足14字节将会用0来再后面补全。
- 密码的16进制字符串被分成两个 7byte 部分。每部分转换成比特流,并且长度位 56bit,长度不足用0在左边补齐长度
- 再分 7bit 为一组,每组末尾加 0,再组成一组
- 上步骤得到的二组,分别作为 key 为
KGS!@#$%
进行 DES 加密。 - 将加密后的两组拼接在一起,得到最终 LM HASH 值。
风险
LM 加密算法存在一些固有的漏洞
- 首先,密码长度最大只能为14个字符
- 密码不区分大小写。在生成哈希值之前,所有密码都将转换为大写
- 查看我们的加密过程,就可以看到使用的是分组的 DES,如果密码强度是小于 7 位,那么第二个分组加密后的结果肯定是 aad3b435b51404ee,同理,如果我们看到 lm hash 的结尾是 aad3b435b51404ee,就可以判断密码强度少于7位
- 一个14个字符的密码分成7 + 7个字符,并且分别为这两个半部分计算哈希值。这种计算哈希值的方式使破解难度成倍增加,因为攻击者需要将7个字符(而不是14个字符)强制暴力破解。这使得14个字符的密码的有效强度等于,或者是7个字符的密码的两倍,该密码的复杂度明显低于 9514 14个字符的密码的理论强度。
- Des 密码强度不高
NTLM-Hash
NTLM Hash
为了解决 LM 加密和身份验证方案中固有的安全弱点,Microsoft 于 1993 年在 Windows NT 3.1 中引入了 NTLM 协议。
NT LAN Manager(NTLM)哈希是 Windows 系统认可的另一种算法,用于替代古老的 LM-Hash,一般指 Windows 系统下 Security Account Manager(SAM)中保存的用户密码 hash,在 Windows Vista/Windows 7/Windows Server 2008 以及后面的系统中,NTLM 哈希算法是默认启用的。
下面是各个版本对 LM 和 NTLM 的支持。
2000 | XP | 2003 | Vista | Win7 | 2008 | Win8 | 2012 | |
---|---|---|---|---|---|---|---|---|
LM | ✔ | ✔ | ✔ | |||||
NTLM | ✔ | ✔ | ✔ | ✔ | ✔ |
✔ | 系统默认使用的加密方式 |
---|---|
当密码超过14位时使用的加密方式 |
当用户登录时,将用户输入的明文密码加密成 NTLM Hash
,与 SAM
数据库文件中的 NTLM Hash
进行比较。
在渗透测试中,通常可从 Windows 系统中的 SAM
文件和域控的 NTDS.dit
文件中获得所有用户的 hash,通过 Mimikatz 读取 lsass.exe
进程能获得已登录用户的 NTLM hash
。
生成原理
- 先将用户密码转换为十六进制格式。
- 将十六进制格式的密码进行 Unicode 编码。
- 使用 MD4 摘要算法对 Unicode 编码数据进行 Hash 计算
快速生成
python2 -c 'import hashlib,binascii; print binascii.hexlify(hashlib.new("md4", "P@ssw0rd".encode("utf-16le")).digest())'
NTLM Hash 与 NTLM 的关系
在 Windows 中,密码 Hash 目前称之为 NTLM Hash,其中 NTLM 全称是:“NT LAN Manager”。
而 NTLM 是一种网络认证协议,与 NTLM Hash 的关系就是:NTLM 网络认证协议是以 NTLM Hash 作为根本凭证进行认证的协议。也就是说,NTLM 与 NTLM Hash 相互对应。
在本地认证的过程中,其实就是将用户输入的密码转换为 NTLM Hash 与 SAM 中的 NTLM Hash 进行比较。
本地认证流程
本地登录时,用户的密码存储在 %SystemRoot%\system32\config\SAM
这个文件里。当用户输入密码进行本地认证的过程中,所有的操作都是在本地进行的。他其实就是将用户输入的密码转换为 NTLM Hash,然后与 SAM 中的 NTLM Hash 进行比较。当用户注销、重启、锁屏后,操作系统会让 winlogon 显示登录界面,也就是输入框。当 winlogon.exe 接收输入后,将密码交给 lsass 进程,这个进程中会存一份明文密码,将明文密码加密成 NTLM Hash,对 SAM 数据库比较认证。
- Windows Logon Process(即 winlogon.exe),是Windows NT 用户登录程序,用于管理用户登录和退出。
- LSASS 用于微软 Windows 系统的安全机制。用于本地安全和登录策略。
参考如下
winlogon.exe -> 接收用户输入 -> lsass.exe -> 认证
-
当刚开机、注销等操作后,winlogon.exe 进程会显示一个登录界面要求输入用户名和密码。
-
输入用户名和密码后,会被 winlogon.exe 获取,然后将其发送给 lsass.exe 进程。
-
lsass.exe 将明文密码计算得到 NT Hash(不考虑LM)。
-
之后会将用户名和密码计算得到的 NT Hash 拿到 SAM 数据库去查找比对。
DPAPI
从 Windows 2000 开始,Microsoft 随操作系统一起提供了一种特殊的数据保护接口,称为 Data Protection Application Programming Interface(DPAPI)。其分别提供了加密函数 CryptProtectData 与解密函数 CryptUnprotectData 以用作敏感信息的加密解密。
主要用于保护加密的数据,常见的应用如:
- EFS文件加密
- 存储无线连接密码
- Windows Credential Manager
- Internet Explorer
- Outlook
- Skype
- Windows CardSpace
- Windows Vault
- Google Chrome
Master Key
64 字节,用于解密 DPAPI blob,使用用户登录密码、SID 和 16 字节随机数加密后保存在 Master Key file 中
Master Key file
二进制文件,可使用用户登录密码对其解密,获得 Master Key
分为两种:
- 用户 Master Key file,位于 %APPDATA%\Microsoft\Protect%SID%
- 系统 Master Key file,位于 %WINDIR%\System32\Microsoft\Protect\S-1-5-18\User
存放密钥的文件则被称之为 Master Key Files,其路径一般为 %APPDATA%/Microsoft/Protect/%SID%
。而这个文件中的密钥实际上是随机 64 位字节码经过用户密码等信息的加密后的密文,所以只需要有用户的明文密码 / Ntlm/Sha1 就可以还原了。
Preferred 文件
位于 Master Key file 的同级目录,显示当前系统正在使用的 MasterKey 及其过期时间,默认 90 天有效期
为了安全考虑,Master Key 是每 90 天就会更新一次,而 Preferred 文件中记录了目前使用的是哪一个 Master Key 文件以及其过期时间,这里这个文件并没有经过任何加密
格式如下:
typedef struct _tagPreferredMasterKey
{
GUID guidMasterKey;
FILETIME ftCreated;
} PREFERREDMASTERKEY, *PPREFERREDMASTERKEY;
例如
前16字节 E3 A5 DD 1F E8 E7 24 4D 93 37 FC C7 71 F1 E1 84 对应 guid,调整格式后,对应文件为
1FDDA5E3-E7E8-4D24-9337-FCC771F1E184
后8字节 A0 59 47 CD 9A 23 D7 01 对应过期时间
使用 3gstudent 文章中分享的解析方法如下:
#include
int main(void)
{
FILE *fp;
unsigned char buf[24];
fopen_s(&fp,"Preferred","rb");
fread(buf,1,24,fp);
printf("Data: ");
for(int i=0;i<24;i++)
{
printf("%02x",buf[i]);
}
fclose(fp);
printf("\nguidMasterKey: %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",buf[3],buf[2],buf[1],buf[0],buf[5],buf[4],buf[7],buf[6],buf[8],buf[9],buf[10],buf[11],buf[12],buf[13],buf[14],buf[15]);
char lowDateTime[9],highDateTime[9];
sprintf_s(lowDateTime,9,"%02X%02X%02X%02X",buf[19],buf[18],buf[17],buf[16]);
sprintf_s(highDateTime,9,"%02X%02X%02X%02X",buf[23],buf[22],buf[21],buf[20]);
printf("dwLowDateTime:%s\n",lowDateTime);
printf("dwHighDateTime:%s\n",highDateTime);
FILETIME ftUTC;
SYSTEMTIME stUTC2;
sscanf_s(lowDateTime,"%x",&ftUTC.dwLowDateTime);
sscanf_s(highDateTime,"%x",&ftUTC.dwHighDateTime);
FileTimeToSystemTime(&ftUTC, &stUTC2);
printf("");
printf("Expiry time: %d-%d-%d %d:%d:%d\n", stUTC2.wYear, stUTC2.wMonth, stUTC2.wDay, stUTC2.wHour, stUTC2.wMinute, stUTC2.wSecond);
return 0;
}
CREDHIST
此外,在 %APPDATA%/Microsoft/Protect/
目录下还有一个 CREDHIST 文件。由于 Master Key 的还原与用户密码相关,所以需要保存用户的历史密码信息以确保接口的正常使用,而此文件中就保存了用户的历史密码(Ntlm hash/sha1 hash)。
网络认证
在内网渗透中,经常遇到工作组环境,而工作组环境是一个逻辑上的网络环境(工作区),隶属于工作组的机器之间无法互相建立一个完美的信任机制,只能点对点,是比较落后的认证方式,没有信托机构。
假设 A 主机与 B 主机属于同一个工作组环境,A 想访问 B 主机上的资料,需要将一个存在于 B 主机上的账户凭证发送至 B 主机,经过认证才能够访问 B 主机上的资源。
这是我们接触比较多的 SMB 共享文件的案例,SMB 的默认端口是 445。
早期 SMB 协议在网络上传输明文口令。后来出现 LAN Manager Challenge/Response 验证机制,简称 LM,它很容易被破解,就又有了 NTLM 以及 Kerberos。
LM
LM 与 NTLM 协议的认证机制相同,但是加密算法不同。
目前大多数的 Windows 都采用 NTLM 协议认证,LM 协议已经基本淘汰了。
NTLM
认证的应用
在域环境下,可以使用 Kerberos 或者 NTLM 认证来实现对用户的身份认证。在很多企业的内部网络中(基本都是域环境),都是使用 Kerberos认证或 NTLM 认证,在 Windows 2000 以后,在域环境下,Kerberos 是默认的认证方式。因为由于 NTLM 认证存在安全风险,所以用 Kerberos 认证的较多。Kerberos 较之 NTLM 更高效、更安全,同时认证过程也相对复杂。在非域环境下,一般都是使用 NTLM 进行认证。SMB 服务和很多 Web 程序都是使用 NTLM 来实现对用户的身份认证。
NTLM 并没有定义它所依赖的传输层协议。NTLM 消息的传输完全依赖于使用 NTLM 的上层协议来决定。所以说 NTLM 是一个嵌入式协议。
如果你自己写一个利用 NTLM SSP 的程序,那么在拿到 NTLM 消息后,你可以以任何你喜欢的方式将这些消息发送至服务端。比如通过 HTTP,TCP,或者任何其他类型的 7 层协议,或者你自己定义的协议。
什么是 NTLM
NTLM 是一种网络认证协议,以 NTLM Hash 作为凭证进行认证。NTLM Hash 长度为32位,由数字和字母组成,采用挑战/响应(Challenge/Response)的消息交换模式,
这个协议只支持 Windows.
NTLM 协议的认证过程分为三步:
- 协商 : 主要用于确认双方协议版本
- 质询 : 就是挑战(Challenge)/响应(Response)认证机制起作用的范畴
- 验证 : 验证主要是在质询完成后,验证结果,是认证的最后一步。
Challenge/Response
-
客户端需要访问服务器的某个服务(前提是他得知道服务器的用户名和密码),所以得进行身份认证。于是,客户端输入服务器的用户名和密码进行验证,客户端会缓存服务器密码的 NTLM-Hash 值。客户端发送 TYPE 1 Negotiate 协商消息去协商需要认证的主体,用户(服务器端的用户名),机器以及需要使用的安全服务等等信息。
-
服务端接收到客户端发送过来的 TYPE 1 消息,会读取其中的内容,并从中选择出自己所能接受的服务内容,加密等级,安全服务等等。然后传入 NTLM SSP,得到 NTLM_CHALLENGE 消息(被称为 TYPE 2 消息,Challenge 挑战消息),并将此 TYPE 2 消息发回给客户端。此TYPE 2消息中包含了一个由服务端生成的 16 位随机值,此随机值被称为 Challenge,服务器将该 Challenge 保存起来。
-
客户端收到服务端返回的 TYPE 2 消息, 读取出服务端所支持的内容,并取出其中的随机值 Challenge,用缓存的服务器端密码的哈希值 NTLM-Hash 对其进行加密,得到 Net NTLM-Hash(加密后的 Challenge),并且将 Net NTLM-Hash 封装到 NTLM_AUTH 消息中(被称为 TYPE 3 消息, Authenticate 认证消息),发往服务端。
-
服务器在收到 Type3 的消息之后,用自己的密码的 NTLM-Hash 对 Challenge 进行加密,并比较自己计算出的 Net NTLM-Hash 认证消息和客户端发送的认证消息是否匹配。如果匹配,则证明客户端掌握了正确的密码,认证成功,否则认证失败。
详细过程
-
type 1 协商
这个过程是客户端向服务器发送 type 1(协商)消息,它主要包含客户端支持和服务器请求的功能列表。
主要包含以下结构
-
type 2 质询
这个过程是服务器用 type 2 消息(质询)进行响应,这包含服务器支持和同意的功能列表。但是,最重要的是,它包含服务器产生的 Challenge。
主要包含以下结构
其中最主要的信息是 challenge。后面加密验证依赖于 challenge
-
type 3 身份验证
这个过程客户端接收到 challenge 之后,使用用户 hash 与 challenge 进行加密运算得到 response,将 response,username,challenge 发给服务器。消息中的 response 是最关键的部分,因为它向服务器证明客户端用户已经知道帐户密码。
主要包含以下结构
这里的 Challeng 不同于 type2 的 Challenge,这里的 Challenge 是一个随机的客户端 nonce。
MIC 是校验和,设计 MIC 主要是为了防止这个包中途被修改
sessionkey 是在要求进行签名的时候用的,用来进行协商加密密钥,可能有些文章会说 sessionkey 就是加密密钥,需要拥有用户 hash 才能计算出来,因此攻击者算不出来,就无法加解密包。但是想想就不可能,这个 session_key 已经在流量里面明文传输,那攻击者拿到之后不就可以直接加解密包了。
注意
- Chanllenge 是 Server 产生的一个 16 字节的随机数,每次认证都不同
- Response 的表现形式是 Net-NTLM Hash,它是由客户端提供的密码 Hash 加密 Server 返回的 Chanllenge 产生的结果。
NTLMv2
NTLMv1 和 NTLMv2 的加密因素都是 NTLM Hash,而最显著的区别就是 Challenge 和加密算法不同,共同点就是加密的原料都是 NTLM Hash。
- Challage: NTLMv1 的 Challenge 有 8 位,NTLMv2 的 Challenge 为 16 位。
- Net-NTLM Hash:NTLMv1 的主要加密算法是 DES,NTLMv2 的主要加密算法是 HMAC-MD5。
设置系统使用 LM 还是 NTLM 还是 NTLMv2,需要修改 Local Security Policy 中的 LmCompatibilityLevel 选项
- 发送 LM NTLM 响应: 客户端使用 LM 和 NTLM 身份验证,而决不会使用 NTLMv2 会话安全;域控制器接受 LM、NTLM 和 NTLMv2 身份验证。
- 发送 LM & NTLM - 如果协商一致,则使用 NTLMv2 会话安全: 客户端使用 LM 和 NTLM 身份验证,并且在服务器支持时使用 NTLMv2 会话安全;域控制器接受 LM、NTLM 和 NTLMv2 身份验证。
- 仅发送 NTLM 响应: 客户端仅使用 NTLM 身份验证,并且在服务器支持时使用 NTLMv2 会话安全;域控制器接受 LM、NTLM 和 NTLMv2 身份验证。
- 仅发送 NTLMv2 响应: 客户端仅使用 NTLMv2 身份验证,并且在服务器支持时使用 NTLMv2 会话安全;域控制器接受 LM、NTLM 和 NTLMv2 身份验证。
- 仅发送 NTLMv2 响应\拒绝 LM: 客户端仅使用 NTLMv2 身份验证,并且在服务器支持时使用 NTLMv2 会话安全;域控制器拒绝 LM (仅接受 NTLM 和 NTLMv2 身份验证)。
- 仅发送 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 响应
Net-NTLM hash
在 type3 中的响应,有六种类型的响应
- LM(LAN Manager)响应 - 由大多数较早的客户端发送,这是“原始”响应类型。
- NTLM v1 响应 - 这是由基于 NT 的客户端发送的,包括 Windows 2000 和 XP。
- NTLMv2 响应 - 在 Windows NT Service Pack 4 中引入的一种较新的响应类型。它替换启用了 NTLM 版本 2 的系统上的 NTLM 响应。
- LMv2 响应 - 替代 NTLM 版本 2 系统上的 LM 响应。
- NTLM2 会话响应 - 用于在没有 NTLMv2 身份验证的情况下协商 NTLM2 会话安全性时,此方案会更改 LM NTLM 响应的语义。
- 匿名响应 - 当匿名上下文正在建立时使用; 没有提供实际的证书,也没有真正的身份验证。“存 根”字段显示在类型 3 消息中。
这六种使用的加密流程一样,都是 Challenge/Response 验证机制,区别在 Challenge 和加密算法不同。
在以上流程中,登录用户的密码 hash 即 NTLM hash,其中,经过 NTLM Hash 加密 Challenge 的结果在网络协议中称之为 Net NTLM Hash,response 中包含 Net-NTLM hash.
在 NTLM 认证中,NTLM 响应分为 NTLM v1,NTLMv2,NTLM session v2 三种协议,不同协议使用不同格式的 Challenge 和加密算法.所以也就存在不同协议的 Net-NTLM hash,即 Net-NTLM v1 hash,Net-NTLM v2 hash
Net-NTLM v1 hash
v1 是将 16字节的 NTLM hash 空填充为 21 个字节,然后分成三组,每组7比特,作为 3DES 加密算法的三组密钥,加密 Server 发来的 Challenge。 将这三个密文值连接起来得到 response。
回顾一下流程
- 客户端向服务器发送一个请求
- 服务器接收到请求后,生成一个 8 位的 Challenge,发送回客户端
- 客户端接收到 Challenge 后,使用登录用户的密码 hash 对 Challenge 加密,作为 response 发送给服务器
- 服务器校验 response
Net-NTLM v2 hash
v2 将 Unicode 后的大写用户名与 Unicode 后的身份验证目标(在 Type 3 消息的”TargetName”字段中指定的域或服务器名称)拼在一起。请注意,用户名将转换为大写,而身份验证目标区分大小写,并且必须与“TargetName”字段中显示的大小写匹配。使用 16 字节 NTLM 哈希作为密钥,得到一个值。
回顾一下流程
- 客户端向服务器发送一个请求
- 服务器接收到请求后,生成一个 16 位的 Challenge,发送回客户端
- 客户端接收到 Challenge 后,使用登录用户的密码 hash 对 Challenge 加密,作为 response 发送给服务器
- 服务器校验 response
使用 16 字节 NTLMv2 哈希作为密钥,将 HMAC-MD5 消息认证代码算法加密一个值(来自 type 2 的 Challenge 与 Blob 拼接在一起)。得到一个 16 字节的 NTProofStr。
将 NTProofStr 与 Blob 拼接起来形成得到 response。至于选择哪个版本的响应由 LmCompatibilityLevel 决定。
Challenge/Response 验证机制里面 type3 response 里面包含 Net-ntlm hash,NTLM v1 响应和 NTLMv2 响应对应的就是 Net-ntlm hash 分为 Net-ntlm hash v1 和 Net-ntlm hash v2。
Net-ntlm hash v1 的格式为:
username::hostname:LM response:NTLM response:challenge
Net-ntlm hash v2 的格式为:
username::domain:challenge:HMAC-MD5:blob
下面演示从 response 里面提取 NTLMv2
这里的 challenge 是 type2 服务器返回的 challenge 不是 type3 流量包里面的 client Challenge
就是 18f77b6fe9f8d876
HMAC-MD5 对应数据包中的 NTProofSt : 0ecfccd87d3bdb81713dc8c07e6705b6
blob 就是 response 减去 NTProofStr。(因为在计算 response 的时候,response 就是由 NTProofStr 加上 blob)
- username(要访问服务器的用户名):Administrator
- domain(访问者主机名或者 ip):DESKTOP-QKM4NK7
- challenge(数据包 2 中服务器返回的 challenge 值):18f77b6fe9f8d876
- HMAC-MD5(数据包 3 中的 NTProofStr): 0ecfccd87d3bdb81713dc8c07e6705b6
- blob(blob 对应数据为 NTLMv2 Response 开头去掉 NTProofStr 的后半部分):01010000000000002a470d3bc233d6017eb1f527b5e7bd4d0000000002001e00570049004e002d0041003500470050004400430050004a0037004f00540001001e00570049004e002d0041003500470050004400430050004a0037004f00540004001e00570049004e002d0041003500470050004400430050004a0037004f00540003001e00570049004e002d0041003500470050004400430050004a0037004f005400070008002a470d3bc233d601060004000200000008003000300000000000000001000000002000003737fbe7dbcbd2c8e5d7a030f44586c91423d9c5202f827f3f6cf26f69adbfe80a001000000000000000000000000000000000000900280063006900660073002f003100390032002e003100360038002e003100340031002e003100330039000000000000000000
所以最后,Net-NTLM v2 Hash 值为:
Administrator::DESKTOP-QKM4NK7:18f77b6fe9f8d876:0ecfccd87d3bdb81713dc8c07e6705b6:01010000000000002a470d3bc233d6017eb1f527b5e7bd4d0000000002001e00570049004e002d0041003500470050004400430050004a0037004f00540001001e00570049004e002d0041003500470050004400430050004a0037004f00540004001e00570049004e002d0041003500470050004400430050004a0037004f00540003001e00570049004e002d0041003500470050004400430050004a0037004f005400070008002a470d3bc233d601060004000200000008003000300000000000000001000000002000003737fbe7dbcbd2c8e5d7a030f44586c91423d9c5202f827f3f6cf26f69adbfe80a001000000000000000000000000000000000000900280063006900660073002f003100390032002e003100360038002e003100340031002e003100330039000000000000000000
上面的 Net-NTLM v2 Hash 值若使用 hashcat 爆破应为 Abcd1234
抓包过程见 Wireshark笔记 案例中 NTLMv2 部分
域环境中NTLM认证方式
-
用户通过输入 Windows 帐号和密码登录客户端主机,客户端会缓存密码的哈希值 NTLM-Hash。成功登录客户端的用户如果试图访问服务器资源,需要向对方发送一个请求,该请求利用 NTLM SSP 生成 NTLM_NEGOTIATE 消息 (被称为 TYPE 1 消息,Negotiate 协商消息),并将 TYPE 1 消息发送给服务端中,该 TYPE 1 消息中包含一个以明文表示的用户名以及其他的一些协商信息(认证的主体,机器以及需要使用的安全服务等等信息)
-
服务端接收到客户端发送过来的 TYPE 1 消息,会读取其中的内容,并从中选择出自己所能接受的服务内容,加密等级,安全服务等等。然后传入 NTLM SSP,得到 NTLM_CHALLENGE 消息(被称为 TYPE 2 消息,Challenge 挑战消息),并将此 TYPE 2 消息发回给客户端。此 TYPE 2 消息中包含了一个由服务端生成的16位随机值,此随机值被称为 Challenge,服务器将该 Challenge 保存起来。
-
客户端收到服务端返回的 TYPE 2 消息, 读取出服务端所支持的内容,并取出其中的随机值 Challenge,用缓存的密码的哈希值 NTLM-Hash 对其进行加密,得到 Net NTLM-Hash(加密后的 Challenge),并且将 Net NTLM-Hash 封装到 NTLM_AUTH 消息中(被称为 TYPE 3 消息, Authenticate认证消息),发往服务端。
-
服务器接收到客户端发送来的 NTLM_AUTH 的 TYPE 3 消息后,取出其中的 Net NTLM-Hash 值,并向 DC 域控(Domain Control)发送针对客户端的验证请求。该请求主要包含以下三方面的内容:客户端用户名、原始的 Challenge 和 加密后的 Challenge(也就是 Net NTLM-Hash)。
-
DC 根据用户名获取该帐号的密码哈希值 NTLM-Hash,用密码哈希值 NTLM-Hash 对原始的 Challenge 进行加密得到 Net NTLM-Hash。如果加密后的 Challenge 和服务器发送的一致,则意味着用户拥有正确的密码,验证通过,否则验证失败。DC 将验证结果发给服务器。
-
服务器根据 DC 返回的结果,对客户端进行回复。
抓包过程见 Wireshark笔记 案例中 域环境中NTLM认证方式 部分
SSP & SSPI
SSPI(Security Support Provider Interface)
这是 Windows 定义的一套接口,此接口定义了与安全有关的功能函数,用来获得验证、信息完整性、信息隐私等安全功能,就是定义了与安全有关的功能函数,包括但不限于:
- 身份验证机制
- 为其他协议提供的 Session security 机制
SSP(Security Support Provider)
SSPI 的实现者,对 SSPI 相关功能函数的具体实现。微软自己实现了如下的 SSP,用于提供安全功能:
- NTLM SSP
- Kerberos
- Cred SSP
- Digest SSP
- Negotiate SSP
- Schannel SSP
- Negotiate Extensions SSP
- PKU2U SSP
在系统层面,SSP 就是一个 dll,来实现身份验证等安全功能.不同的 SSP,实现的身份验证机制是不一样的。
比如 NTLM SSP 实现的就是一种 Challenge/Response 验证机制。
而 Kerberos 实现的就是基于 ticket 的身份验证机制。
我们可以编写自己的 SSP,然后注册到操作系统中,让操作系统支持更多的自定义的身份验证方法。
SSPI 接口提供了多种功能,包括 AcquireCredentialsHandle,InitializeSecurityContext 和 AcceptSecurityContext。
在 NTLM 身份验证期间,客户端和服务器都将使用这些功能。简要描述步骤如下:
- 客户端调用
AcquireCredentialsHandle
,以获得对用户凭证的间接访问。 - 然后客户端调用
InitializeSecurityContext
,这个函数在第一次调用时,会创建一个 type 1 消息,因此类型为 NEGOTIATE。 - 服务器在收到消息时,会调用
AcceptSecurityContext
函数。这个函数将创建 type 2 消息,即 CHALLENGE。 - 当收到这个消息时,客户端将再次调用
InitializeSecurityContext
,但这次将 CHALLENGE 作为参数传递。NTLMSSP 包负责一切,通过加密 challenge 计算 response ,并将产生最后的 AUTHENTICATE 消息。 - 在收到最后这条消息后,服务器也会再次调用
AcceptSecurityContext
,认证验证将自动进行。
之所以解释这些步骤,是为了说明在现实中,从客户端或服务器的角度来看,交换的3条消息的结构并不重要。我们凭借对NTLM协议的了解,知道这些消息对应的是什么,但客户端和服务器都不关心。这些消息在微软文档中被描述为不透明的令牌。
这意味着这5个步骤完全独立于客户端的类型或服务器的类型。只要协议中有适当的位置,以允许从客户端到服务器以一种或另一种方式交换这种不透明的结构,它们就可以工作,而不管使用什么协议。
我们抓包分析 ntlm 的时候,就会看到 ntlm 是放在 GSS-API 里面
为啥这里会出现 GSSAPI 呢,SSPI 是 GSSAPI 的一个专有变体,进行了扩展并具有许多特定于 Windows 的数据类型。
SSPI 生成和接受的令牌大多与 GSS-API 兼容。所以这里出现 GSSAPI 只是为了兼容,我们可以不必理会。
可以直接从 NTLM SSP 开始看起。注册为 SSP 的一个好处就是,SSP 实现了了与安全有关的功能函数,那上层协议(比如 SMB)在进行身份认证等功能的时候,就可以不用考虑协议细节,只需要调用相关的函数即可。
而认证过程中的流量嵌入在上层协议里面。不像 kerbreos,既可以镶嵌在上层协议里面,也可以作为独立的应用层协议。ntlm 是只能镶嵌在上层协议里面,消息的传输依赖于使用 ntlm 的上层协议。比如镶嵌在 SMB 协议里,或镶嵌在 HTTP 协议。
Integration with HTTP (MS-NTHT)(NTLM over HTTP)
以 HTTP 为例
GET /index.html HTTP/1.1
Host: www.test.com
User-Agent: Mozilla/5.0
Accept: text/html
在这个例子中,必须的元素是HTTP行为(GET)、请求页面的路径(/index.html)、协议版本(HTTP/1.1)或Host头(Host: www.test.com)。
除此之外,添加其他的http报文也是可以的
正是利用这一特性,才能够将 NTLM 消息从客户端传输到服务器。客户端在一个名为 Authorization 的头中发送消息,服务器在一个名为 WWW-Authenticate 的头中发送消息。如果客户端试图访问一个需要认证的网站,服务器将通过添加 WWW-Authenticate 头来响应,并突出显示它支持的不同认证机制。对于 NTLM,它将简单地说 NTLM。
客户端知道需要 NTLM 认证,将发送授权头中的第一条消息,用 base64 编码,因为该消息不仅包含可打印字符。服务器将在 WWW-Authenticate 头中回应一个挑战,客户端将计算响应,并在授权头中发送。如果认证成功,服务器通常会返回一个 200 的返回码,表示一切顺利。
> GET /index.html HTTP/1.1
> Host: www.test.com
> User-Agent: Mozilla/5.0
> Accept: text/html
< HTTP/1.1 401 Unauthorized
< WWW-Authenticate: NTLM
< Content type: text/html
< Content-Length: 0
> GET /index.html HTTP/1.1
> Host: www.test.com
> User-Agent: Mozilla/5.0
> Accept: text/html
> Authorization: NTLM
< HTTP/1.1 401 Unauthorized
=> WWW-Authenticate: NTLM
< Content type: text/html
< Content-Length: 0
> GET /index.html HTTP/1.1
> Host: www.test.com
> User-Agent: Mozilla/5.0
> Accept: text/html
> Authorization: NTLM
< HTTP/1,200 OKAY.
< WWW-Authenticate: NTLM
< Content type: text/html
< Content-Length: 0
< Connection: close
只要 TCP 会话是开放的,认证就会有效。然而,一旦会话关闭,服务器将不再拥有客户端的安全内容,就必须进行新的认证。这种情况经常会发生,由于微软的 SSO(单点登录)机制,这对用户来说往往是透明的。
更多内容: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-ntht/f09cf6e1-529e-403b-a8a5-7368ee096a6a
Integration with SMB (NTLM Over Server Message Block)
它是SMB协议,用于访问网络共享,SMB协议的工作原理是使用命令。例如,有 SMB_COM_OPEN
、SMB_COM_CLOSE
或 SMB_COM_READ
,这些命令用于打开、关闭或读取文件。
SMB 还具有专用于配置 SMB 会话的命令,该命令为 SMB_COM_SESSION_SETUP_ANDX
。此命令中的两个字段专用于 NTLM 消息的内容。
- LM/LMv2 Authentication: OEMPassword
- NTLM/NTLMv2 authentication: UnicodePassword
从 SMB 数据包的示例可以看到,其中包含服务器对身份验证的响应
- https://wiki.wireshark.org/SampleCaptures?action=AttachFile&do=get&target=smbtorture.cap.gz
以上 2 个案例表明 NTLM 消息的内容与协议无关。它可以包含在任何支持它的协议中
更多内容: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/c083583f-1a8f-4afe-a742-6ee08ffeb8cf
Signing
Windows 下的 SSP 除了提供身份认证功能以外,还提供会话安全功能。
比如 Client 与 Server 建立了一个 Socket 连接后,可以使用 SSP 与 Server 进行身份认证,身份认证完以后,Client 与 Server 还可以利用 SSP 提供的会话安全功能为后续的数据包进行签名与加密,以防止数据包被中间人篡改、窃听。
SSP 提供的会话安全功能,是基于 session key 的。在 Client 与 Server 端进行了身份认证以后,Client 与 Server 端都能够同时得到一个用于会话安全功能的 session key。攻击者要想知道这个 session key,就必须要知道 Client 的原始密码,而对于 Credential Relay 的攻击场景,攻击者只是站在一个中间人的位置对 Credential 进行转发,是不可能知道客户端的原始密码的
攻击者在攻击一个开启了 Signing/Encryption 的服务器的时候,当认证完毕之后,使用一个客户端和服务端都知道的 session key 对后续所有的操作进行加密,攻击者由于没有 session key,也没法对内容进行加密解密,所以也就没办法进行 Relay, 最多只能将流量原封不动转发过去。
这个 key 是 sessionkey,需要使用用户 hash 去生成,攻击者没有用户 hash,所以没有 sessionkey, 也就是没办法加解密,这个时候签名也就起到了防御 Relay 的效果。
一般情况下,域控会默认开启,而 Windows 单机默认都不会开, 因为用于域控制器的 GPO 包含以下条目:
关闭签名验证的命令: Windows Server 系列中 RequireSecuritySignature 子键默认值为 1
reg add HKLM\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters /v RequireSecuritySignature /t REG_DWORD /d 0 /f
关于 SMB 签名的更多信息请参考官方文档 : https://docs.microsoft.com/zh-cn/archive/blogs/josebda/the-basics-of-smb-signing-covering-both-smb1-and-smb2
LDAP 签名
对于 LDAP,还有三个级别:
- 禁用:这意味着不支持数据包签名。
- 协商签名:此选项表示计算机可以处理签名,并且如果与之通信的计算机也可以处理签名,则将对其进行签名。
- 必需:这最终表明不仅支持签名,而且必须对数据包进行签名才能使会话继续。
如您所见,中间级别的协商签名不同于 SMBv2 的情况,因为这一次,如果客户端和服务器能够对数据包进行签名,则它们将。而对于 SMBv2,只有在至少需要一个实体的情况下才对数据包进行签名。
与 SMB 的区别在于,在 Active Directory 域中,所有主机都具有 “Negotiated Signing” 设置。域控制器不需要签名。
对于域控制器, ldapserverintegrity
注册表项位于 HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\NTDS\Parameters
配置单元中,根据级别可以为 0、1 或 2。默认情况下,它在域控制器上设置为 1。
对于客户端,此注册表项位于 HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\ldap
对于客户端,它也设置为 1。由于所有客户端和域控制器都具有协商签名功能,因此默认情况下将对所有 LDAP 数据包进行签名。
与 SMB 不同,LDAP 中没有标志来指示是否对数据包进行签名。而是,LDAP 使用在 NTLM 协商中设置的标志。无需更多信息。在客户端和服务器均支持 LDAP 签名的情况下, NEGOTIATE_SIGN
将设置该标志并对数据包进行签名。
如果一方要求签名,而另一方不支持该签名,则该会话将根本不会开始。需要签名的一方将忽略未签名的数据包。
因此,现在我们了解到,与 SMB 相反,如果我们位于客户端和服务器之间,并且希望使用 LDAP 将身份验证中继到服务器,则需要两件事:
- 该服务器不能要求数据包签名,这是默认情况下,所有机器的情况下,
- 该客户端必须不设置 NEGOTIATE_SIGN 标志 1。如果他这样做,那么服务器将期望签名,并且由于我们不知道客户端的秘密,因此我们将无法对我们精心制作的 LDAP 数据包进行签名。
关于要求 2,有时客户端没有设置此标志,但是不幸的是,Windows SMB 客户端设置了该标志!默认情况下,不可能将 SMB 身份验证中继到 LDAP。
那么,为什么不只更改 NEGOTIATE_FLAG 标志并将其设置为 0 呢?这是因为 NTLM 消息中有 MIC
Negotiation
实际上,在 NTLM 消息中,除了质询和响应之外,还有其他信息可以交换。也有协商标志或协商标志。这些标志指示发送实体支持的内容。
此协商允许知道客户端和/服务器是否支持签名,并且在 NTLM 交换期间完成。
当客户端将此标志设置为 1 时,表示客户端支持签名。请注意,这并不意味着他一定会在他的数据包上签名。只是他有能力。
类似地,当服务器回复时,如果它支持签名,那么该标志也将设置为 1。
因此,该协商允许客户端和服务器两方中的每一方向对方指示是否可以签名数据包。对于某些协议,即使客户端和服务器支持签名,也不一定意味着将对数据包进行签名。
MIC
MIC 是仅在 NTLM 身份验证的最后一条消息(AUTHENTICATE 消息)中发送的签名。它考虑了 3 条消息。MIC 是使用 HMAC_MD5
函数计算的,它用作取决于客户端机密的密钥,称为 session key。
HMAC_MD5(Session key, NEGOTIATE_MESSAGE + CHALLENGE_MESSAGE + AUTHENTICATE_MESSAGE)
session key 取决于客户端的机密,因此攻击者无法重新计算MIC。
如果仅修改了这3条消息之一,则MIC将不再有效,因为这3条消息的串联将是不同的。因此,不能更改 NEGOTIATE_SIGN
示例中建议的标志。
攻击者删除 MIC,该怎么办?当然可以,因为 MIC 是可选的。
但还有另一个标志指示存在 MIC,即 msAvFlags。
它也出现在 NTLM 响应中,如果它是 0x00000002,它告诉服务器必须存在 MIC 。因此,如果服务器看不到 MIC,它将知道发生了什么事,它将终止身份验证。如果标志表明必须有 MIC,则必须有 MIC。
如果我们更改或删除 msAcFlags 标志将使 NTLMv2 哈希无效
MIC 保护 3 条消息的完整性,msAvFlags 保护 MIC 的存在,而 NTLMv2 哈希保护标志的存在。攻击者不知道用户的秘密,因此无法重新计算此哈希。
EPA
Extended Protection for Authentication
攻击者很有可能从协议 A 检索 NTLM 消息,然后使用协议 B 将其发送回去。这就是我们已经提到的跨协议中继。
EPA 就是一种保护措施来应对这种攻击。这种保护的原理是将身份验证层与正在使用的协议绑定,即使存在的 TLS 层也将其绑定(例如 LDAPS 或 HTTPS)。通常的想法是,在最后一条 NTLMAUTHENTICATE 消息中,一条信息被放置在此处,并且攻击者无法对其进行修改。该信息指示所需的服务,并可能指示包含目标服务器证书的哈希值的另一信息。
TLS Binding 与 Service binding 这两个方案就是在原有的身份认证数据中加入一些其他的额外信息,这些额外的信息使得 Server 端可以免受 Relay 的攻击。
Service Binding
如果客户端希望向服务器进行身份验证以使用特定服务,则将在 NTLM 响应中添加标识该服务的信息。
这样,当合法服务器收到此身份验证时,它可以看到客户端请求的服务,并且如果它与实际请求的服务不同,则它将不同意提供该服务。
该方案会在原有 Windows SSPI 生成的 authentication token 中加入一段额外信息,这段额外的信息是目标服务的 SPN。
- 攻击者通过某种方式触发 Client 与自己认证,Client 发送给 攻击者的凭据中带有 攻击者的 SPN(因为 Client 是在访问 攻击者),并且这个 SPN 受到了完整性保护(具体的完整性保护的方式依认证协议不同而不同),使得 攻击者无法删除、修改这个 SPN。(需要知道的一点是, NTLM 中也是会涉及到 SPN 的概念的)
- 攻击者将凭据转发至 Server
- Server 收到凭据后,检查凭据中的 SPN,发现 SPN 不是自己的而是 攻击者的,说明这个凭据并不是发给自己的(而是发给 攻击者的),所以认为遇到了 Credential Relay 攻击,认证将会失败。
由于服务名称在 NTLM 响应中,因此受 NtProofStr 响应保护,该响应是此信息,质询和其他信息(例如 msAvFlags)的 HMAC_MD5。它是用客户的秘密计算的。
TLS Binding && Channel Binding
该方案会在原有 Windows SSPI 生成的 authentication token 中加入一段额外信息,这段额外的信息被称为 Channel Binding Token(CBT)。
如果客户端要使用封装在 TLS 中的协议(例如 HTTPS,例如 LDAPS),它将与服务器建立 TLS 会话,并计算服务器证书哈希。此哈希称为 “通道绑定令牌” 或 CBT。计算完成后,客户端会将此哈希放入其 NTLM 响应中。然后,合法服务器将在身份验证结束时接收 NTLM 消息,读取提供的哈希,然后将其与证书的真实哈希进行比较。如果不同,则表示他不是 NTLM 交换的原始收件人。
它可以使 Server 端有能力知道其接收到的凭据到底是不是发给自己的(也就是有能力知道收到的凭据是不是被 Relay 过来的)。如果发现凭据不是发给自己的(也就是凭据是被 Relay 过来的),则拒收,则 攻击者尝试与 Server 进行身份认证的请求将会失败。
- 攻击者通过某种方式使得 Client 与自己建立 TLS 连接,并且 Client 将 Credential(authentication token) 发送给攻击者。authentication token 中带有 CBT。 CBT 是基于 client 到 server 的这个 TLS 连接的一些属性所计算出来的。且这个 CBT 受到了完整性保护,使得攻击者无法删除、修改 CBT。具体的完整性保护的方式依认证协议的不同而不同。
- 攻击者与一台开启了 TLS Binding 机制的 Server 建立 TLS 连接,将 authentication token 转发至 Server
- Server 接收到 authentication token 后,会基于攻击者到 server 的这个 TLS 连接的一些属性计算出来一个 CBT,同时取出 攻击者转发过来的由 client 计算出来的 CBT进行对比。
- 对比将会失败,因为 client 计算出来的 CBT 是基于 client --> 攻击者这个 TLS 连接的一些属性,而 server 计算出来的 CBT是基于 攻击者--> server 这个 TLS 连接的一些属性。 通过这个对比,Server 就会知道 攻击者转发过来的 authentication token 并不是发给自己的,所以认定这个凭据是被 relay 过来的,所以 攻击者与 server 的认证将会失败 。
由于有了这种保护,因此不再可能进行以下两种攻击:
- 如果攻击者希望中继使用的协议从一个客户端的信息,而不一个 TLS 层的协议与一个 TLS 层(HTTP 到 LDAPS,例如),则攻击者将不能从目标服务器添加证书哈希进 NTLM 响应,因为它无法更新 NtProofStr。
- 如果攻击者希望将带有 TLS 的协议中继到带有 TLS 的另一个协议(HTTPS 到 LDAPS),则在客户端和攻击者之间建立 TLS 会话时,攻击者将无法提供服务器证书,因为它不匹配攻击者的身份。因此,它将必须提供 “自制” 证书,以识别攻击者。然后,客户端将对该证书进行哈希处理,并且当攻击者将 NTLM 响应中继到合法服务器时,响应中的哈希将与真实证书的哈希不同,因此服务器将拒绝身份验证。
需要注意的是,如果你的服务端程序想要受到 EPA 的保护,则要求:
- 运行服务端的操作系统必须支持 EPA(Win7 及 Win 2018 R2 后自动支持,或者可以通过安装补丁的方式来添加支持)
- 你的服务端自身需要做修改,来接入 EPA
- 连接服务端的客户端所在的操作系统要支持 EPA 并且客户端需要做相应修改来发送 CBT 或 SPN
即,EPA 是操作系统提供的一些基础框架,它并不会自动保护服务器上的所有程序,只有那些使用了 EPA 的程序才会受到保护。
有不少服务端程序虽然支持 EPA,但是考虑到兼容性问题(比如客户端不支持 EPA),所以没有强制开启 EPA,LDAPS 就是这么一个例子。微软针对 CVE-2017-8563 的修复方式就是使 LDAP Server 支持 EPA,但是却没有默认强制 LDAP Server 必须要使用 EPA。
LmCompatibilityLevel
什么时候用什么类型的 hash 呢?是由 LmCompatibilityLevel 来决定的
当服务器上有一个账号 admin 密码 123 的账户,但是你 net use \\server "123" /user:admin
却提示账号密码错误?
有可能就遇到了两边 LmCompatibilityLevel 不兼容的情况。
即,客户端发送的 hash 的类型与服务端所期待的类型不一样,服务端计算出来了与客户端不一样的 hash,导致用户名密码错误。
在 LmCompatibilityLevel 不兼容的情况下,你正常去连接的结果是验证失败,自然用 NTLM-Relay 的结果肯定也是验证失败。
LmCompatibilityLevel 的默认值,不同的操作系统,甚至不同的补丁版本,是不一样的。在多数情况下应该是兼容的。
域认证
域认证部分内容来自 [浅学Windows认证]、[彻底理解Windows认证 - 议题解读]
MSCACHE
MSCACHE 简介
你的办公笔记本加了公司的域,你一直是使用域账号登陆这台机器。你尝试登陆时所输入的账号密码将由域控来进行验证,验证通过后你就能登陆这台笔记本。 但是你是否发现过,当你的笔记本处于断网状态的时候,你依然可以用域账号来登陆这台笔记本。也就是说,当这台机器根本连不上域控的时候,你也可以使用域账号来登陆这台机器,那这个时候,是谁来负责验证你输入的域账号密码是否正确呢? 就是 MSCACHE。
Mscash 是微软的一种散列算法,用于在登录成功后将缓存的域凭证存储在系统本地。缓存的凭证不会过期。域凭证被缓存在本地系统上,这样即使 DC 宕机,域成员也可以登录机器。值得注意的是,mscash hash 是不可 PTH 的
MSCACHE 中包含的内容
- 域用户的 mscache hash,或者叫 dcc hash,根据操作系统的版本不同,又分为 dcc1 hash 与 dcc2 hash。Vista 之前保存的是 dcc1, 之后保存的是 dcc2。 两种 hash 的生成算法不一样。这段 mscache hash 主要用于对用户输入的密码进行验证
- 域用户的授权信息,比如这个域用户是属于哪个域组的
- 授权信息主要用于在验证通过后来生成 access token。
- 一些其他的信息,比如 UPN,logon server 之类的
工作原理
当机器可以连上域控的时候,你用域账号去登陆这台机器,在登陆成功后(域控验证了你的身份后),系统会将你的凭据以及授权信息保存在注册表里面。默认是保存 10 个凭据(可以对这个值进行更改)。当被保存的凭据已经超过 10 个的话,新的凭据会覆盖掉老的凭据。
凭据被缓存在注册表里的这些用户,在机器连不上域控的时候也可以登陆这台机器(只能交互式登陆,比如控制台或远程桌面。远程桌面的时候要注意,不能使用带有 NLA 功能的 RDP 客户端,要用老的比如 XP 上带的 RDP 客户端),但是没有被缓存在注册表里的用户是无法登陆的。
MSCACHE 的保存位置默认只有 SYSTEM 权限可读
HKEY_LOCAL_MACHINE\SECURITY\Cache
Kerberos
学习资料
- https://www.kerberos.org/software/tutorial.html
Kerberos 协议
Kerberos 是一种计算机网络授权协议,用来在非安全网络中,对个人通信以安全的手段进行身份认证。软件设计上采用客户端/服务器结构,并且能够进行相互认证,即客户端和服务器端均可对对方进行身份认证。可以用于防止窃听、防止重放攻击、保护数据完整性等场合,是一种应用对称密钥体制进行密钥管理的系统。支持 SSO。Kerberos 的扩展产品也使用公开密钥加密方法进行认证。
当有 N 个人使用该系统时,为确保在任意两个人之间进行秘密对话,系统至少保存有它与每个人的共享密钥,所需的最少会话密钥数为 N 个。
Kerberos 协议基于对称密码学,并需要一个值得信赖的第三方。Kerberos 协议的扩展可以为认证的某些阶段提供公钥密码学支持。
简要概括认证过程
Kerberos 认证用于域环境中,它是一种基于票据(Ticket)的认证方式。该认证过程的实现不依赖于主机操作系统的认证,无需基于主机地址的信任,不要求网络上所有主机的物理安全,并假定网络上传送的数据包可以被任意地读取、修改和插入数据。在以上情况下, Kerberos 作为一种可信任的第三方认证服务,是通过传统的密码技术(如:共享密钥)执行认证服务的。
客户端要访问服务器的资源,需要首先购买服务端认可的 ST 服务票据。也就是说,客户端在访问服务器之前需要预先买好票,等待服务验票之后才能入场。但是这张票不能直接购买,需要一张 TGT 认购权证(Ticket Granting Ticket)。也就是说,客户端在买票之前必须先获得一张 TGT 认购权证。这张 TGT 认购权证和 ST 服务票据均由 KDC 发售。
他的整个认证过程涉及到三方:客户端、服务端和 KDC(Key Distribution Center)。在 Windows 域环境中,由 DC(域控)来作为 KDC。
Kerberos 认证过程如下:
-
client 向 kerberos 服务请求,希望获取访问 server 的权限。 kerberos 得到了这个消息,首先得判断 client 是否是可信赖的,也就是白名单黑名单的说法。这就是 AS 服务完成的工作,通过在 AD 中存储黑名单和白名单来区分 client。成功后,返回 AS 返回 TGT 给 client。
-
client 得到了 TGT 后,继续向 kerberos 请求,希望获取访问 server 的权限。kerberos 又得到了这个消息,这时候通过 client 消息中的 TGT,判断出了 client 拥有了这个权限,给了 client 访问 server 的权限 ticket。
-
client 得到 ticket 后,终于可以成功访问 server。这个 ticket 只是针对这个 server,其他 server 需要向 TGS 申请。
Kerberos 认证所参与的角色
- 访问服务的 Client
- 提供服务的 Server
- KDC(Key Distribution Center,密钥分发中心) = DC(Domain Controller)
其中 KDC 服务默认安装在一个域的域控中,而 Client 和 Server 为域内的用户或者是服务,如 HTTP 服务、SQL 服务。在 Kerberos 中 Client 是否有权限访问 Server 端的服务由 KDC 发放的票据来决定
认证中涉及到的部分词汇
- Authentication Server : 为 Client 生成 TGT 的服务。 AS 的作用是验证 Client 端的身份,验证通过就会给一个 TGT 票据给 Client
- AD(Account Database) : 活动目录,存储所有 Client 白名单,只有存在于白名单的 Client 才能申请到 AS 给的 TGT,类似于本机 SAM,在 DC 上
- DC(Domain Controller) : 域控
- KDC(Key Distribution Center) : 密钥分发中心,由域控担任
- KAS(Kerberos Authentication Service) : Kerberos 认证服务
- TGT(Ticket Granting Ticket) : 入场券,通过入场券能够获得票据,是一种临时凭证的存在
- TGS(Ticket Granting Server) : 为 client 生成某个服务的 ticket。 TGS 的作用是通过 AS 发送给 Client 的 TGT 换取访问 Server 端的 ST 票据。ST 也有资料称为 TGS Ticket,为了和 TGS 区分,此处使用 ST
- ST(Ticket) : 票据,是网络对象互相访问的凭证。
- Session Key : 会话密钥,只有 Client 和 TGS 知道
- krbtgt 账户:每个域控制器都有一个 krbtgt 的用户,是 KDC 的服务账户,用来创建票据授予服务(TGS)加密的密钥。
获得认购权证
首先,我们来看看客户端如何获得 TGT 认购权证
。TGT 是 KDC 的 KAS 认证服务(Kerberos Authentication Service)发放的。
-
当某个用户通过输入域帐号和密码试图登录某台主机的时候,本机的 Kerberos 服务会向 KDC 的 KAS 认证服务发送一个认证请求。该请求主要包括两部分内容,明文形式的用户名和用用户秘钥加密原始
Authenticator
后得到的加密后Authenticator
(Authenticator 是客户端和服务端可以用于验证对方身份的一个东西)。 -
当 KDC 接收到请求之后,通过 AD 查询该用户名得到该用户的信息。通过查询得到的密码信息对
Authenticator
进行解密得到原始的Authenticator
。如果解密后的Authenticator
和已知的Authenticator
一致,则证明请求者提供的密码正确,即确定了登录者的真实身份。KAS 成功认证对方的身份之后,会先生成一个用用户密码加密后的用于确保该用户和 KDC 之间通信安全的Logon Session Key
会话秘钥。KAS 接着为该用户创建TGT 认购权证
。TGT
主要包含两方面的内容:用户相关信息和原始Logon Session Key
,而整个TGT
则通过 KDC 自己的密钥进行加密。最终,被不同密钥加密的Logon Session Key
和TGT
返回给客户端。
获得 ST 服务票据
经过上面的步骤,客户端获取了进入同域中其他主机入场券的 TGT 认购权证和 Logon Session Key,然后用自己的密钥解密 Logon Session Key 得到原始的 Logon Session Key。然后它会在本地缓存此 TGT 和原始 Logon Session Key。如果现在它需要访问某台服务器的资源,它就需要凭借这张 TGT 认购凭证向 KDC 购买相应的入场券。这里的入场券也有一个专有的名称——ST 服务票据(Service Ticket)。具体来说,ST 是通过 KDC 的另一个服务 TGS(Ticket Granting Service)出售的。
-
客户端先向 TGS 发送一个
ST 购买请求
,该请求主要包含如下的内容:客户端用户名、通过Logon Session Key
加密的Authenticator
、TGT
和访问的服务器名(其实是服务)。 -
TGS 接收到请求之后,通过自己的秘钥解密
TGT
并得到原始Logon Session Key
,然后通过Logon Session Key
解密Authenticator
,进而验证了对方的真实身份。TGS 完成对客户端的认证之后,会生成一个用Logon Session Key
加密后的用于确保客户端-服务器之间通信安全的Service Session Key
会话秘钥。然后为该客户端生成ST 服务票据
。ST 服务票据
主要包含两方面的内容:客户端用户信息和原始Service Session Key
,整个ST
通过服务器密码派生的秘钥进行加密。最终两个被加密的Service Session Key
和ST
回复给客户端。
用 ST 服务票据双向认证
-
客户端接收到 TGS 回复后,通过缓存的
Logon Session Key
解密得到原始Service Session Key
,同时它也得到了进入服务器ST 服务票据
。该Serivce Session Key
和ST 服务票据
会被客户端缓存。客户端访问某服务器资源,将ST 服务票据
和Service Session Key
加密的Authenticator
发送给服务端。 -
服务器收到客户端发来的
ST 服务票据
。但是,服务端如何确保客户端发来的ST 服务票据
是通过TGS
购买,而不是自己伪造的呢?这很好办,不要忘了 ST 是通过服务器自己密码派生的秘钥进行加密的。具体的操作过程是这样的,服务器在接收到请求之后,先通过自己密码派生的秘钥解密ST
,并从中提取Service Session Key
。然后通过提取出来的Service Session Key
解密Authenticator
,进而验证了客户端的真实身份。实际上,到目前为止,服务端已经完成了对客户端的验证,但是,整个认证过程还没有结束。谈到认证,很多人都认为只是服务器对客户端的认证,实际上在大部分场合,我们需要的是双向验证(Mutual Authentication),即访问者和被访问者互相验证对方的身份。现在服务器已经可以确保客户端是它所声称的那么用户,客户端还没有确认它所访问的不是一个钓鱼服务呢。为了解决客户端对服务器的验证,服务端需要将解密后的Authenticator
再次用Service Session Key
进行加密,并发挥给客户端。客户端再用缓存的Service Session Key
进行解密,如果和之前的内容完全一样,则可以证明自己正在访问的服务器和自己拥有相同的Service Session Key
。双向认证过后,开始了服务资源的访问。
详细概括认证过程
当 Client 想要访问 Server 上的某个服务时,需要先向 AS 证明自己的身份,然后通过 AS 发放的 TGT 向 Server 发起认证请求,这个过程分为三块:
- The Authentication Service Exchange: Client 与 AS 的交互
- AS_REQ
- AS_REP
- The Ticket-Granting Service (TGS) Exchange: Client 与 TGS 的交互
- TGS_REQ
- TGS_REP
- The Client/Server Authentication Exchange: Client 与 Server 的交互
- AP_REQ
- AP_REP
整体过程如图
-
用户登录
用户登录阶段,通常由用户(AA)输入[用户名][密码]信息,在客户端侧,用户输入的密码信息被一个单向 Hash 函数生成 Client 密钥,即 AA 的 NTLM Hash:
-
请求身份认证
-
客户端向 AS 发送请求认证
KRB-AS-REQ:Client 发送明文
用户名 AA
和Authenticator1
信息到 KDC (Key Distribution Center)。Authenticator1 的内容为使用 Client 密码哈希加密的时间戳、Client ID、网络类型、加密类型等。 -
AS 确认客户端登录者身份
KRB-AS-REP:AS 收到用户认证请求后,AS 根据请求中的
用户名 AA
信息,从数据库中查找用户名是否存在。如果用户名 AA
存在,则从 KDC 中可以获取用户 AA
的密码,使用单向函数为该密码生成一个Client 密钥
(即NTLM Hash)。AS 生成随机字符串
Client/TGS Session Key
,使用Client 密钥
(用户 AA 的密码 NTLM Hash)对Client/TGS Session Key
加密得到sessionkey_as
;再使用 TGS 密钥(krbtgt 用户的 NTLM Hash)对
Client/TGS Session Key
、Client Info
和Timestamp
加密,得到TGT
(TGT票据)。将
sessionkey_as
和TGT
一起返回给 Client。Client 收到 AS 的响应消息后,利用自身的
Client 密钥
(AA 的 NTLM Hash)对sessionkey_as
解密,这样就获取到Client/TGS Session Key
。- AS 的响应消息中有一条是属于 Client 的,有一条是 TGS 的。
- TGT 的到期时间为 8 小时,如果超过了 8 小时,还需要重新申请 TGT,不能之间进入下一步获取 Ticket。
- KDC 返回的 TGT 客户端是无法解密的,因为它没有 KDC Hash,如果有,我们就可以伪造黄金票据
-
-
请求授权访问服务
-
客户端向 TGS 发送请求服务授权请求
KRB-TGS-REQ:Client 收到
sessionkey_as
和TGT
后,使用Client 密钥
(AA 的 NTLM Hash)对sessionkey_as
解密就能得到Client/TGS Session Key
,然后使用Client/TGS Session Key
对 Client Info 和 timestamp 加密得到Authenticator2
。将
Authenticator2
、TGT
、Service ID
(要请求的服务 ID)发送给 KDC 中的 TGS。- 由于 TGT 是使用
TGS 密钥
(krbtgt 的 NTLM Hash)加密的,Client 无法对 TGT 解密。 - 如果假设这个数据被中间人窃取到,也无法在短时间内破解,因为 KDC 会校验时间戳。
- 由于 TGT 是使用
-
TGS 为 Client 响应服务授权票据
TGS-REP:TGS 收到请求后,检查 KDC 数据库中是否存在所请求的服务(
Service ID
)。如果存在,TGS 使用TGS 密钥
(krbtgt 的 NTLM Hash)解密 TGT,得到Client/TGS Session Key
、timestamp、Client info;同时使用从 TGT 中解密得到的Client/TGS Session Key
去解密Authenticator2
,得到 Client info 和 timestamp。 比对Authenticator2
和TGT
的解密内容以验证通过。- TGS 比对
Authenticator2
包含的Client ID
和TGT
中的Client ID
- 比较时间戳(误差范围在2分钟)
- 通过生命周期字段检查 TGT 是否过期
- 检查
Authenticator2
已经不再 TGS 的缓存中 - 若原始请求中的网络地址不为 NULL,比较 TGT 中的 IP 和请求的 IP
验证成功后,随机生成 Client 所请求服务的会话密钥
Client/Server Session Key
;使用 Server 密钥(即服务器计算机的NTLM Hash)对
Client/Server Session Key
、Client Info
(包含 Client ID)、TimeStamp
加密得到Client-To-Server Ticket
(也称为 ST 票据);使用
Client/TGS Session Key
对Client/Server Session Key
加密得到sessionkey_tgs
最终将
Client-To-Server Ticket
、sessionkey_tgs
返回给 Client。 - TGS 比对
-
-
请求服务
-
Client 向 SS(Service Server)发送服务请求
AP-REQ:Client 收到
Client-To-Server Ticket
、sessionkey_tgs
之后,使用Client/TGS Session Key
对sessionkey_tgs
解密得到Client/Server Session Key
,然后使用Client/Server Session Key
对 Client Info 和 timestamp 加密得到Authenticator3
将
Authenticator3
和Client-To-Server Ticket
发送给所请求服务的服务器(Service Server
)。- Ticket 客户端无法解密
-
Service Server 响应 Client
AP-REP:Service Server 收到客户端的服务访问请求之后,利用 Server 密钥(Server 的 ntlm Hash)对
Client-To-Server Ticket
解密,提取出Client/Server SessionKey
、Client ID 等信息。Service Server 使用
Client/Server SessionKey
对Authenticator3
解密得到 Client ID 和 TimeStamp。类似于 TGS,Service Server 也要做如下校验:
- Client ID;
- 时间戳;
- ticket 是否过期;
- 避免重放攻击,查看 Service Server 的 cache 是否包含 authenticator3;
- 网络地址比较
Service Server 发送最后的验证消息——用
Client/Server SessionKey
加密的 Timestamp 和Service ID
数据包给 Client。Client 收到之后,使用缓存的
Client/Server SessionKey
解密提取 Timestamp 信息,然后确认该信息与 Client 发送的 Authenticator3 中的 Timestamp 信息是否一致。验证通过后,在定义的通讯周期内,Client 可以使用票据请求 Service。由此完成了 Client 和 Service Server 的双向认证。
- Kerberos 协议设计的思路就是用来在不受信的环境下进行认证的协议。
- krbtgt 账号的 NTLM Hash 理论上只存在于 KDC 中。这意味着 TGT 只能由 KDC 来解密。如果 krbtgt 账号的 NTLM Hash 泄露了,那么 TGT 就能被解密甚至伪造。伪造的 TGT 叫做黄金票据。
- Ticket 是由服务器计算机本身的 NTLM Hash 加密的,Client 不能解密。如果该 Hash 泄露,那么就可以解密甚至伪造 Ticket。伪造的 Ticket 叫做白银票据。
- 在上述的流程中,涉及到时间戳 timestamp,由于它的存在,才使得被第三方获取了加密信息 Authenticator1 、Authenticator2、TGT 不会在短时间内被暴力破解。timestamp 一般时间为8小时。
- Kerberos 协议和 NTLM 协议都会使用 NTLM Hash 对生成的任意随机数加密,然后比对结果。 Kerberos 的主要区别在于添加了第三方——-KDC 参与到认证过程中。
- Client info 中包含网络地址、Client ID 等信息
-
- 每次交互 Client 可以收到两条消息,一条是可以解密的,一条是无法解密的
- Client 期望访问的服务或者主机从不直接与 KDC 通信
- KDC 存储了其数据库下所有主机和服务的密钥
- 密钥由密码加上一组随机数的哈希值,哈希算法由 Kerberos 的具体实现选择。对于服务和主机而言,其本身是没有密码的。
- 所有密钥存储于 KDC 数据库
- KDC 本身由主密钥加密
- 已经存在 Kerberos 的配置和实现采用公钥加密
PAC
上述为 RFC 规定的 Kerberos 认证授权流程(其中 NTLM Hash 是针对 Windows 举例的),而微软所实现的 Kerberos 工作流程与之则有所不同,其区别的关键就在于,KDC 所返回的 KRB_AS_REP
中将包含一组 PAC 的信息。
PAC 的全称是 Privilege Attribute Certificate(特权属性证书)。其中所包含的是各种授权信息,例如用户所属的用户组、用户所具有的权限等。(User SID 和 Groups SID)
为了防止被伪造和串改,在 PAC 中包含有两个数字签名 PAC_SERVER_CHECKSUM
和 PAC_PRIVSVR_CHECKSUM
,这两个数字签名分别由 Server 端密码 HASH 和 KDC 的密码 HASH 加密。
正如上文所述,当用户与 KDC 之间完成了认证过程之后, 用户需要访问服务器所提供的某项服务时, 服务器为了判断用户是否具有合法的权限必须通过将用户的用户名传递给 KDC, KDC 通过得到的用户名查询用户的用户组信息,用户权限等,进而返回给服务器,服务器再将此信息与用户所索取的资源的 ACL 进行比较, 最后决定是否给用户提供相应的服务。
在 Windows 的 Kerberos 实现中, 默认情况下,KRB_AS_REP
信息中将包含一组 PAC 信息,也就是说,用户所得到的 TGT(TicketGranting Ticket)会包含用户的授权信息。用户再用包含有授权信息的 TGT 去申请相应的 Service Ticket,KDC 在收到这个 KRB_TGS_REQ
请求的时候, 将 TGT 里的 PAC 信息解析出来, 加入到 Service Ticket 里返回。接下来, 当用户向服务器程序提交 KRB_AP_REQ
消息时, 服务器程序则将其中所包含的 PAC 信息传送给操作系统得到一个访问令牌, 并且同时将这个 PAC 的数字签名以 KRB_VERIFY_PAC
的消息传输给 KDC, KDC 再将验证这个 PAC 的数字签名的结果以 RPC 返回码的形式告诉服务器, 服务器就可以根据这个结果判断 PAC 数据的真实性和完整性,并做出最后对 KRB_AP_REQ
的判断。
- 优点:
- 以后对资源的访问中,服务端再接收到客户的请求的时候不再需要借助 KDC 的帮助提供完整的授权信息来完成对用户权限的判断, 而只需要根据请求中所包含的 PAC 信息直接与本地资源的 ACL 相比较做出裁决。
- 解决 PAC 欺骗,防止攻击者利用篡改的 PAC 信息实现未授权访问
- 缺点:
- PAC 在用户的认证阶段引入会导致认证耗时过长。(Windows Kerberos 客户端会通过 RPC 调用 KDC 上的函数来验证 PAC 信息,这时候用户会观察到在服务器端与 KDC 之间的 RPC 包流量的增加。)
- 由于 PAC 是微软特有的一个特性,所以启用了 PAC 的域中将不支持装有其他操作系统的服务器,制约了域配置的灵活性
SPN
使用 Kerberos 的域认证认证服务,需要正确配置 SPN
服务主体名称(SPN:Service Principal Names)是服务实例(可以理解为一个服务,比如HTTP、MSSQL)的唯一标识符(即服务器上所运行服务的唯一标识)
Kerberos 使用 SPN 将服务实例与服务登录帐户相关联。如果在整个域 或 域林中的计算机上安装多个服务实例,则每个实例都必须具有自己的 SPN。如果客户端使用多个名称进行身份验证,则给定的服务实例具有多个 SPN,即每个使用 Kerberos 的服务都需要一个 SPN.
在使用 Kerberos 身份验证的网络中,必须在内置计算机帐户(如 NetworkService 或 LocalSystem)或用户帐户下为服务器注册 SPN。 对于内置帐户,SPN 将自动进行注册。 但是,如果在域用户帐户下运行服务,则必须为要使用的帐户手动注册 SPN。
也就是说, SPN 分为两种:
- 当一个服务的权限为 Local System 或 Network Service,则 SPN 注册在域内机器帐户 (Computers) 下
- 当一个服务的权限为一个域用户,则 SPN 注册在域用户帐户 (Users) 下
SPN 在其注册的域林中必须是唯一的,若不唯一,则身份验证就会失败。
要使用 Active Directory 作为 Kerberos 实现,可以使用 setspn
命令来注册 SPN。要运行此命令,必须满足下列条件:
- 必须登录到域控制器
- 必须运行提升了特权的命令提示符(以管理员身份运行)
- 必须是 Domain Admins 组的成员(或者域管理员已授予你适当的许可权)
SNP 由服务类、主机名和端口组成。SPN 的格式:
/:/
// :服务类型,如LDAP、TERMSRV、SMTP、MSSQL、HTTP
// :服务所在主机名称,可以是FQDN(如data.test.lab、server.test.lab)和NetBIOS名(如data、server)
// :服务端口,若服务运行在默认端口上,则端口号可以省略
// :专有名称
通用服务类型 ,可参考 https://adsecurity.org/?page_id=183
举例:
- 用户 AAA 要访问 MSSQL 服务的资源,进行到 Kerberos 认证的第四步 (TGS-REP) 时,KDC 查询 MSSQL 服务的 SPN.
- 若该 SPN 注册在机器账户 (Computers) 下,TGS 将会查询数据库中所有机器账户 (Computers) 的 ServicePrincipalName 属性,找到对应的账户,使用该账户的 NTLM Hash 对
Client/Server Session Key
、Client Info
(包含 Client ID)、TimeStamp
加密得到Client-To-Server Ticket
(也称为 ST 票据)。 - 若查询服务的 SPN 注册在域用户账户 (Users) 下,TGS 将会查询数据库中所有域用户账户 (Users) 的
ServicePrincipalName
属性,找到对应的账户,使用该账户的 NTLM Hash 对 Client/Server Session Key、Client Info
(包含 Client ID)、TimeStamp
加密得到Client-To-Server Ticket
(也称为 ST 票据).
spn 官方文档: https://docs.microsoft.com/en-us/windows/desktop/AD/service-principal-names
委派
委派(Delegation):是一种让用户可以委托服务器代表自己与其他服务进行验证的功能,它允许服务账户在活动目录中模拟其他域用户身份,主要用于当服务需要以某个用户的身份来请求访问其他服务资源的场景。比如,在域内,用户 Jack 经过 Kerberos 身份验证访问服务 Web(服务 web 处于域),Web 服务再以 Jack 的身份去请求域中的服务 MSSQL,若 Jack 有权限访问就能访问成功,这种过程就是委派的一个过程。
域委派的4种主要方式:
- 非约束委派
- 表示你授予该帐户权限以委派任何服务,前提是满足启动委派所需的所有其他步骤。
- 从 IT 安全角度来看,此选项最容易配置但安全性最低。
- 约束委派 - 仅限 Kerberos
- 更安全,它将委派任务限制到指定列表,不像非约束委派允许委派给任何服务。
- 与非约束委派相比,需要额外配置。
- 必须确保在帐户上设置 SPN 并添加允许帐户委派的服务。
- 协议转换
- 基于资源的约束委派
用户在 Kerberos 认证中访问服务 A 和服务 B 的过程图:
后改进了这种同一用户访问多服务的过程,实现了 A 服务模拟用户访问 B 服务的过程。
在用户发送一个 ST(图中为 TGS)访问服务时,连同其TGT一起发送,服务 A 使用用户的 TGT 向服务B进行 ST(图中为 TGS),进而简化了用户请求服务 B 资源时验证访问的认证过程。这种就是非约束委派(TrustedForDelegation)的过程:
非约束委派过程中,如果攻击者截获了 Service A 验证的 ST 和 TGT,就可以用它们访问服务 B,进而模拟管理员访问任意服务,漫游内网。
约束委派
为了解决非约束委派的隐患,微软发布了约束委派(S4U2Proxy)。
若服务 A 允许委派给服务B,则 A 能使用 S4U2Proxy 协议将用户发送的 TS(图中的 TGS,TGS 必须是可转发的) 再转发给域控制器认证,为用户请求访问服务 B 的 TS(图中的 TGS)。接着,服务 A 就能使用新获得的 TS(图中的 TGS)模拟用户访问服务 B:
上图中用户是通过 Kerberos 协议与服务 A 进行认证的,而当用户以其他方式(如 NTLM 认证,基于表单的认证等方式)与 Web 服务器进行认证后,用户是无法向 Web 服务器提供请求该服务的 TS(图中的 TGS),因而服务器 A 也无法进一步使用 S4U2Proxy 协议请求访问服务 B。S4U2Self 协议便是解决该问题的方案,被设置为 TrustedToAuthForDelegation
的服务能够调用 S4U2Self 向认证服务器为任意用户请求访问自身的可转发的服务票据,此后,便可通过 S4U2Proxy 使用这张 TGS 向域控制器请求访问 B 的票据。这就是协议转换委派(S4U2Self/TrustedToAuthForDelegation):
基于资源的约束委派
传统的约束委派中仍然存在一些缺点,如无法进行跨域委派。微软在 Windows Server 2012 中引入了基于资源的约束委派,相对于传统的约束委派,主要有三处改进:
- 委派的权限授予给了拥有资源的后端(B)而不再是前端(A)
- 不再需要域管理员权限设置委派,只需拥有在计算机对象上编辑
msDS-AllowedToActOnBehalfOfOtherIdentity
属性的权限 - 委派功能现在可以跨域和林
基于资源的约束委派(Resource-Based Constrained Delegation)是一种允许资源自己去设置哪些账户委派给自己的约束委派。
传统的约束委派是“正向的”,通过修改服务 A 属性 msDS-AllowedToDelegateTo
,添加服务 B 的 SPN(Service Principle Name),设置约束委派对象(服务 B),服务 A 便可以模拟用户向域控制器请求访问服务B以获得服务票据(TGS)来使用服务 B 的资源。
而基于资源的约束委派则是相反的,通过修改服务 B 属性 msDS-AllowedToActOnBehalfOfOtherIdentity
,添加服务 A 的 SPN,达到让服务 A 模拟用户访问 B 资源的目的。
Source & Reference
- 深刻理解windows安全认证机制
- Windows用户密码的加密方法与破解
- Windows下的密码hash——NTLM hash和Net-NTLM hash介绍
- 浅学Windows认证
- 技术干货 | Windows认证体系解读
- 彻底理解Windows认证 - 议题解读
- NT LAN Manager - Wikipedia
- LAN Manager - Wikipedia
- Windows内网协议学习NTLM篇之NTLM基础介绍
- 红队与理论:Credential Relay 与 EPA
- NTLM Relay
- 你并不懂 Mimikatz Part 2 - MSCACHE
- 一文读懂Kerberos认证流程
点击关注,共同学习!安全狗的自我修养
github haidragon
https://github.com/haidragon