域渗透学习笔记(二、windows系统认证方式)

1.windows系统中的密码算法

windows操作系统主要密码加密算法的发展阶段包含如下四个阶段:

  • 1.明文阶段:用户名密码直接明文传输和存储。
  • 2.LAN Manager(LM)哈希:Windows系统所用的第一种密码哈希算法,但是太简单了容易被破解。Windows VistaWindows 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为[email protected]#$%进行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.使用上面的两组字符串对[email protected]#$%进行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为"[email protected]#$%"进行加密。
    LM_1 = DesEncrypt("[email protected]#$%", t_1)
    LM_2 = DesEncrypt("[email protected]#$%", 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 v1NTLM v2NTLM 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 keyClient nameEnd 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
LDAPDCSync 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