NTLM认证协议及SSPI的NTLM实现

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

NTLM认证协议及SSPI的NTLM实现没错,NTLM就是你听说过的那个NTLM。是微软应用最广泛的认证协议之一。NTLM是NTLANManager的缩写,这也说明了协议的来源。NTLM是WindowsNT早期版本的标准安全协议。Windows2000内置三种基本安全协议之一。NTLM适用范围非常广,既可用于域内的认证服务,也可用于没有AD的环境,让两台独立电脑相互认证。你可能每天都用到它而不自知,你也肯可能觉得你很熟悉它了,但是这里可能还有你所不知道的背后的秘密。比如,你可能知道NTLM可以认证用户身份,但是你可能不知道NTLM可以提供会话安全服务(NTLMSessionsecurity)。作为一个开始,我们先来介绍几个基础概念,概念清楚了,然后再看技术细节。1,什么是认证。认证就是承认和证明的意思。就是你能证明你的身份。比如你要访问一个受保护的资源,服务器需要认证你的身份。你可以声称你是系统管理员,但是怎么证明你就是管理员呢。方法很多,这里有个简单直接的方法就是证明你知道管理员的密码。认证的问题转化为:“怎么证明你知道你所声称的用户的密码?”这个问题了。一个简单暴力的证明方法是,让你直接提供密码给服务器,然后服务器去数据库里面比对,看你提供的密码对不对。如果对,认证通过。否则失败。常见的所谓WindowsForms认证,或者叫做windowsbasic认证就是这种方式。简单直接。但是密码需要在网络上传输,安全问题就不说了,你懂的。怎样在不直接提供密码的情况下,间接证明你知道密码呢?NTLM就是干这个的了。看起来很神奇,不是吗。比如对面有两个人互相说话(通信),说的都是明文,每一句你都能听懂。他们并没有说自己的密码就相互认证身份了,你听了半天,却不知道密码是什么。更神奇的是,他们认证之后,再说的话你可能就听不懂了(NTLMSessionsecurity,会话安全)。(如果他们协商会话安全之后,后续的通信都是安全加密的。)2.什么是NTLM认证。前面已经说过了,NTLM是一种在不直接提供密码的情况下,间接证明客户端知道用户密码的方法。NTLM认证最常见的应用场景恐怕就是用在浏览器(http协议)上的认证了。但是实际上,NTLM只规定了认证的流程,和认证消息格式。并不跟具体的协议相关。所以跟http就更没有必然联系了。浏览器只是在http协议头上携带了NTLM的消息而已,通过了认证。我们知道http通常是明文的,所以如果直接传输密码非常不安全,NTLM就有效的防止了这个问题。怎么理解这个问题呢,举个夸张点的例子,如果不嫌烦,客户端和服务端甚至可以通过传递小纸条的方式传递NTLM消息,来认证身份。而纸条的内容是明文的,中间传递者都可以随意查看,但是却无法知道密码,也无法伪造。现在可以开始技术细节了,我们还是采取由大及小的方式。先从整体介绍,再逐步深入。1.NTLM的认证消息,及认证流程。前面说过了,NTLM消息并不和任何传输协议绑定,它的认证消息理论上可以通过任何方式传递,所以我们的讨论都集中在协议本身,而不去关心下层的传输方式。我们先看一个图:NTLM认证共需要三个消息完成:(1).Type1消息。Negotiate协商消息。客户端在发起认证时,首先向服务器发送协商消息。协商需要认证的主体,用户,机器以及需要使用的安全服务等等信息。并通知服务器自己支持的协议内容,加密等级等等。(2).Type2消息。Challenge挑战消息。服务器在收到客户端的协商消息之后,会读取其中的内容,并从中选择出自己所能接受的服务内容,加密等级,安全服务等等。并生成一个随机数challenge,然后生成challenge消息返回给客户端。(3).Type3消息。Authenticate认证消息。客户端在收到服务端发回的Challenge消息之后,读取熬服务端所支持的内容,和随机数challenge。决定服务端所支持的内容是否满足自己的要求。如果满足,则使用自己的密码以及服务器的随机数challenge通过复杂的运算,期间可能需要自己生成一个客户端随机数clientchallenge也加入运算,并最终生成一个认证消息。并发回给服务器。(4).服务器在收到Type3的消息之后,回经过几乎同样的运算,并比较自己计算出的认证消息和服务端发回来的认证消息是否匹配。如果匹配,则证明客户端掌握了正确的密码,认证成功。允许客户端使用后续服务。如果不匹配,则认证失败。2.NTLM认证消息的结构.NTLM的消息很简单,只有三种,Type1,Type2和Type3.它们都有相似的结构。认证消息都是二进制的,但是通常我们见到的都是它们的Base64的编码格式。类似这种:1:TlRMTVNTUAADAAAAGAAYAHAAAACSAJIAiAAAAAAAAAAAAAAAGgAaAEgAAAAOAA4AYgAAAAAAAAAAAAAABYKIogAAAAAAAAAPYQBkAG0AaQBuAGkAcwB0AHIAYQB0AG8AcgBOAEUASQBMAC0AUABDALZLpLeO2n6Sx1s9JjrAfQOqf2QsmfTeP9cjC86k7BsjZEsKzjOoYBcBAQAAAAAAAEDGE3IuR88Bqn9kLJn03j8AAAAAAgAEAEsAQQABAAoARgBTAFcARQBCAAQADABrAGEALgBjAG8AbQADABgAZgBzAHcAZQBiAC4AawBhAC4AYwBvAG0ABQAMAGsAYQAuAGMAbwBtAAcACAC0gtdyLkfPAQAAAAAAAAAA所以,如果你看到这种形式不要吃惊,把他们用Base64解码即可。协议中的数字都是采用小端的方式存储。(1).消息头这三种消息都具有相似的消息头:(2)Flags标记。这三种消息一般都会携带一个4字节的int值,作为消息的Flags。Flags在三种消息中的位置不一样,所以没有当做消息头来介绍。不过,这个flags非常重要。这里先单独来介绍:(下面是我的代码片段,重点标志我做了注释,后面用到的时候会进一步介绍)1:flagsExps[0x1]=Unicode;2:flagsExps[0x2]=OEM;3:flagsExps[0x4]=RequestTarget;4:flagsExps[0x8]=r10(mustbezero);5:6:flagsExps[0x10]=NegotiateSign;//需要协商签名服务7:flagsExps[0x20]=NegotiateSeal;//需要协商加密服务8:flagsExps[0x40]=NegotiateDatagramStyle;//UDP非连接模式9:flagsExps[0x80]=NegotiateLanManagerKey;//在某些特定的NTLMv1下使用Lanmanagerkey后面会详细介绍10:11://================================12:flagsExps[0x100]=NegotiateNetware(r9mustbezero);13:flagsExps[0x200]=NegotiateNTLM;14:flagsExps[0x400]=r8(shouldbezero);15:flagsExps[0x800]=NegotiateAnonymous;//使用匿名登录16:17:flagsExps[0x1000]=NegotiateDomainSupplied;18:flagsExps[0x2000]=NegotiateWorkstationSupplied;19:flagsExps[0x4000]=NegotiateLocalCall(r7);20:flagsExps[0x8000]=NegotiateAlwaysSign;21:22:23://===============================24:flagsExps[0x10000]=TargetTypeisaDomain.;25:flagsExps[0x20000]=TargetTypeisaServer.;26:flagsExps[0x40000]=TargetTypeShare(r6);27:flagsExps[0x80000]=NegotiateNTLM2Key(EXTENDED_SESSIONSECURITY);//使用扩展会话安全28:29:flagsExps[0x100000]=RequestInitResponse(NTLMSSP_NEGOTIATE_IDENTIFY);30:flagsExps[0x200000]=RequestAcceptResponse(r5,mustbezero);31:flagsExps[0x400000]=RequestNon-NTSessionKey;32:flagsExps[0x800000]=NegotiateTargetInfo;//协商携带TargetInfo33:34://===============================35:flagsExps[0x1000000]=r4(mustbezero);36:flagsExps[0x2000000]=NTLMSSP_NEGOTIATE_VERSION(协商携带操作系统版本号,一般会忽略此项,仅供调试用途);37:flagsExps[0x4000000]=r3(mustbezero);38:flagsExps[0x8000000]=r2(mustbezero);39:40:flagsExps[0x10000000]=r1(mustbezero);41:flagsExps[0x20000000]=Negotiate128;//协商128位加密42:flagsExps[0x40000000]=NegotiateKeyExchange;//协商交换key,在会话安全中,使用交换key来加密内容,而不是直接使用会话key43:flagsExps[0x80000000]=Negotiate56;//协商56位加密(3).Type1消息a.前面首先是8个字节+4个字节的协议头。前面已经介绍过了。注意,消息类型为1b.然后是四个字节的Flags。前面也介绍过了。这个Flags中表达了客户端想要使用的NTLM的认证服务,以及客户端自己所支持的服务。c.然后,是若干个可选的securitybuffer。注意上图中的securitybuffer,安全缓冲区。它是一个8字节固定大小的结构体。它看起来像是这个样子:它其实是一个缓冲区指针。它指向一个区域,这个区域相对于Type1消息起始的偏移量为offset,这个区域的大小长度为MaxLength,其中的有效使用大小为:Length.如果Flags中包含0×1000标记,则需要提供域。把域名写入到这个缓冲区中。字符集由Flags中的OEM或者Unicode决定。如果Flags中包含0×2000标记,则需要提供workstation的名字。方法同上。d.然后是8字节的操作系统版本号。如果Flags中包含0×2000000,则需要提供操作系统的版本号。e.然后,就是携带的前面securitybuffer中所指向的数据了。在Type1的消息中,只有前面的a和b项,是必须的,后面的都是可选的。(4)Type2消息服务端在收到Type1消息之后,会生成Type2消息返回给客户端。a.前面首先还是8个字节+4个字节的协议头。前面已经介绍过了。注意此时的消息类型已经是2了。b.然后是四个字节的Flags。前面也介绍过了。这个Flags中表达了服务端所能接受的服务。c.上图中的TargetName是要访问的机器名。存储方法是securitybuffer.前面介绍过了,不多说了。d.Flags不多说了。e.Challenge,这是一个服务端生成的8字节的随机数,客户端会用来计算key.f.Context,这是一个8字节的值,其实是两个连续的32位值。表示一个内部handle。当

1 / 6
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功