发新话题
打印

[转载]关于定位lsass内存中的明文密码

[转载]关于定位lsass内存中的明文密码

文章作者:zzzevazzz

Codz:

所谓“不到黄河心不死”、“不撞南墙不回头”、“不见棺材不掉泪”,人是不容易死心的。在没搞清楚lsass内存中明文密码从哪里来到哪里去之前,对它总抱有一丝幻想。最早是在netxeyes看到关于lsass里有明文密码的帖子,当时就想跟踪一下,确定它的位置。后来在安焦又见有人提起,于是建议高手研究一下,可是没有回应。可能是因为高手都一眼看出这没有研究价值。为了消灭“最终の幻想”,我只好自己动手。对于Debug我是很菜的,乘机练习一下。

在VMWare上登陆几次win2003,密码位置一样。好,有可重复性。再挂上WinDbg。因为要跟踪登陆过程,用内核调试器比较好。用户态调试器也可以,在注册表里把lsass.exe的debugger设置为ntsd就行。不过WinDbg的窗口模式用着比较爽。

先找到lsass.exe

kd> !process 0 0
**** NT ACTIVE PROCESS DUMP ****
PROCESS 80ead020  SessionId: none  Cid: 0004   Peb: 00000000  ParentCid: 0000
   DirBase: 00039000  ObjectTable: e1000d58  HandleCount: 184.
   Image: System

PROCESS ffbdd868  SessionId: none  Cid: 0174   Peb: 7ffdf000  ParentCid: 0004
   DirBase: 0324f000  ObjectTable: e1274f58  HandleCount:  17.
   Image: smss.exe

PROCESS 80d7c970  SessionId: 0  Cid: 01ac   Peb: 7ffdf000  ParentCid: 0174
   DirBase: 0414c000  ObjectTable: e12bb720  HandleCount: 243.
   Image: csrss.exe

PROCESS ffb73440  SessionId: 0  Cid: 01c4   Peb: 7ffdf000  ParentCid: 0174
   DirBase: 00459000  ObjectTable: e14aab18  HandleCount: 417.
   Image: winlogon.exe

PROCESS 80d9f7d8  SessionId: 0  Cid: 01f0   Peb: 7ffdf000  ParentCid: 01c4
   DirBase: 001b0000  ObjectTable: e15e6ea0  HandleCount: 254.
   Image: services.exe

PROCESS 80d91550  SessionId: 0  Cid: 01fc   Peb: 7ffdf000  ParentCid: 01c4
   DirBase: 03343000  ObjectTable: e15e9e08  HandleCount: 375.
   Image: lsass.exe

PROCESS ffb88b08  SessionId: 0  Cid: 02a4   Peb: 7ffdf000  ParentCid: 01f0
   DirBase: 00914000  ObjectTable: e163c108  HandleCount: 146.
   Image: svchost.exe

PROCESS ffb8c690  SessionId: 0  Cid: 02e0   Peb: 7ffdf000  ParentCid: 01f0
   DirBase: 03164000  ObjectTable: e16628c8  HandleCount: 112.
   Image: svchost.exe

PROCESS ffb557d8  SessionId: 0  Cid: 0350   Peb: 7ffdf000  ParentCid: 01f0
   DirBase: 004d6000  ObjectTable: e17290a0  HandleCount:  55.
   Image: svchost.exe

PROCESS ffb52938  SessionId: 0  Cid: 035c   Peb: 7ffdf000  ParentCid: 01f0
   DirBase: 00494000  ObjectTable: e17134e0  HandleCount:  76.
   Image: svchost.exe

PROCESS ffb4d7f0  SessionId: 0  Cid: 038c   Peb: 7ffdf000  ParentCid: 01f0
   DirBase: 00e19000  ObjectTable: e174b078  HandleCount: 270.
   Image: svchost.exe

PROCESS ffb34620  SessionId: 0  Cid: 040c   Peb: 7ffdf000  ParentCid: 01f0
   DirBase: 0adb3000  ObjectTable: e176df38  HandleCount: 156.
   Image: inetinfo.exe

PROCESS ffb2c020  SessionId: 0  Cid: 0434   Peb: 7ffdf000  ParentCid: 01f0
   DirBase: 0ab79000  ObjectTable: e168a218  HandleCount:  45.
   Image: VMwareService.exe

PROCESS ff9e2d88  SessionId: 0  Cid: 0500   Peb: 7ffdf000  ParentCid: 01f0
   DirBase: 09d6c000  ObjectTable: e1879210  HandleCount: 136.
   Image: svchost.exe

切换到lsass的进程空间,然后在明文密码的起始位置设一个内存读写断点。

kd> .context 03343000
WARNING: .cache forcedecodeuser is not enabled

我的虚拟机上,密码总是从0x002b5cd0开始。

kd> ba r2 /p 80d91550 002b5cd0
kd> g

然后登陆,过一会就到断到了。

Breakpoint 0 hit
001b:77d7d9a9 f3a5      rep    movsd

重新加载symbol

kd> .reload
Connected to Windows Server 2003 3790 x86 compatible target, ptr64 FALSE
Loading Kernel Symbols
..............................................................................................
Loading unloaded module list
..
Loading User Symbols
...........................................................

看一下寄存器

kd> r
eax=00000000 ebx=00000010 ecx=00000003 edx=00000010 esi=00082014 edi=002b5cd4
eip=77d7d9a9 esp=00b3faac ebp=002b5cb8 iopl=0      nv up ei pl nz ac pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000         efl=00000212
ADVAPI32!MD4Update+0x113:
001b:77d7d9a9 f3a5     rep  movsd ds:00082014=006b0068 es:002b5cd4=00000000

中断在一个串传送指令上。因为此时该指令已经执行过一次了,所以源地址是esi-4

kd> du esi-4
00082010  "ph4nt0m!.."   <-- 看到密码了

密码从哪里来的?当然是作为参数传递进来的,查一下堆栈。

kd> kb
ChildEBP RetAddr  Args to Child
00b3fab8 76624d61 00000000 00082010 00000010 ADVAPI32!MD4Update+0x113
00b3fac8 766258de 002b5cb8 00000010 00082010 cryptdll!md4Sum+0x11
00b3fae4 71c388be 00b3fb00 00081ff8 00093b60 cryptdll!rc4HmacHashPassword+0x3e
00b3fb0c 71c189c7 00b3fd74 00b3fb94 00000017 kerberos!_imp__lstrlenA <PERF> (kerberos+0x388be)
00b3fbb0 71c09d1c 00b3fd74 0000009c 00093aa0 kerberos!KerbCreateEmptyContext+0xd
00b3fbec 71c2bbd0 00000000 00b3fd6c 00b3fd74 kerberos!KerbGetTgsTicket+0x477
00b3fc1c 71c1f34b 00093a40 00b3fd64 00b3fd6c kerberos!KRB5_Module_Startup+0xa886
00b3fc70 7423d44a 00000002 000cf1b8 00b3fd5c kerberos!KerbQueryTicketCache+0x231
00b3fcc4 74246b56 00000002 000cf1b8 00b3fd5c LSASRV!LsaIAuditAccountLogon+0x15b
00b3fd00 7421f583 00000002 000cf1b8 006110f8 LSASRV!LsarSetInformationTrustedDomain+0x2
00b3fe74 74236843 00b3fe8c 005f8e98 00000000 LSASRV!NegHandleClientRequest+0x523
00b3fe84 74208cbf 00602270 00625ce8 005f8e98 LSASRV!LsapCaptureSamInfo+0x84
00000000 00000000 00000000 00000000 00000000 LSASRV!NegpAcquireCredHandle+0x20e

可以看到,ADVAPI32!MD4Update第二个参数0x00082010正是密码的源地址,后面的0x10则是密码长度。
注意到cryptdll!md4Sum也有同样的参数,只是顺序不同,它的第一个参数0x002b5cb8什么意思呢?

kd> dd 002b5cb8
002b5cb8  67452301 efcdab89 98badcfe 10325476  <-- 一串很有规律的值
002b5cc8  00000080 00000000 00340035 00000000
002b5cd8  00000000 00000000 00000000 00000000
002b5ce8  00000000 00000000 00000000 00000000
002b5cf8  00000000 00000000 00000000 00000000
002b5d08  00000000 00000000 e0cfd631 31e96ad1
002b5d18  d7593cb7 c089c0e0 000e0013 000c0182
002b5d28  00000344 ffffffff 00000000 00000000

结合函数名md4Sum和MD4Update,我们很容易知道,那串有规律的值其实是MD4算法要求的hash初始值。
继续查看各个函数的入口参数,我们还能发现一些有趣的东西。

kd> dS 00b3fb00
00082010  "ph4nt0m!"
kd> dS 00b3fd74
00082010  "ph4nt0m!"
kd> dS 000cf1b8
01284660  "Administrator"

用户名和密码的源头一直可以追溯到LSASRV!NegHandleClientRequest。而真正的源头则是winlogon,它通过LPC将用户在登陆界面输入的内容传递给lsass。但是,这些都不是我们关心的。既然lsass内存里只能找到一处明文密码,那就说明这些源密码、源源密码最后都被清零了。我们只关心那个串操作的目的地址是怎么来的。这需要反汇编ADVAPI32!MD4Update。先把经过分析后的函数原型写出来:

void MD4Update(MDstruct *pMD4, WCHAR *pPassword, ULONG PassLeng);

其中第一个参数pMD4是个结构指针,指向下面这个结构。
typedef _MD4 {
   ULONG Buffer[0]; // = 0x67452301;      // Initial values for MD4
   ULONG Buffer[1]; // = 0xefcdab89;
   ULONG Buffer[2]; // = 0x98badcfe;
   ULONG Buffer[3]; // = 0x10325476;
   LARGE_INTEGER Count; // by bit
   WCAHR String[32];
   USHORT Hash[16];
} MD4, *pMD4

这个结构是参考了RFC1186中MD4的数据结构MDstruct,再加上后面的分析得出的。

下面来看MD4Update。

kd> u ADVAPI32!MD4Update L40
ADVAPI32!MD4Update:
77d7d93a 53          push   ebx
77d7d93b 8b5c2410      mov    ebx,[esp+0x10]      ;ebx=PassLeng (by byte)
77d7d93f 55          push   ebp
77d7d940 8b6c240c      mov    ebp,[esp+0xc]       ;ebp=pMD4
77d7d944 8b4d10        mov    ecx,[ebp+0x10]      ;ecx=pMD4->Count.LowPart (by bit)
77d7d947 8bc1         mov    eax,ecx
77d7d949 c1e803        shr    eax,0x3           ;eax=pMD4->Count.LowPart/8 (by byte)
77d7d94c 8d0cd9        lea    ecx,[ecx+ebx*8]      ;ecx+=PassLeng*8
77d7d94f 83e03f        and    eax,0x3f          ;eax%=64
77d7d952 8d14dd00000000  lea    edx,[00000000+ebx*8]  ;edx=PassLeng*8
77d7d959 3bca         cmp    ecx,edx
77d7d95b 56          push   esi
77d7d95c 57          push   edi
77d7d95d 89442414      mov    [esp+0x14],eax      ;pMD4=eax
77d7d961 894d10        mov    [ebp+0x10],ecx      ;pMD4->Count.LowPart+=PassLeng*8
77d7d964 0f82437e0100    jb    ADVAPI32!MD4Update+0x2c (77d957ad)
77d7d96a 8b5514        mov    edx,[ebp+0x14]      ;edx=pMD4->Count.HighPart (by bit)
77d7d96d 8bcb         mov    ecx,ebx
77d7d96f c1e91d        shr    ecx,0x1d          ;ecx=edx/0x20000000
77d7d972 03d1         add    edx,ecx           ;edx=PassLeng*8+edx/0x20000000
77d7d974 85c0         test   eax,eax           ;第一次调用时pMD4->Count为0,所以此时eax为0
77d7d976 895514        mov    [ebp+0x14],edx      ;pMD4->Count.HighPart=edx
77d7d979 0f8761ffffff    jnbe   ADVAPI32!MD4Update+0x40 (77d7d8e0)
77d7d97f f644241803     test   byte ptr [esp+0x18],0x3;检测pPassword是否4K对齐
77d7d984 0f85f3f8ffff    jne    ADVAPI32!MD4Update+0x96 (77d7d27d)
77d7d98a 83fb40        cmp    ebx,0x40          ;PassLeng>64则跳转
77d7d98d 7325         jnb    ADVAPI32!MD4Update+0xdb (77d7d9b4)
77d7d98f 85db         test   ebx,ebx           ;PassLeng!=0则跳转
77d7d991 7507         jnz    ADVAPI32!MD4Update+0x104 (77d7d99a)
77d7d993 5f          pop    edi
77d7d994 5e          pop    esi
77d7d995 5d          pop    ebp
77d7d996 5b          pop    ebx
77d7d997 c20c00        ret    0xc
77d7d99a 8b742418      mov    esi,[esp+0x18]      ;esi=pPassword <-跳到这里
77d7d99e 8bcb         mov    ecx,ebx           ;ecx=PassLeng
77d7d9a0 8bd1         mov    edx,ecx
77d7d9a2 c1e902        shr    ecx,0x2
77d7d9a5 8d7c2818      lea    edi,[eax+ebp+0x18]    ;edi=pMD4->String
77d7d9a9 f3a5         rep    movsd            ;memcpy(pMD4->String, pPassword, PassLeng)
77d7d9ab 8bca         mov    ecx,edx
77d7d9ad 83e103        and    ecx,0x3
77d7d9b0 f3a4         rep    movsb
77d7d9b2 ebdf         jmp    ADVAPI32!MD4Update+0x11c (77d7d993)   ;return
77d7d9b4 8bf3         mov    esi,ebx           ;以下处理PassLeng>64的情况,不关心
77d7d9b6 c1ee06        shr    esi,0x6
77d7d9b9 8b442418      mov    eax,[esp+0x18]
77d7d9bd 50          push   eax
77d7d9be 55          push   ebp
77d7d9bf e8b3faffff     call   ADVAPI32!MD4Transform (77d7d477)
77d7d9c4 8b542418      mov    edx,[esp+0x18]
77d7d9c8 83c240        add    edx,0x40
77d7d9cb 83eb40        sub    ebx,0x40
77d7d9ce 4e          dec    esi
77d7d9cf 89542418      mov    [esp+0x18],edx
77d7d9d3 75e4         jnz    ADVAPI32!MD4Update+0xe0 (77d7d9b9)
77d7d9d5 8b442414      mov    eax,[esp+0x14]
77d7d9d9 ebb4         jmp    ADVAPI32!MD4Update+0x100 (77d7d98f)
77d7d9db 90          nop
77d7d9dc 90          nop
77d7d9dd 90          nop
77d7d9de 90          nop
77d7d9df 90          nop
ADVAPI32!MD5Init:
77d7d9e0 8b442404      mov    eax,[esp+0x4]

现在知道,我们看到的明文密码是pMD4的一部分:pMD4->String。那么pMD4从哪里来的?
继续往前追。

kd> u cryptdll!md4Sum
cryptdll!md4Sum:
76624d50 ff742408      push   dword ptr [esp+0x8]
76624d54 ff742410      push   dword ptr [esp+0x10]
76624d58 ff74240c      push   dword ptr [esp+0xc]
76624d5c e89f100000     call   cryptdll!MD4Update (76625e00)
76624d61 33c0         xor    eax,eax
76624d63 c20c00        ret    0xc
cryptdll!md4Finalize:
76624d66 90          nop
76624d67 90          nop

md4Sum果然只是换了一下参数位置而已。函数原型:

BOOL md4Sum(MDstruct *pMD4, ULONG PassLeng, WCHAR *pPassword);

前面已经知道rc4HmacHashPassword的第一个参数是个PUNICODE_STRING,指向源密码。
分析后的函数原型:

NTSTATUS rc4HmacHashPassword(PUNICODE_STRING uPassword, USHORT *pHash);

kd> u cryptdll!rc4HmacHashPassword L30
cryptdll!rc4HmacHashPassword:
766258a0 55          push   ebp
766258a1 8bec         mov    ebp,esp
766258a3 51          push   ecx            ;居然是__fastcall
766258a4 51          push   ecx
766258a5 8d45fc        lea    eax,[ebp-0x4]      ;得先分析CDLocateCheckSum才知道ebp-0x4是什么
766258a8 50          push   eax
766258a9 6a02         push   0x2
766258ab e890b8ffff     call   cryptdll!CDLocateCheckSum (76621140)
766258b0 85c0         test   eax,eax
766258b2 7d07         jge   cryptdll!rc4HmacHashPassword+0x1b (766258bb)
766258b4 b842030880     mov    eax,0x80080342
766258b9 eb3b         jmp   cryptdll!rc4HmacHashPassword+0x56 (766258f6)
766258bb 8d45f8        lea    eax,[ebp-0x8]      ;ebp-0x8也有待后面分析
766258be 50          push   eax
766258bf 8b45fc        mov    eax,[ebp-0x4]
766258c2 6a00         push   0x0
766258c4 ff500c        call   dword ptr [eax+0xc]
766258c7 85c0         test   eax,eax
766258c9 7c2b         jl    cryptdll!rc4HmacHashPassword+0x56 (766258f6)
766258cb 8b4508        mov    eax,[ebp+0x8]
766258ce ff7004        push   dword ptr [eax+0x4]  ;push uPassword->Buffer
766258d1 0fb700        movzx  eax,word ptr [eax]
766258d4 50          push   eax            ;push uPassword->Length
766258d5 ff75f8        push   dword ptr [ebp-0x8]  ;这个就是密码缓存的地址,位置待定
766258d8 8b45fc        mov    eax,[ebp-0x4]
766258db ff5010        call   dword ptr [eax+0x10] ;在这里call cryptdll!md4Sum
766258de ff750c        push   dword ptr [ebp+0xc]
766258e1 8b45fc        mov    eax,[ebp-0x4]
766258e4 ff75f8        push   dword ptr [ebp-0x8]
766258e7 ff5014        call   dword ptr [eax+0x14]
766258ea 8d45f8        lea    eax,[ebp-0x8]
766258ed 50          push   eax
766258ee 8b45fc        mov    eax,[ebp-0x4]
766258f1 ff5018        call   dword ptr [eax+0x18]
766258f4 33c0         xor    eax,eax
766258f6 c9          leave
766258f7 c20800        ret    0x8
766258fa 90          nop
766258fb 90          nop
766258fc 90          nop
766258fd 90          nop
766258fe 90          nop
766258ff 90          nop
76625900 90          nop
76625901 90          nop
76625902 90          nop
76625903 90          nop
76625904 90          nop

在搞清楚CDLocateCheckSum前,一切都不明朗。先说结论:

NTSTATUS CDLocateCheckSum(ULONG Type, PCHECK_SUM *ppChechSum);

根据所给的Type,在一组CHECK_SUM中找到需要的那个,返回其指针。

kd> u cryptdll!CDLocateCheckSum L20
cryptdll!CDLocateCheckSum:
76621140 a190806276     mov    eax,[cryptdll!cCheckSums (76628090)] ;eax=0x0000000f
76621145 85c0         test   eax,eax
76621147 7431         jz    cryptdll!CDLocateCheckSum+0x23 (7662117a)
76621149 8d0cc0        lea    ecx,[eax+eax*8]      ;结构大小=0xf*9=0x24
7662114c 8d0c8da0806276  lea    ecx,[cryptdll!CheckSumFns (766280a0)+ecx*4] ;ecx指向_CHECK_SUM
76621153 83e924        sub    ecx,0x24          ;结构指针自减
76621156 8b11         mov    edx,[ecx]          ;获取CheckSums的类型?
76621158 48          dec    eax              ;那么eax(初值0xf)就是CHECK_SUM的总数
76621159 3b542404      cmp    edx,[esp+0x4]       ;查找类型2?
7662115d 7406         jz    cryptdll!CDLocateCheckSum+0x2b (76621165)
7662115f 85c0         test   eax,eax
76621161 7417         jz    cryptdll!CDLocateCheckSum+0x23 (7662117a)
76621163 ebee         jmp    cryptdll!CDLocateCheckSum+0x13 (76621153) ;循环
76621165 8b4c2408      mov    ecx,[esp+0x8]
76621169 8d04c0        lea    eax,[eax+eax*8]      ;根据循环变量定位结构头
7662116c 8d0485a0806276  lea    eax,[cryptdll!CheckSumFns (766280a0)+eax*4]
76621173 8901         mov    [ecx],eax          ;返回结构指针
76621175 33c0         xor    eax,eax
76621177 c20800        ret    0x8
7662117a b842030880     mov    eax,0x80080342
7662117f ebf6         jmp    cryptdll!CDLocateCheckSum+0x28 (76621177)
76621181 90          nop
76621182 90          nop
76621183 90          nop
76621184 90          nop
76621185 90          nop
76621186 90          nop
76621187 90          nop
76621188 90          nop
76621189 90          nop
7662118a 90          nop
7662118b 90          nop
kd> dd 76628090 L1
76628090  0000000f

看一下CHECK_SUM究竟有什么:

kd> dd cryptdll!CheckSumFns L40
766280a0  ffffff77 00000010 00000002 76624ed0
766280b0  76621110 76621690 766213f0 76621bf0
766280c0  00000000 ffffff76 00000010 00000002
766280d0  76624ed0 76621110 76621690 766213f0
766280e0  76621840 00000000 00000002 00000010
766280f0  00000000 76624cf0 76624d50 76624d80
76628100  766211f0 76624d30 00000000 00000007
76628110  00000010 00000000 76621220 76621110
76628120  76621260 766211f0 76621bd0 00000000
76628130  00000001 00000004 00000000 76625aa0
76628140  76625980 76625b10 766211f0 76625b60
76628150  00000000 ffffff7a 00000008 00000002
76628160  76624ed0 76625040 76624f60 76624fb0
76628170  76624ef0 00000000 ffffff79 00000008
76628180  00000002 76624ed0 76621110 76624ea0
76628190  766213f0 76624db0 00000000 ffffff7b
kd> u 76624cf0
cryptdll!md4Initialize:
76624cf0 56          push   esi
76624cf1 6a68         push   0x68
76624cf3 ff156c106276    call  dword ptr [cryptdll!_imp__malloc (7662106c)]
76624cf9 8bf0         mov    esi,eax
76624cfb 85f6         test   esi,esi
76624cfd 59          pop    ecx
76624cfe 7507         jnz    cryptdll!md4Initialize+0x17 (76624d07)
76624d00 b8170000c0     mov    eax,0xc0000017
kd> u 76624d50
cryptdll!md4Sum:
76624d50 ff742408      push   dword ptr [esp+0x8]
76624d54 ff742410      push   dword ptr [esp+0x10]
76624d58 ff74240c      push   dword ptr [esp+0xc]
76624d5c e89f100000     call   cryptdll!MD4Update (76625e00)
76624d61 33c0         xor    eax,eax
76624d63 c20c00        ret    0xc
cryptdll!md4Finalize:
76624d66 90          nop
76624d67 90          nop
kd> u 76624d80
cryptdll!md4Finalize:
76624d80 56          push   esi
76624d81 8b742408      mov    esi,[esp+0x8]
76624d85 57          push   edi
76624d86 56          push   esi
76624d87 e894100000     call   cryptdll!MD4Final (76625e20)
76624d8c 8b7c2410      mov    edi,[esp+0x10]
76624d90 83c658        add    esi,0x58
76624d93 a5          movsd
kd> u 766211f0
cryptdll!md4Finish:
766211f0 56          push   esi
766211f1 8b742408      mov    esi,[esp+0x8]
766211f5 ff36         push   dword ptr [esi]
766211f7 ff1570106276    call   dword ptr [cryptdll!_imp__free (76621070)]
766211fd 832600        and    dword ptr [esi],0x0
76621200 59          pop    ecx
76621201 33c0         xor    eax,eax
76621203 5e          pop    esi
kd> u 76624d30
cryptdll!md4InitializeEx:
76624d30 ff742410      push   dword ptr [esp+0x10]
76624d34 6a00         push   0x0
76624d36 e8b5ffffff     call   cryptdll!md4Initialize (76624cf0)
76624d3b c21000        ret    0x10
cryptdll!md4Sum:
76624d3e 90          nop
76624d3f 90          nop
76624d40 90          nop
76624d41 90          nop

原来是这样:
trpedef _CHECK_SUM {
   DWORD Type;           //??
   ULONG Unknow1;
   ULONG Unknoe2;
   PVOID Function[5];
   ULONG Unknow3;      // 总是0?
}

对于Type==2的情况,Function[5]分别指向:
cryptdll!md4Initialize
cryptdll!md4Sum
cryptdll!md4Finalize
cryptdll!md4Finish
cryptdll!md4InitializeEx

再回到rc4HmacHashPassword。

kd> u cryptdll!rc4HmacHashPassword L30
cryptdll!rc4HmacHashPassword:
766258a0 55          push   ebp
766258a1 8bec         mov    ebp,esp
766258a3 51          push   ecx
766258a4 51          push   ecx
766258a5 8d45fc        lea    eax,[ebp-0x4]      ;ebp-0x4是结构指针地址&pChechSum
766258a8 50          push   eax
766258a9 6a02         push   0x2            ;查找类型2的CHECK_SUM
766258ab e890b8ffff     call   cryptdll!CDLocateCheckSum (76621140) ;CDLocateCheckSum(2,&pChechSum)
766258b0 85c0         test   eax,eax
766258b2 7d07         jge   cryptdll!rc4HmacHashPassword+0x1b (766258bb)
766258b4 b842030880     mov    eax,0x80080342
766258b9 eb3b         jmp   cryptdll!rc4HmacHashPassword+0x56 (766258f6)
766258bb 8d45f8        lea    eax,[ebp-0x8]      ;ebp-0x8=&pMD4
766258be 50          push   eax            ;push &pMD4
766258bf 8b45fc        mov    eax,[ebp-0x4]      ;eax=pChechSum
766258c2 6a00         push   0x0
766258c4 ff500c        call   dword ptr [eax+0xc]  ;md4Initialize(0,&pMD4)
766258c7 85c0         test   eax,eax
766258c9 7c2b         jl    cryptdll!rc4HmacHashPassword+0x56 (766258f6)
766258cb 8b4508        mov    eax,[ebp+0x8]
766258ce ff7004        push   dword ptr [eax+0x4]  ;push uPassword->Buffer (pPassword)
766258d1 0fb700        movzx  eax,word ptr [eax]
766258d4 50          push   eax            ;push uPassword->Length (PassLeng)
766258d5 ff75f8        push   dword ptr [ebp-0x8]  ;现在知道pMD4由md4Initialize决定
766258d8 8b45fc        mov    eax,[ebp-0x4]
766258db ff5010        call   dword ptr [eax+0x10] ;md4Sum(pMD4,PassLeng,pPassword)
766258de ff750c        push   dword ptr [ebp+0xc]
766258e1 8b45fc        mov    eax,[ebp-0x4]
766258e4 ff75f8        push   dword ptr [ebp-0x8]
766258e7 ff5014        call   dword ptr [eax+0x14] ;md4Finalize(pMD4,pHash)
766258ea 8d45f8        lea    eax,[ebp-0x8]
766258ed 50          push   eax
766258ee 8b45fc        mov    eax,[ebp-0x4]
766258f1 ff5018        call   dword ptr [eax+0x18] ;md4Finish(&pMD4)
766258f4 33c0         xor    eax,eax
766258f6 c9          leave
766258f7 c20800        ret    0x8
766258fa 90          nop
766258fb 90          nop
766258fc 90          nop
766258fd 90          nop
766258fe 90          nop
766258ff 90          nop
76625900 90          nop
76625901 90          nop
76625902 90          nop
76625903 90          nop
76625904 90          nop

再看md4Initialize:

kd> u cryptdll!md4Initialize L10
cryptdll!md4Initialize:
76624cf0 56          push   esi
76624cf1 6a68         push   0x68
76624cf3 ff156c106276    call  dword ptr [cryptdll!_imp__malloc (7662106c)]
76624cf9 8bf0         mov    esi,eax          ;pMD4=malloc(0x68)
76624cfb 85f6         test   esi,esi
76624cfd 59          pop    ecx
76624cfe 7507         jnz    cryptdll!md4Initialize+0x17 (76624d07)
76624d00 b8170000c0     mov    eax,0xc0000017
76624d05 eb0e         jmp    cryptdll!md4Initialize+0x25 (76624d15)
76624d07 56          push   esi
76624d08 e8d3100000     call   cryptdll!MD4Init (76625de0) ;MD4Init(pMD4)
76624d0d 8b44240c      mov    eax,[esp+0xc]
76624d11 8930         mov    [eax],esi
76624d13 33c0         xor    eax,eax
76624d15 5e          pop    esi
76624d16 c20800        ret    0x8

搞了半天,pMD4(包括其中的密码缓存)是由malloc分配的。这下没戏了,根本无法确定它的位置。
这一点其实用脚趾头想想也知道,但非要亲眼所见才死心。 ^_^

还有最后一线“希望”——希望lsass把密码留着别释放。

md4Initialize(0,&pMD4);
md4Sum(pMD4,PassLeng,pPassword);
之后是
md4Finalize(pMD4,pHash);

kd> u cryptdll!md4Finalize L10
cryptdll!md4Finalize:
76624d80 56          push   esi
76624d81 8b742408      mov    esi,[esp+0x8]
76624d85 57          push   edi
76624d86 56          push   esi
76624d87 e894100000     call   cryptdll!MD4Final (76625e20) ;MD4Final(pMD4)
76624d8c 8b7c2410      mov    edi,[esp+0x10]
76624d90 83c658        add    esi,0x58      ;esi=pMD4->Hash
76624d93 a5          movsd             ;memcpy(pHash,pMD4->Hash,16)
76624d94 a5          movsd
76624d95 a5          movsd
76624d96 a5          movsd
76624d97 5f          pop    edi
76624d98 33c0         xor    eax,eax
76624d9a 5e          pop    esi
76624d9b c20800        ret    0x8
cryptdll!md4Finish:
76624d9e 90          nop

md4Finalize调用MD4Final:

kd> u cryptdll!MD4Final
cryptdll!MD4Final:
76625e20 ff2550106276    jmp  dword ptr [cryptdll!_imp__MD4Final (76621050)]

转到_imp__MD4Final:

kd> dd cryptdll!_imp__MD4Final L1
76621050  77d7d3f3
kd> u 77d7d3f3 L35
ADVAPI32!MD4Final:
77d7d3f3 83ec48        sub    esp,0x48
77d7d3f6 53          push   ebx
77d7d3f7 55          push   ebp
77d7d3f8 56          push   esi
77d7d3f9 8b742458      mov    esi,[esp+0x58]      ;esi=pMD4
77d7d3fd 8b4610        mov    eax,[esi+0x10]      ;eax=pMD4->Count.LowPart
77d7d400 8b4e14        mov    ecx,[esi+0x14]      ;ecx=pMD4->Count.HighPart
77d7d403 8d5e58        lea    ebx,[esi+0x58]      ;ebx=pMD4->Hash
77d7d406 8903         mov    [ebx],eax         ;下面是一些算法的操作,不关心
77d7d408 c1e803        shr    eax,0x3          ;盯紧esi(=pMD4)就是了
77d7d40b 83e03f        and    eax,0x3f
77d7d40e 83f838        cmp    eax,0x38
77d7d411 57          push   edi
77d7d412 894e5c        mov    [esi+0x5c],ecx
77d7d415 ba38000000     mov    edx,0x38
77d7d41a 0f83d3830100    jnb    ADVAPI32!MD4Final+0x29 (77d957f3)
77d7d420 2bd0         sub    edx,eax
77d7d422 8bca         mov    ecx,edx
77d7d424 8be9         mov    ebp,ecx
77d7d426 c1e902        shr    ecx,0x2
77d7d429 33c0         xor    eax,eax
77d7d42b 8d7c2410      lea    edi,[esp+0x10]
77d7d42f f3ab         rep    stosd
77d7d431 52          push   edx
77d7d432 8d542414      lea    edx,[esp+0x14]
77d7d436 8bcd         mov    ecx,ebp
77d7d438 83e103        and    ecx,0x3
77d7d43b 52          push   edx
77d7d43c f3aa         rep    stosb
77d7d43e 56          push   esi
77d7d43f c644241c80     mov    byte ptr [esp+0x1c],0x80
77d7d444 e8f1040000     call   ADVAPI32!MD4Update (77d7d93a)
77d7d449 6a08         push   0x8
77d7d44b 53          push   ebx
77d7d44c 56          push   esi
77d7d44d e8e8040000     call   ADVAPI32!MD4Update (77d7d93a)
77d7d452 8b06         mov    eax,[esi]
77d7d454 8b4e04        mov    ecx,[esi+0x4]
77d7d457 8b5608        mov    edx,[esi+0x8]
77d7d45a 8903         mov    [ebx],eax
77d7d45c 8b460c        mov    eax,[esi+0xc]
77d7d45f 5f          pop    edi
77d7d460 894e5c        mov    [esi+0x5c],ecx
77d7d463 895660        mov    [esi+0x60],edx
77d7d466 894664        mov    [esi+0x64],eax
77d7d469 5e          pop    esi
77d7d46a 5d          pop    ebp
77d7d46b 5b          pop    ebx
77d7d46c 83c448        add    esp,0x48
77d7d46f c20400        ret    0x4
ADVAPI32!MD5Init:
77d7d472 90          nop
77d7d473 90          nop
77d7d474 90          nop

咦,怎么没释放?别高兴的太早,下面还有md4Finish呢!
md4Finish(&pMD4);

kd> u cryptdll!md4Finish L10
cryptdll!md4Finish:
766211f0 56          push   esi
766211f1 8b742408      mov    esi,[esp+0x8]
766211f5 ff36         push   dword ptr [esi]
766211f7 ff1570106276    call   dword ptr [cryptdll!_imp__free (76621070)] ;free(pMD4)
766211fd 832600        and    dword ptr [esi],0x0      ;pMD4=NULL
76621200 59          pop    ecx
76621201 33c0         xor    eax,eax
76621203 5e          pop    esi
76621204 c20400        ret    0x4
cryptdll!md5Initialize:
76621207 90          nop
76621208 90          nop
76621209 90          nop
7662120a 90          nop
7662120b 90          nop
7662120c 90          nop
7662120d 90          nop

彻底没戏啦。pMD4连同里面的明文密码被free了。

我不知道关于lsass留着明文密码备用的说法究竟是不是可靠的,至少我们看到的那个确实被free了。
如果说,前面提到的多个“源密码”中的某一个被lsass留着,那就不应该搜索不到。要么密码不是明文的。

结论很明显,在lsass里找明文密码属于RP问题。如果它已经被覆盖,就算你用什么模拟登陆的方法确定它的位置,也是回天乏术。如果没有被覆盖,用WinEggDrop的办法找密码已经足够了。

我再加一个判断条件:密码前面的2个ULONG总是0x00000200和0x00000000。它们就是pMD4->Count的LowPart和HighPart,用于保存被加密数据的bit数。MD4加密以64字节(0x200 bit)为最小单位,密码不超过32个字符的话,一轮加密就完了,所以它们总是0x200和0x0。这个条件可以在密码被覆盖时减少误报。

以上。
益友网吧联盟  http://www.96-7.com

TOP

发新话题