[内网渗透] 浅谈-NTLM

admin 2023年1月1日07:12:26评论13 views字数 4349阅读14分29秒阅读模式

0x00 NTLM 简介
NTLM是什么?
NTLM 是一套身份验证和会话安全协议,用于各种 Microsoft 网络协议的实现中(注:NTLM为嵌套协议,被嵌套在各种协议,如 HTTP、SMB、SMTP 等协议中),并由NTLM安全支持提供程序(NTLMSSP)支持。NTLM 最初用于DCE/RPC的身份验证和协商(Negotiate),在整个 Microsoft 系统中也用作集成的单点登录机制(SSO)。可以认为 NTLM 是HTTP身份验证的技术栈的一部分。同时,它也用于 SMTP,POP3,IMAP(Exchange 的所有部分),CIFS/SMB,Telnet,SIP以及其他可能的Microsoft实现中。
NTLM的作用?
NTLM Security Support Provider 在 Windows Security Support Provider(SSPI)框架内提供身份验证(Authentication),完整性(Signing)和机密性(Sealing)服务。SSPI 定义了由支持提供程序(supporting providers)实现的一组核心安全功能集;NTLMSSP就是这样的提供程序(supporting providers)。SSPI 定义并由 NTLMSSP 实现以下核心操作:

  1. 身份验证(Authentication)- NTLM 提供了质询响应(challenge-response)身份验证机制,在这种机制中,客户端无需向服务器发送密码即可证明其身份。(注:我们常说的PTH等等操作都发生在这里。)

  2. 签名(Signing)-NTLMSSP提供了一种对消息应用数字"签名"的方法。这样可以确保已签名的消息未被(偶然或有意地)修改,并 且确保签名方知道共享机密。NTLM实现了对称签名方案(消息身份验证码或MAC);也就是说,有效的签名只能由拥有公共共享Key的各方生成和验证。

  3. Sealing(注:找不到合适的词来翻译,可以理解为加密封装)-NTLMSSP实现了对称Key加密机制,该机制可提供消息机密性。对于NTLM,Sealing还意味着签名(已签名的消息不一定是已Sealing的,但是所有已Sealing的消息都已签名)。

Kerberos已取代NTLM成为基于域的方案的首选身份验证协议。但是,Kerberos是需要有受信任的第三方方案,不能在不存在受信任的第 三方的情况下使用。例如,成员服务器(不属于域的服务器),本地帐户以及对不受信任域中资源的身份验证。在这种情况下,NTLM仍然是主要的身份验证机制 (可能会持续很长时间)。
0x01 NTLM认证过程
ntlm认证用的一种challenge/response模式,翻译过来质询/应答,其实就是问问题答问题。它的流程:
1、客户端向服务器发送登录请求,登录请求包含明文用户名。服务器上存储了相应的用户名及对应的hash。
2、服务器收到请求后,会生成一个随机的16位随机数(这个随机数就是challenge质询,问问题)明文返回客户端。这时候服务器会使用该用户的密码hash去加密将要返回的challenge,生成一个challenge1.
3、客户端收到了challenge,然后使用自己的密码hash对challenge加密,获得了challenge2(这个challenge2就是response应答,答问题)并发送给服务器。
4、服务器收到challenge2后和自己存储的challenge1做对比,一样的话就代表验证成功。
[内网渗透] 浅谈-NTLM
再看下本地登录,在本地登录时,操作系统会拿用户输入的密码去系统中进行校验,系统存储密码位置在%SystemRoot%system32configsam,sam相当于是个数据库。sam中存的是用户的ntlmhash,在本地认证过程中,其实就是将用户输入的密码转换成ntlmhash然后和sam中的ntlmhash做比较。
0x02 NTLMv1v2、Net-NTLM、ntds.dit
在上面说到的ntlmhash过程时,服务器会随机产生一个随机数,如果这个随机数是8位的,那就是ntlmv1,如果是16位那就是ntlmv2。那什么是net-ntlm,还是上面那个ntlmhash过程,服务器生成一个随机数并用相应的ntlmhash对其加密然后返回给客户端,这个返回的东西就是net-ntlm。

注意区别:ntlmhash存放在安全账户管理数据库中,也就是sam中,以及域控的ntds.dit数据库中。而net-ntlm是用于网络验证的,是通过用户的ntlmhash和相应算法产生的。

ntds.dit:sam是个人信息存储数据库,ntds.dit是域中成员信息存储数据库,默认位置在域控的%SystemRoot%NTDS文件夹中,只能由域控制器进程和协议访问,里面包含了当前域中所有用户的信息和hash值。
0x03 LM-Hash、NTLM-Hash
windows 操作系统通常使用两种方法对用户的明文密码进行加密处理。在域环境中,用户信息存储在ntds.dit中,加密后为散列值。
在windows下通过SAMInside提取到的密码Hash时,可以看到有两条,分别是LM-Hash和NT-Hash,这是对同一个密码的两种不同的加密方式。在windows操作系统中,hash的结构通常如下:

username:RID:LM-HASH:NT-HASH
Administrator:500:AAD3B435B51404EEAAD3B435B51404EE:31D6CFE0D16AE931B73C59D7E0C089C0:::

windows hash是不加盐的
AAD3B435B51404EEAAD3B435B51404EE
是LM Hash,
31D6CFE0D16AE931B73C59D7E0C089C0
是NT Hash。

LM Hash的计算:
  1. 用户的密码转换为大写,密码转换为16进制字符串,不足14字节将会用0来再后面补全。
  2. 密码的16进制字符串被分成两个7byte部分。每部分转换成比特流,并且长度位56bit,长度不足使用0在左边补齐长度
  3. 再分7bit为一组,每组末尾加0,再组成一组
  4. 上步骤得到的二组,分别作为key 为 KGS!@#$%进行DES加密。
  5. 将加密后的两组拼接在一起,得到最终LM HASH值。

参考脚本
#coding=utf-8import reimport binasciifrom pyDes import *def DesEncrypt(str, Des_Key):    k = des(binascii.a2b_hex(Des_Key), ECB, pad=None)    EncryptStr = k.encrypt(str)return binascii.b2a_hex(EncryptStr)def group_just(length,text):# text 00110001001100100011001100110100001101010011011000000000    text_area = re.findall(r'.{%d}' % int(length), text) # ['0011000', '1001100', '1000110', '0110011', '0100001', '1010100', '1101100', '0000000']    text_area_padding = [i + '0' for i in text_area] #['00110000', '10011000', '10001100', '01100110', '01000010', '10101000', '11011000', '00000000']    hex_str = ''.join(text_area_padding) # 0011000010011000100011000110011001000010101010001101100000000000    hex_int = hex(int(hex_str, 2))[2:].rstrip("L") #30988c6642a8d800if hex_int == '0':        hex_int = '0000000000000000'return hex_intdef lm_hash(password):# 1. 用户的密码转换为大写,密码转换为16进制字符串,不足14字节将会用0来再后面补全。    pass_hex = password.upper().encode("hex").ljust(28,'0') #3132333435360000000000000000    print(pass_hex) # 2. 密码的16进制字符串被分成两个7byte部分。每部分转换成比特流,并且长度位56bit,长度不足使用0在左边补齐长度    left_str = pass_hex[:14] #31323334353600    right_str = pass_hex[14:] #00000000000000    left_stream = bin(int(left_str, 16)).lstrip('0b').rjust(56, '0') # 00110001001100100011001100110100001101010011011000000000    right_stream = bin(int(right_str, 16)).lstrip('0b').rjust(56, '0') # 00000000000000000000000000000000000000000000000000000000# 3. 再分7bit为一组,每组末尾加0,再组成一组    left_stream = group_just(7,left_stream) # 30988c6642a8d800    right_stream = group_just(7,right_stream) # 0000000000000000# 4. 上步骤得到的二组,分别作为key 为 "KGS!@#$%"进行DES加密。    left_lm = DesEncrypt('KGS!@#$%',left_stream) #44efce164ab921ca    right_lm = DesEncrypt('KGS!@#$%',right_stream) # aad3b435b51404ee# 5. 将加密后的两组拼接在一起,得到最终LM HASH值。return left_lm + right_lmif __name__ == '__main__':    # 这里填入要加密的hash    hash = lm_hash("123456")


文章更深度解析

https://github.com/Pik-sec/tip/blob/main/NTLM.docx



原文始发于微信公众号(Pik安全实验室):[内网渗透] 浅谈-NTLM

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年1月1日07:12:26
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   [内网渗透] 浅谈-NTLMhttp://cn-sec.com/archives/1493279.html

发表评论

匿名网友 填写信息