1.windows系统中的密码算法
windows操作系统主要密码加密算法的发展阶段包含如下四个阶段:
- 1.明文阶段:用户名密码直接明文传输和存储。
- 2.LAN Manager(LM)哈希:Windows系统所用的第一种密码哈希算法,但是太简单了容易被破解。
Windows Vista
和Windows 2008
之后版本的系统放弃使用了这种哈希。 - 3.NT LAN Manager(NTLM)哈希:windows系统中
Vista
之后的版本(包含windows7,windows8,windows10,以及windows2000及之后server版本
)默认用这种算法进行本地身份认证。
2. LM Hash
2.1 LM Hash生成规则
- 1.用户密码首先不能超过14个字符
- 2.对输入密码转换成大写
- 3.密码转换为16进制字符串,不够14个字节的用0补全
- 4.将16进制字符串分成两个 7字节的部分,每部分转换成56bit的比特流,长度不足的左边用0补齐,再分7bit一组末尾加0
- 5.将上述两组8字节字符串分别当作key为
KGS!@#$%
进行DES加密,然后拼在一起当作最后结果
2.2 LM Hash生成实例分析
此处我们以密码Ad123456789.
作为例子说明:
- 1.转换为大写:
Ad123456789.
变换为AD123456789.
- 2.转换为16进制字符串:
AD123456789.
变换为41443132333435363738392e
- 3.补全至14字节:
41443132333435363738392e
变换为41443132333435363738392e000
- 4.分为两个7字节的字符串:第一部分为
41443132333435
,第二部分为363738392e0000
- 5.转换为比特流,不足4位的在前面补0:第一部分变为
01000001010001000011000100110010001100110011010000110101
,第二部分变为00110110001101110011100000111001001011100000000000000000
- 6.以7比特一组进行分组并在末尾补0:第一个分组为:
['01000000', '10100010', '00001100', '00100110', '00100010', '10011000', '11010000', '01101010']
,第二个分组为['00110110', '00011010', '11001110', '00000110', '10010010', '01110000', '00000000', '00000000']
- 7.将上述两个分组转化成两个8字节的字符串:第一个字符串为
40a20c262298d06a
,第二个字符串为361ace0692700000
- 8.使用上面的两组字符串对
KGS!@#$%
进行des加密:得到第一个字符串的加密结果为a6a587efcfa761c1
,第二个字符串加密结果为16c020f51a519d4e
,拼在一起得到最终的LM哈希a6a587efcfa761c116c020f51a519d4e
和系统中mimikatz抓出来的显然是一样的,如下图: python脚本如下:
# coding=utf-8 import base64 import binascii from pyDes import * def DesEncrypt(str, Des_Key): k = des(Des_Key, ECB, pad=None) EncryptStr = k.encrypt(str) return binascii.b2a_hex(EncryptStr) def Zero_padding(str): b = [] l = len(str) num = 0 for n in range(l): if (num < 8) and n % 7 == 0: b.append(str[n:n + 7] + '0') num = num + 1 return ''.join(b) if __name__ == "__main__": test_str = "123456" # 用户的密码转换为大写,并转换为16进制字符串 test_str = test_str.upper().encode('hex') str_len = len(test_str) # 密码不足14字节将会用0来补全 if str_len < 28: test_str = test_str.ljust(28, '0') # 固定长度的密码被分成两个7byte部分 t_1 = test_str[0:len(test_str) / 2] t_2 = test_str[len(test_str) / 2:] # 每部分转换成比特流,并且长度位56bit,长度不足使用0在左边补齐长度 t_1 = bin(int(t_1, 16)).lstrip('0b').rjust(56, '0') t_2 = bin(int(t_2, 16)).lstrip('0b').rjust(56, '0') # 再分7bit为一组末尾加0,组成新的编码 t_1 = Zero_padding(t_1) t_2 = Zero_padding(t_2) print t_1 t_1 = hex(int(t_1, 2)) t_2 = hex(int(t_2, 2)) t_1 = t_1[2:].rstrip('L') t_2 = t_2[2:].rstrip('L') if '0' == t_2: t_2 = "0000000000000000" t_1 = binascii.a2b_hex(t_1) t_2 = binascii.a2b_hex(t_2) # 上步骤得到的8byte二组,分别作为DES key为"KGS!@#$%"进行加密。 LM_1 = DesEncrypt("KGS!@#$%", t_1) LM_2 = DesEncrypt("KGS!@#$%", t_2) # 将二组DES加密后的编码拼接,得到最终LM HASH值。 LM = LM_1 + LM_2 print LM
2.3 LM Challenge/Response认证
虽然LM Hash设计出来也是为了防止SMB认证明文传输,所以也有基于LM哈希的SMB认证算法。但是这种认证方式比较远古,现在基本上弃用了。具体操作如下:
- 1.Client向Server发送一个认证请求,请求中包含明文的登录用户名。服务器会提前存储登录用户名和对应的密码hash
- 2.Server端向Client端发送一个challenge(一个8byte的字符串,16位的16进制数)
- 3.Client端计算用于登录密码的LM哈希(32位的16进制数),然后在后补10个
0
变成42位的16进制字符串即21字节。 - 4.将21字节字符串划分为3组,每组7字节,然后按照LM Hash生成算法再分别对这三组字符生成DESKey,变成每组8字节。
- 5.用三个DESKey分别对challenge进行DES加密,把结果拼到一起,得到一个respnese发送给Server端进行验证。Server端自己再用自己的LM哈希算一遍,结果一样就通过。
3.NTLM哈希
3.1 NTLM哈希生成规则
- 1.明文口令转换成ascii值
- 2.ascii值转换成16进制
- 3.16进制字符串采用小端序改成Unicode
- 4.对转化结果md4加密
总结起来其实就是MD4(UTF-16-LE(password))
3.2 NTLM哈希生成实例分析
此处我们以密码Ad123456789.
作为例子说明:
- 1.明文口令转换成ascii值:
Ad123456789.
转化为65 100 49 50 51 52 53 54 55 56 57 46
- 2.ascii值转换成16进制:
65 100 49 50 51 52 53 54 55 56 57 46
转化为41 64 31 32 33 34 35 36 37 38 39 2e
- 3.16进制字符串采用小端序改成Unicode:
41 64 31 32 33 34 35 36 37 38 39 2e
转换为410064003100320033003400350036003700380039002e
- 4.:对转化结果md4加密:
410064003100320033003400350036003700380039002e
转变为b07289e15dd2274a8bcc372f024d9609
。
python代码如下
import hashlib,binascii hash = hashlib.new('md4', "Ad123456789.".encode('utf-16le')).hexdigest() print hash
3.3 NTLM Challenge/Response认证(Net-NTLM)
3.3.0 这种认证出现在什么地方?
NTLM Challenge/Response认证是一种网络认证协议,这种认证协议目前我们比较常见的主要是在SMB认证里面!!!就是使用SMB协议的时候是用这种协议认证的!!!不能和Kerberos协议混淆!Kerberos是在域用户登录某台域内机器的桌面时候用的认证协议。
3.3.1 NTLM Challenge/Response认证过程
NTLM Challenge/Response进行认证的时候主要包含以下三个步骤:
- 1.Client向Server发送一个请求,请求中包含明文的登录用户名。Server提前存储登录用户名和对应的密码hash。
- 2.Server接收到请求后,生成一个16或者8位的随机数(这个随机数被称为
Challenge
,NTLM v2和NTLM v1不同),明文发送回客户端。使用所请求登录的用户密码hash加密Challenge,获得Challenge1
。 - 3.Cilent接收到Challenge后,使用请求登录用户的密码hash对Challenge加密,获得一个包含了加密后Challenge的
response
,然后把这个response发送给Server。 - 4.Server接收到response后对比Challenge1和response中的Challenge是否相同,相同则认证成功。
注意!!!在上述过程中,始终没有使用到明文密码,也就是说一个用户只要能得到密码的hash即可完成Net-NTLM认证!!!
3.3.2 Net-NTLM v2过程详述
Net-NTLM认证主要包含以下三种版本的协议:NTLM v1
、NTLM v2
、NTLM session v2
。目前比较主流的就是Net-NTLMv2协议。以下使用NTLM v2协议进行简述。
上图中的四个请求就是典型的NTLM v2的认证过程,首先在第二个请求包中我们可以发现对应的challenge值。
第三个数据包中包含了client加密后的challenge
注:上述认证过程是在workgroup环境的认证过程,而在域环境中对比response的工作是由域控来进行的,如下图所示
为了对上述过程的区别更加直观,这里我们使用wireshark进行一下对比,使用同样的两台机器去建立IPC连接:
- 在非域环境下登录的数据包如下图所示
- 在域环境下登录的数据包如下图所示 从图中我们可以看到,在非域环境下,Server端直接判定了认证失败,而在域环境下,Server端在收到response后转发给了域控,由域控判定了认证是否通过,再由Server端将认证结果转发给了client端。
4.windows域认证
目前windows在域环境中认证主要用的就是Kerberos
协议。Kerberos是希腊神话中守护地狱之门的一条凶猛的三头神犬。Kerberos 从提出到今天,共经历了五个版本的发展。93年就已经颁布了第五版,所以目前见到的系统主要都是用Kerberos v5
。Kerberos系统架构如下图所示:
4.0 Kerberos Distribution Center的组成
- Account Database(AD):保存了所有Client的白名单。
- Authentication Service(AS):为所有Client生成TGT的白名单。
- Ticket Granting Service(TGS):为Cient生成某个Server的Ticket
4.1 windows域认证过程详解
-
1.Client端向KDC(Kerberos Distribution Center)发送一个请求,表示自己需要去访问某个Server需要得到授权。这个请求当中包含了
用户名
,用这个用户名对应的NTLM哈希加密的时间戳
,Service Info
。 -
2.KDC收到请求,根据Client所提供的用户名,在自己的AD(
Account Database
)中查看是否存在这个用户于白名单中。如果存在则生成一个随机的Session Key
。对于这个Session Key,KDC会用Client的NTLM Hash
进行加密。然后用krbtgt
用户的NTLM Hash对Session Key和一些客户端的信息进行加密,得到所谓的TGT
(Ticket Granting Ticket)。TGT
中包含了Session key
、Client name
、End Time
。然后把这两个东西发送给客户端。 -
3.Client获得了得到上面返回内容后,首先用自己的NTLM Hash把Session Key解密出来,然后用解密得到的Session Key,加密Client info和时间戳。然后把
TGT
,用Session Key加密的结果
,Client Info + Server Info
发送给TGS。 -
4.TGS收到后用
krbtgt
用户的哈希去解密TGT
,得到Session Key
,再用Session Key去解密客户端发来的信息,得到Client Info和时间戳。然后校验时间戳和用户信息是否匹配。如果验证通过,TGS会在生成一个Server Session Key
。然后用Session Key去加密Server Session Key。用Server NTLM Hash(Server的计算机名所对应的NTLM哈希)去加密Server Session Key+Client Info+到期时间得到所谓的Ticket
。然后把这两个结果返回给客户端。 -
5.Client把Ticket和用Server Session Key加密的Client Info以及时间戳发送给Server。
-
6.Server拿到数据包,用自己的NTLM Hash解密Ticket,得到Server Session Key,Client Info,到期时间。再用Server Session Key解密Client加密的信息,判断Client Info是否一致,时间戳是否超时。如果都OK则认证成功。
4.2 针对kerberos协议的攻击
4.2.1 白银票据
4.2.1.1 白银票据简介
从认证过程我们可以发现,假如说我们手中有了Server NTLM Hash
,那么前面的四步是完全可以直接跳过的。不需要经过KDC,直接自己用Server NTLM Hash伪造一个Ticket就可以完成认证。这就是传说中的白银票据。
4.2.1.1.2 白银票据可用服务
白银票据只能针对所掌握NTLM Hash的Server进行伪造,所能支持的服务如下:
服务注释 | 服务名 |
---|---|
WMI |
HOST、RPCSS |
PowerShell Remoteing |
HOST、HTTP |
WinRM |
HOST、HTTP |
Scheduled Tasks |
HOST |
LDAP 、DCSync |
LDAP |
Windows File Share (CIFS) |
CIFS |
Windows Remote Server Administration Tools |
RPCSS、LDAP、CIFS |
4.2.2 黄金票据
4.2.2.1 黄金票据简介
如果得到了krbtgt用户
的NTLM Hash,那么就可以自己伪造TGT。从而跳过了第一步和第二步,不需要再去验证用户名和对应的NTLM哈希。通过伪造的TGT,再去申请Ticket,从而就可以访问域内所有的Server。
5.参考链接
https://blog.csdn.net/wulantian/article/details/42418231 https://blog.csdn.net/mango_song/article/details/16802811 http://sh1yan.top/2019/06/03/Discussion-on-Silver-Bill-and-Gold-Bill/ https://www.secpulse.com/archives/94848.html