Quantcast
Channel: 看雪安全论坛
Viewing all articles
Browse latest Browse all 9556

【原创】【原创】【原创】缓冲区溢出一例 __security_cookie

$
0
0
虽然来看雪很长时间了,但是这次是本菜鸟第一次在看雪发文章,还望各位高手前辈多多指教:):。本文记录一次崩溃的分析过程,旨在知识分享,别无它用。进入正题,前段时间一直在学习用windbg,看《软件调试》这本书,知道在xp下也有自带的一个调试器 – ntsd.exe。于是乎用ntsd绑住了notepad,然后!peb,结果ntsd就崩溃了,试了几次都是如此。我就纳闷了,难道我的ntsd用不了,不对啊,其它命令都没问题。想想这时该是windbg出场了!在ntsd绑住了notepad后,用windbg绑住ntsd,在ntsd上输入命令!peb,回车,windbg停了下来,kb如下:

代码:

0:000> kb
ChildEBP RetAddr  Args to Child              
00077d58 7c92de7a 7c801e3a ffffffff 00000502 ntdll!KiFastSystemCallRet
00077d5c 7c801e3a ffffffff 00000502 000780b0 ntdll!NtTerminateProcess+0xc
00077d6c 68d89648 ffffffff 00000502 0031c158 kernel32!TerminateProcess+0x20
000780b0 68d7295d 00b84f20 00000000 00000000 DBGHELP!__report_gsfailure+0xf5
0007871c 68d75677 003f0500 003f096c 003f095c DBGHELP!diaLocatePdb+0x758
00078860 68d7b54e 003f0500 003d2a90 003b14a0 DBGHELP!diaOpenPdb+0x239
00078894 68d816f7 0000078c 0000076c 003d2a90 DBGHELP!GetDebugData+0x27d
00078a00 68d81de4 0000078c 003d1b60 68d7c94e DBGHELP!load+0xa5
00078c70 68d7cd2f 0000078c 00079dbc 00079d9c DBGHELP!InternalLoadModule+0xb6
00078cc4 68d7cd86 0000078c 00000000 00079dbc DBGHELP!SymLoadModuleEx+0x30
00078cf0 6d9ac52d 0000078c 00000000 00079dbc DBGHELP!SymLoadModule64+0x23
0007a0d4 6d9ac6e6 0000078c 00000000 0007a97c dbgeng!TypeInfoFound+0x4cc
0007a94c 6d9adbb3 0007a97c 0007aa0c 0007a9ac dbgeng!SymbolTypeDumpNew+0x60
0007a960 6d9adc98 0007a97c 0007aa0c 00000000 dbgeng!FastSymbolTypeDump+0x7e
0007a9e8 6d970b73 0000078c 0031a9f0 0007aa30 dbgeng!SymbolTypeDump+0xb3
0007aa14 6979ca77 00000016 0007aa30 00000030 dbgeng!ExtIoctl+0x3e7
0007aa80 697a7d15 7ffde000 00000000 69793de0 exts!GetShortField+0xb2
0007ab50 697a816a 7ffde000 00000000 00000000 exts!DumpPeb+0x3ea
0007ab80 6d96f09d 00314a94 0007ad2f 0007ad2f exts!peb+0xdb
0007abd0 6d96fa2b 00314a90 00314de8 0007ad2c dbgeng!CallExtension+0x15d

从调用堆栈中来看,ntsd此时是在找符号文件,而且看来是干了坏事弹个报告错误的框就要走人了。看下DBGHELP!diaLocatePdb+0x758前面是在干什么

0
代码:

:000> ub DBGHELP!diaLocatePdb+0x758 L5
DBGHELP!diaLocatePdb+0x74d:
68d72952 8b4dfc          mov     ecx,dword ptr [ebp-4]
68d72955 5f              pop     edi
68d72956 5e              pop     esi
68d72957 5b              pop     ebx
68d72958 e8db6b0100      call    DBGHELP!__security_check_cookie (68d89538)

结果又发现了__security_check_cookie,之前也遇到由这个函数报告出来的异常,那时的做法是通过屏蔽代码,最后才辛辛苦苦找出了导致异常崩溃的源头。这次又遇到了,一次代码屏蔽都那么辛苦,以后还遇到的话,这日子咋过了。恰巧,前几天也在看雪看到了一篇说到这个__security_check_cookie的问题,原理主要是在函数的开始调用过程时将__security_cookie的值保存到局部变量中,然后在函数退出的时候检查下,比较局部变量中的值相对于__security_cookie是否改变了,是的话,就证明函数在调用过程中不小心改掉了这个局部变量的值,目前我遇到的都是由于缓冲区溢出导致。先来看下这个函数:
代码:

0:000> uf DBGHELP!__security_check_cookie
DBGHELP!__security_check_cookie:
68d89538 3b0dfc25df68    cmp     ecx,dword ptr [DBGHELP!__security_cookie (68df25fc)]  
68d8953e 7509            jne     DBGHELP!__security_check_cookie+0x11 (68d89549)

DBGHELP!__security_check_cookie+0x8:
68d89540 f7c10000ffff    test    ecx,0FFFF0000h
68d89546 7501            jne     DBGHELP!__security_check_cookie+0x11 (68d89549)

DBGHELP!__security_check_cookie+0x10:
68d89548 c3              ret

DBGHELP!__security_check_cookie+0x11:
68d89549 e905000000      jmp     DBGHELP!__report_gsfailure (68d89553)

DBGHELP!__report_gsfailure:
68d89553 8bff            mov     edi,edi
68d89555 55              push    ebp
68d89556 8bec            mov     ebp,esp
68d89558 81ec30030000    sub     esp,330h
68d8955e 57              push    edi
68d8955f 8985d8fdffff    mov     dword ptr [ebp-228h],eax
68d89565 898dd4fdffff    mov     dword ptr [ebp-22Ch],ecx
68d8956b 8995d0fdffff    mov     dword ptr [ebp-230h],edx
68d89571 899dccfdffff    mov     dword ptr [ebp-234h],ebx
68d89577 89b5c8fdffff    mov     dword ptr [ebp-238h],esi
68d8957d 89bdc4fdffff    mov     dword ptr [ebp-23Ch],edi
68d89583 668c95f0fdffff  mov     word ptr [ebp-210h],ss
68d8958a 668c8de4fdffff  mov     word ptr [ebp-21Ch],cs
68d89591 668c9dc0fdffff  mov     word ptr [ebp-240h],ds
68d89598 668c85bcfdffff  mov     word ptr [ebp-244h],es
68d8959f 668ca5b8fdffff  mov     word ptr [ebp-248h],fs
68d895a6 668cadb4fdffff  mov     word ptr [ebp-24Ch],gs
68d895ad 9c              pushfd
68d895ae 8f85e8fdffff    pop     dword ptr [ebp-218h]
68d895b4 c78528fdffff01000100 mov dword ptr [ebp-2D8h],10001h
68d895be 8b4504          mov     eax,dword ptr [ebp+4]
68d895c1 8985e0fdffff    mov     dword ptr [ebp-220h],eax
68d895c7 8d4504          lea     eax,[ebp+4]
68d895ca 8985ecfdffff    mov     dword ptr [ebp-214h],eax
68d895d0 8d4504          lea     eax,[ebp+4]
68d895d3 8b40fc          mov     eax,dword ptr [eax-4]
68d895d6 8985dcfdffff    mov     dword ptr [ebp-224h],eax
68d895dc 6a14            push    14h
68d895de 59              pop     ecx
68d895df 33c0            xor     eax,eax
68d895e1 8dbdd0fcffff    lea     edi,[ebp-330h]
68d895e7 f3ab            rep stos dword ptr es:[edi]
68d895e9 c785d0fcffff090400c0 mov dword ptr [ebp-330h],0C0000409h
68d895f3 8b4504          mov     eax,dword ptr [ebp+4]
68d895f6 8985dcfcffff    mov     dword ptr [ebp-324h],eax
68d895fc 8d85d0fcffff    lea     eax,[ebp-330h]
68d89602 8945f8          mov     dword ptr [ebp-8],eax
68d89605 8d8528fdffff    lea     eax,[ebp-2D8h]
68d8960b 8945fc          mov     dword ptr [ebp-4],eax
68d8960e a1fc25df68      mov     eax,dword ptr [DBGHELP!__security_cookie (68df25fc)]
68d89613 898520fdffff    mov     dword ptr [ebp-2E0h],eax
68d89619 a1f825df68      mov     eax,dword ptr [DBGHELP!__security_cookie_complement (68df25f8)]
68d8961e 898524fdffff    mov     dword ptr [ebp-2DCh],eax
68d89624 6a00            push    0
68d89626 ff156411d668    call    dword ptr [DBGHELP!_imp__SetUnhandledExceptionFilter (68d61164)]
68d8962c 8d45f8          lea     eax,[ebp-8]
68d8962f 50              push    eax
68d89630 ff156011d668    call    dword ptr [DBGHELP!_imp__UnhandledExceptionFilter (68d61160)]
68d89636 6802050000      push    502h
68d8963b ff158010d668    call    dword ptr [DBGHELP!_imp__GetCurrentProcess (68d61080)]
68d89641 50              push    eax
68d89642 ff155c11d668    call    dword ptr [DBGHELP!_imp__TerminateProcess (68d6115c)]
68d89648 5f              pop     edi
68d89649 c9              leave
68d8964a c3              ret

由cmp ecx,dword ptr [DBGHELP!__security_cookie这句可看出,是用ecx的值来做比较,如果发现不同了,就跳到DBGHELP!__report_gsfailure处去处理了,最后就是弹出报告错误的框,确定后就退出进程了。从上可以看出,ecx的值是从外部调用传进来的,即ub DBGHELP!diaLocatePdb+0x758 L5时显示的mov     ecx,dword ptr [ebp-4]这句,看来__security_cookie就保存在ebp-4的地方。反汇编DBGHELP!diaLocatePdb如下:

代码:

0:000> u DBGHELP!diaLocatePdb
DBGHELP!diaLocatePdb:
68d72205 8bff            mov     edi,edi
68d72207 55              push    ebp
68d72208 8bec            mov     ebp,esp
68d7220a 81ec64060000    sub     esp,664h
68d72210 a1fc25df68      mov     eax,dword ptr [DBGHELP!__security_cookie (68df25fc)]
68d72215 8b4d10          mov     ecx,dword ptr [ebp+10h]
68d72218 8b5520          mov     edx,dword ptr [ebp+20h]
68d7221b 8945fc          mov     dword ptr [ebp-4],eax

从上面的反汇编代码证实了之前的猜测,接下来咱们就对dword ptr [ebp-4]这个局部变量的地址设写入断点,看看谁修改了它。
既然在找符号文件,就看看相关的函数在找哪个pdb文件了,我开始定位在DBGHELP!diaLocatePdb,看了下参数,发现DBGHELP!diaLocatePdb的第二个参数是符号文件名称,da 003f096c如下:

代码:

0:000> da 003f096c 
003f096c  "MicrosoftWindowsCommon-Controls-"
003f098c  "6.0.2600.6028-comctl32.pdb"

看来是在找这个pdb的时候ntsd崩溃了。接下来在DBGHELP!diaLocatePdb处下断点,bu DBGHELP!diaLocatePdb "da poi(esp+8);" ,其中poi(esp+8)为第二个参数的值。在重来一次,这时windbg断下了很多次,不过按多几下F5就过去了,直到ntsd在找MicrosoftWindowsCommon-Controls-6.0.2600.6028-comctl32.pdb文件时才停下来。

代码:

省略。。。。。。
003f096c  "oleaut32.pdb"
eax=003f096c ebx=003f0500 ecx=0031c178 edx=00190000 esi=00000000 edi=0031c158
eip=68d72205 esp=00078720 ebp=00078860 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
DBGHELP!diaLocatePdb:
68d72205 8bff            mov     edi,edi
0:000> g
003f096c  "MicrosoftWindowsCommon-Controls-"
003f098c  "6.0.2600.6028-comctl32.pdb"
eax=003f096c ebx=003f0500 ecx=0031c178 edx=001a0000 esi=00000000 edi=0031c158
eip=68d72205 esp=00078720 ebp=00078860 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
DBGHELP!diaLocatePdb:
68d72205 8bff            mov     edi,edi

这时,单步执行汇编语句,直到mov     dword ptr [ebp-4],eax这一句汇编代码,windbg显示如下:

代码:

DBGHELP!diaLocatePdb:
68d72205 8bff            mov     edi,edi
68d72207 55              push    ebp
68d72208 8bec            mov     ebp,esp
68d7220a 81ec64060000    sub     esp,664h
68d72210 a1fc25df68      mov     eax,dword ptr [DBGHELP!__security_cookie (68df25fc)]
68d72215 8b4d10          mov     ecx,dword ptr [ebp+10h]
68d72218 8b5520          mov     edx,dword ptr [ebp+20h]
68d7221b 8945fc          mov     dword ptr [ebp-4],eax ss:0023:00078718=00000001

此时__security_cookie的值为0000f3c7, 看到ebp-4的值为00078718,先F10单步执行一下,然后对00078718该地址下写入断点,ba w4 00078718,F5运行,此时windbg停在DBGHELP!EnsureTrailingBackslash函数里的68d78e61 5e              pop     esi
一句,如下所示:

代码:

DBGHELP!EnsureTrailingBackslash:
68d78e3e 8bff            mov     edi,edi
68d78e40 55              push    ebp
68d78e41 8bec            mov     ebp,esp
68d78e43 56              push    esi
68d78e44 8b7508          mov     esi,dword ptr [ebp+8]
68d78e47 56              push    esi
68d78e48 ff15e810d668    call    dword ptr [DBGHELP!_imp__lstrlenA (68d610e8)]
68d78e4e 85c0            test    eax,eax
68d78e50 740f            je      DBGHELP!EnsureTrailingBackslash+0x23 (68d78e61)
68d78e52 03c6            add     eax,esi
68d78e54 8078ff5c        cmp     byte ptr [eax-1],5Ch
68d78e58 7407            je      DBGHELP!EnsureTrailingBackslash+0x23 (68d78e61)
68d78e5a c6005c          mov     byte ptr [eax],5Ch
68d78e5d c6400100        mov     byte ptr [eax+1],0
68d78e61 5e              pop     esi
68d78e62 5d              pop     ebp
68d78e63 c20400          ret     4

pop     esi这句是cpu接下来要执行的指令,所以导致异常发生的指令就是上一句了,即mov     byte ptr [eax+1],0。此时eax的值为00078717,再加1就是00078718了,这不就是之前保存__security_cookie的局部变量的地址吗!mov     byte ptr [eax+1],0,显然是它修改了之前那个局部变量的值。可是为什么会修改到这个地方呢?接下来继续往下看。
从DBGHELP!EnsureTrailingBackslash的反汇编代码中可以看出该函数主要是给指定的字符串末尾加上反斜杠。此时这个字符串是什么呢?从上面可以看出该字符串的地址是从外部传进来的,而且暂时放在了esi寄存器里面,目前还没有变过。此时da esi如下:

代码:

0:000> da esi
00078614  "C:\WINDOWS\WinSxS\x86_Microsoft."
00078634  "Windows.Common-Controls_6595b641"
00078654  "44ccf1df_6.0.2600.6028_x-ww_61e6"
00078674  "5202\MicrosoftWindowsCommon-Cont"
00078694  "rols-6.0.2600.6028-comctl32.pdb\"
000786b4  "symbols\dll\MicrosoftWindowsComm"
000786d4  "on-Controls-6.0.2600.6028-comctl"
000786f4  "32.pdb\dll\MicrosoftWindowsCommo"
00078714  "n-C\"

这个字符串的长度可以计算下
0:000> ? 00078714 - 00078614
Evaluate expression: 256 = 00000100
256再加上最后一行的四个字符总共是260个字符(不包括空结束符)。那这个从外面传进来的缓冲区有多大呢?此时函数调用堆栈如下:

代码:

0:000> kb
ChildEBP RetAddr  Args to Child              
000780a0 68d72461 00078614 0031c158 00000000 DBGHELP!EnsureTrailingBackslash+0x23
0007871c 68d75677 003f0500 003f096c 003f095c DBGHELP!diaLocatePdb+0x25c
00078860 68d7b54e 003f0500 003d2a90 003b14a0 DBGHELP!diaOpenPdb+0x239
00078894 68d816f7 0000078c 0000076c 003d2a90 DBGHELP!GetDebugData+0x27d
00078a00 68d81de4 0000078c 003d1b60 68d7c94e DBGHELP!load+0xa5
00078c70 68d7cd2f 0000078c 00079dbc 00079d9c DBGHELP!InternalLoadModule+0xb6
00078cc4 68d7cd86 0000078c 00000000 00079dbc DBGHELP!SymLoadModuleEx+0x30
00078cf0 6d9ac52d 0000078c 00000000 00079dbc DBGHELP!SymLoadModule64+0x23
0007a0d4 6d9ac6e6 0000078c 00000000 0007a97c dbgeng!TypeInfoFound+0x4cc
0007a94c 6d9adbb3 0007a97c 0007aa0c 0007a9ac dbgeng!SymbolTypeDumpNew+0x60
0007a960 6d9adc98 0007a97c 0007aa0c 00000000 dbgeng!FastSymbolTypeDump+0x7e
0007a9e8 6d970b73 0000078c 0031a9f0 0007aa30 dbgeng!SymbolTypeDump+0xb3
0007aa14 6979ca77 00000016 0007aa30 00000030 dbgeng!ExtIoctl+0x3e7
0007aa80 697a7d15 7ffd6000 00000000 69793de0 exts!GetShortField+0xb2
0007ab50 697a816a 7ffd6000 00000000 00000000 exts!DumpPeb+0x3ea
0007ab80 6d96f09d 00314a94 0007ad2f 0007ad2f exts!peb+0xdb
0007abd0 6d96fa2b 00314a90 00314de8 0007ad2c dbgeng!CallExtension+0x15d
0007acfc 6d9718ba 00314a90 00314e68 0007ad2c dbgeng!CallAnyExtension+0xb2
0007bd3c 6d98613f 00314a90 0007dedd 00000000 dbgeng!fnBangCmd+0x5a9
0007de8c 6d987077 00314a90 00000000 00000000 dbgeng!ProcessCommands+0x355

看下调用DBGHELP!EnsureTrailingBackslash前的代码,

代码:

0:000> ub DBGHELP!diaLocatePdb+0x25c L5
DBGHELP!diaLocatePdb+0x24a:
68d7244f 50              push    eax
68d72450 e8a2f5ffff      call    DBGHELP!sstrcpy (68d719f7)
68d72455 8d85f8feffff    lea     eax,[ebp-108h]
68d7245b 50              push    eax
68d7245c e8dd690000      call    DBGHELP!EnsureTrailingBackslash (68d78e3e)

从上面可以看到传进来的缓冲区首地址是ebp-108,从ebp-108到ebp-4,这中间的缓冲区大小我们可以计算下:

0:000> ? 108
Evaluate expression: 264 = 00000108
除去保存__security_cookie的那个局部变量的四个字节外,就剩下只能够保存260字符大小的字符串了,前面的那个很长的字符串刚好是260,但是还要加上个结束符,结果就修改了保存__security_cookie的那个局部变量的值,最终造成ntsd崩溃了。此时那个局部变量的值为:

0:000> dd 00078718 L1
00078718  0000f300
之前__security_cookie的值为0000f3c7。至此,终于发现了那个神秘崩溃背后的真相,但是谁来拯救我的ntsd呢?:eek::eek::eek::eek::eek:
  从这次的分析中,可以看到__security_cookie可以很方便的查出问题的所在,以后就不用在遇到这种问题时,辛辛苦苦的屏蔽代码了!也许很多大牛都知道了如何处理__security_cookie的问题了,但这是本菜鸟第一次独立的分析,所以还是贴出来分享下这辛苦中的乐趣吧:eek:。
谢谢看雪论坛中牛人们的无私分享,让我这个菜鸟在看雪的日子里真地学到了很多,最后还要支持下看雪老大,希望看雪越来越好:):。

Viewing all articles
Browse latest Browse all 9556

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>