NTLM 基础介绍

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NTLM 基础介绍相关的知识,希望对你有一定的参考价值。

参考技术A windows内部是不保存明文密码的,只保存密码的hash。
其中,本机用的密码hash是保存在本地的SAM文件中,域用户的密码hash保存在域控下的NTDS.DIT文件中。那么,hash是以什么样的形式进行保存的呢?
在我们抓取用户hash时,经常看到如下格式:
Administrator:500:AAD3B435B51404EEAAD3B435B51404EE:31D6CFE0D16AE931B73C59D7E0C089C0:::
需要明确的是: AAD3B435B51404EEAAD3B435B51404EE 是LM Hash, 31D6CFE0D16AE931B73C59D7E0C089C0 是NTLM Hash
下面就详细的来了解一下这两种hash。

全称是LAN Manager Hash, windows最早用的加密算法,由IBM设计。
LM Hash的计算:

lm协议的脆弱之处在于

由上面可知,LM hash其实是很脆弱的,对此,微软于1993年在Windows NT 3.1中引入了NTLM协议。NTLM Hash是支持Net NTLM认证协议及本地认证过程中的一个重要参与物,其长度为32位,由数字与字母组成。
下面是各个版本针对LM和NTLM的支持。

NTLM验证是一种Challenge/Response 验证机制,由三种消息组成:通常称为type 1(协商),类型type 2(质询)和type 3(身份验证)。值得注意的是,NTLM协议为嵌入式协议。
它基本上是这样工作的:

type1过程发送的内容主要包含客户端支持和服务器的功能列表。包结构如下:

这个过程是服务器用type 2消息(质询)进行响应,这包含服务器支持和同意的功能列表。但是,最重要的是,它包含服务器产生的Challenge。
主要 包含以下结构:

其中最主要的信息是challenge。后面加密验证依赖于challenge
抓包查看对应的信息如下:

这个过程客户端接收到challenge之后,使用用户hash与challenge进行加密运算得到response,将response,username,challenge发给服务器。消息中的response是最关键的部分,因为它向服务器证明客户端用户已经知道帐户密码。
主要包含以下结构:

在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和加密算法不同。
这里我们侧重讲下NTLM v1响应和NTLMv2响应
● v2是16位的Challenge,而v1是8位的Challenge
v1是将 16字节的NTLM hash空填充为21个字节,然后分成三组,每组7比特,作为3DES加密算法的三组密钥,加密Server发来的Challenge。 将这三个密文值连接起来得到response。
而v2是的加密算法是:
(1). 将Unicode后的大写用户名与Unicode后的身份验证目标(在Type 3消息的"TargetName"字段中指定的域或服务器名称)拼在一起。请注意,用户名将转换为大写,而身份验证目标区分大小写,并且必须与“TargetName”字段中显示的大小写匹配。使用16字节NTLM哈希作为密钥,得到一个值。
(2) 构建一个blob信息

SMTP 通过 Exchange 使用 Python 集成 Windows 身份验证 (NTLM)

【中文标题】SMTP 通过 Exchange 使用 Python 集成 Windows 身份验证 (NTLM)【英文标题】:SMTP through Exchange using Integrated Windows Authentication (NTLM) using Python 【发布时间】:2011-02-24 09:00:27 【问题描述】:

我想使用已登录 Windows 用户的凭据来验证与使用 NTLM 的 Exchange 服务器的 SMTP 连接。

我知道 python-ntlm 模块和 two patches 启用了 SMTP 的 NTLM 身份验证,但是我想使用当前用户的安全令牌,而不必提供用户名和密码。

与Windows Authentication with Python and urllib2非常相似的问题。

【问题讨论】:

【参考方案1】:

虽然下面的解决方案只使用了 Python Win32 扩展(Python Win32 扩展中包含的 sspi 示例代码非常有用),但问题中提到的 python-ntlm IMAP 和 SMTP 补丁也可以作为有用的指南。

from smtplib import SMTPException, SMTPAuthenticationError
import string
import base64
import sspi

# NTLM Guide -- http://curl.haxx.se/rfc/ntlm.html

SMTP_EHLO_OKAY = 250
SMTP_AUTH_CHALLENGE = 334
SMTP_AUTH_OKAY = 235

def asbase64(msg):
    # encoding the message then convert to string
    return base64.b64encode(msg).decode("utf-8")

def connect_to_exchange_as_current_user(smtp):
    """Example:
    >>> import smtplib
    >>> smtp = smtplib.SMTP("my.smtp.server")
    >>> connect_to_exchange_as_current_user(smtp)
    """

    # Send the SMTP EHLO command
    code, response = smtp.ehlo()
    if code != SMTP_EHLO_OKAY:
        raise SMTPException("Server did not respond as expected to EHLO command")

    sspiclient = sspi.ClientAuth('NTLM')

    # Generate the NTLM Type 1 message
    sec_buffer=None
    err, sec_buffer = sspiclient.authorize(sec_buffer)
    ntlm_message = asbase64(sec_buffer[0].Buffer)

    # Send the NTLM Type 1 message -- Authentication Request
    code, response = smtp.docmd("AUTH", "NTLM " + ntlm_message)

    # Verify the NTLM Type 2 response -- Challenge Message
    if code != SMTP_AUTH_CHALLENGE:
        raise SMTPException("Server did not respond as expected to NTLM negotiate message")

    # Generate the NTLM Type 3 message
    err, sec_buffer = sspiclient.authorize(base64.decodebytes(response))
    ntlm_message = asbase64(sec_buffer[0].Buffer)

    # Send the NTLM Type 3 message -- Response Message
    code, response = smtp.docmd(ntlm_message)
    if code != SMTP_AUTH_OKAY:
        raise SMTPAuthenticationError(code, response)

【讨论】:

@NoahYetter 你知道如何/从哪里得到sspi吗? @gt6989b 它包含在 pywin32 中 @NoahYetter 非常感谢,这很有帮助——我在网上找遍了所有地方都找不到。【参考方案2】:

很好的答案,但作为 python 3 的更新

def asbase64(msg):
    # encoding the message then convert to string
    return base64.b64encode(msg).decode("utf-8")

【讨论】:

多余的括号:base64.b64encode(msg).decode('utf-8')【参考方案3】:

由于指定了空白 cmd,Python 2.7.x 将无法发送 NTLM 类型 3 消息:

code, response = smtp.docmd("", ntlm_message)

这最终会将正确的响应发送回服务器,但是由于 docmd() 调用 putcmd() 的性质,它会预先挂起一个空格。

smtplib.py:

def putcmd(self, cmd, args=""):
    """Send a command to the server."""
    if args == "":
        str = '%s%s' % (cmd, CRLF)
    else:
        str = '%s %s%s' % (cmd, args, CRLF)
    self.send(str)

# ...

def docmd(self, cmd, args=""):
    """Send a command, and return its response code."""
    self.putcmd(cmd, args)
    return self.getreply()

因此采用 else 条件的路径,从而发送 str(' ' + ntlm_message + CRLF) 导致 (501, 'Syntax error in parameters or arguments')

因此,修复只是将 NTLM 消息作为 cmd 发送。

code, response = smtp.docmd(ntlm_message)

已提交对上述答案的修复,但谁知道它何时会被审核/接受。

【讨论】:

以上是关于NTLM 基础介绍的主要内容,如果未能解决你的问题,请参考以下文章

T1187 强制 NTLM 认证

T1187 强制 NTLM 认证

T1187 强制 NTLM 认证

渗透技巧——通过HTTP协议获得Net-NTLM hash

如何防御“神器”Mimikatz窃取系统密码?

滥用exchage远程调用域管理员API接口