Author:** k0Sh1** ### 漏洞分析 GNU GTypist是一款Linux下的文本编辑软件,比较尴尬的是在我调试过程中,发现gtypist实际上开启了CNARAY和NX,也就是说,按照PoC给出的Exploit应该是没法利用的,这个应该是一个拒绝服务漏洞,该漏洞是由于当输入的文件路径是一个畸形文件的时候,首先会执行一次strcpy_chk拷贝,这个拷贝过程会因为畸形文件导致程序进入错误处理而退出,下面对此漏洞进行详细分析。 首先gdb运行,直接通过run `python -c 'print "\x41"*4084'`运行,会发现程序中断。 ``` Program received signal SIGABRT, Aborted. [----------------------------------registers-----------------------------------] EAX: 0x0 EBX: 0xb12 ECX: 0xb12 EDX: 0x6 ESI: 0x3e ('>') EDI: 0xb7f56000 --> 0x1a5da8 EBP: 0xbfffb6a8 --> 0xb7f0fdd6 ("buffer overflow detected") ESP: 0xbfffb434 --> 0xbfffb6a8 --> 0xb7f0fdd6 ("buffer overflow detected") EIP: 0xb7fdebe0 (<__kernel_vsyscall+16>:pop ebp) EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0xb7fdebdc <__kernel_vsyscall+12>:nop 0xb7fdebdd <__kernel_vsyscall+13>:nop 0xb7fdebde <__kernel_vsyscall+14>:int 0x80 => 0xb7fdebe0...
Author:** k0Sh1** ### 漏洞分析 GNU GTypist是一款Linux下的文本编辑软件,比较尴尬的是在我调试过程中,发现gtypist实际上开启了CNARAY和NX,也就是说,按照PoC给出的Exploit应该是没法利用的,这个应该是一个拒绝服务漏洞,该漏洞是由于当输入的文件路径是一个畸形文件的时候,首先会执行一次strcpy_chk拷贝,这个拷贝过程会因为畸形文件导致程序进入错误处理而退出,下面对此漏洞进行详细分析。 首先gdb运行,直接通过run `python -c 'print "\x41"*4084'`运行,会发现程序中断。 ``` Program received signal SIGABRT, Aborted. [----------------------------------registers-----------------------------------] EAX: 0x0 EBX: 0xb12 ECX: 0xb12 EDX: 0x6 ESI: 0x3e ('>') EDI: 0xb7f56000 --> 0x1a5da8 EBP: 0xbfffb6a8 --> 0xb7f0fdd6 ("buffer overflow detected") ESP: 0xbfffb434 --> 0xbfffb6a8 --> 0xb7f0fdd6 ("buffer overflow detected") EIP: 0xb7fdebe0 (<__kernel_vsyscall+16>:pop ebp) EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0xb7fdebdc <__kernel_vsyscall+12>:nop 0xb7fdebdd <__kernel_vsyscall+13>:nop 0xb7fdebde <__kernel_vsyscall+14>:int 0x80 => 0xb7fdebe0 <__kernel_vsyscall+16>:pop ebp 0xb7fdebe1 <__kernel_vsyscall+17>:pop edx 0xb7fdebe2 <__kernel_vsyscall+18>:pop ecx 0xb7fdebe3 <__kernel_vsyscall+19>:ret 0xb7fdebe4:int3 [------------------------------------stack-------------------------------------] 0000| 0xbfffb434 --> 0xbfffb6a8 --> 0xb7f0fdd6 ("buffer overflow detected") 0004| 0xbfffb438 --> 0x6 0008| 0xbfffb43c --> 0xb12 0012| 0xbfffb440 --> 0xb7dde307 (<__GI_raise+71>:xchg ebx,edi) 0016| 0xbfffb444 --> 0xb7f56000 --> 0x1a5da8 0020| 0xbfffb448 --> 0xbfffb4e4 ("0 00:00 0 [vvar]\nb7fde000-b7fdf000 r-xp 00000000 00:00 0 [vdso]\nb7fdf000-b7ffe000 r-xp 00000000 08:01 9148\003") 0024| 0xbfffb44c --> 0xb7ddf9c3 (<__GI_abort+323>:mov edx,DWORD PTR gs:0x8) 0028| 0xbfffb450 --> 0x6 [------------------------------------------------------------------------------] Legend: code, data, rodata, value Stopped reason: SIGABRT 0xb7fdebe0 in __kernel_vsyscall () ``` 通过bt回溯堆栈调用情况。 ``` gdb-peda$ bt #0 0xb7fdebe0 in __kernel_vsyscall () #1 0xb7dde307 in __GI_raise (sig=sig@entry=0x6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56 #2 0xb7ddf9c3 in __GI_abort () at abort.c:89 #3 0xb7e1c6f8 in __libc_message (do_abort=do_abort@entry=0x2, fmt=fmt@entry=0xb7f0fe55 "*** %s ***: %s terminated\n") at ../sysdeps/posix/libc_fatal.c:175 #4 0xb7eaa2d5 in __GI___fortify_fail ( msg=msg@entry=0xb7f0fdd6 "buffer overflow detected") at fortify_fail.c:31 #5 0xb7ea838a in __GI___chk_fail () at chk_fail.c:28 #6 0xb7ea7877 in __strcpy_chk (dest=0xbfffd42c 'A' <repeats 200 times>..., src=0xbfffe672 'A' <repeats 200 times>..., destlen=<optimized out>) at strcpy_chk.c:60 #7 0x0804bf30 in ?? () #8 0xb7dc9a63 in __libc_start_main (main=0x8049750, argc=0x2, argv=0xbfffe4f4, init=0x804f330, fini=0x804f3a0, rtld_fini=0xb7fedc90 <_dl_fini>, stack_end=0xbfffe4ec) at libc-start.c:287 #9 0x0804c393 in ?? () ``` 可以看到Linux调用了abort之后程序退出了,在#7位置处于程序领空,随后调用了strcpy_chk函数,该函数的模型如下。 ``` #include <string.h> char * __strcpy_chk(char * dest, const char * src, size_t destlen); ``` 实际上这个函数有点像strcpy_s函数,#8是Linux调用main函数的调用,因此跟踪一下0804bf30位置看一下上下文。 ``` .text:0804BF13 loc_804BF13: ; CODE XREF: .text:0804A49Dj .text:0804BF13 push esi .text:0804BF14 push 1000h .text:0804BF19 push dword ptr [ebx+eax*4] .text:0804BF1C lea eax, [ebp-101Ch] .text:0804BF22 push eax .text:0804BF23 mov ebx, eax .text:0804BF25 mov [ebp-2D1Ch], eax .text:0804BF2B call ___strcpy_chk ``` 0804bf2b位置调用了strcpy_chk,在这里下断看一下。 ``` gdb-peda$ b *0x0804bf2b Breakpoint 1 at 0x804bf2b gdb-peda$ run `python -c 'print "\x41"*4098'` Starting program: /usr/bin/gtypist `python -c 'print "\x41"*4098'` /usr/bin/gtypist: /lib/i386-linux-gnu/libncursesw.so.5: no version information available (required by /usr/bin/gtypist) /usr/bin/gtypist: /lib/i386-linux-gnu/libncursesw.so.5: no version information available (required by /usr/bin/gtypist) /usr/bin/gtypist: /lib/i386-linux-gnu/libtinfo.so.5: no version information available (required by /usr/bin/gtypist) [----------------------------------registers-----------------------------------] EAX: 0xbfffd42c --> 0x0 EBX: 0xbfffd42c --> 0x0 ECX: 0x0 EDX: 0xb7f5617c --> 0x0 ESI: 0x0 EDI: 0xbfffe661 ("/usr/bin/gtypist") EBP: 0xbfffe448 --> 0x0 ESP: 0xbfffb700 --> 0xbfffd42c --> 0x0 EIP: 0x804bf2b (call 0x80495d0 <__strcpy_chk@plt>) EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x804bf22:push eax 0x804bf23:mov ebx,eax 0x804bf25:mov DWORD PTR [ebp-0x2d1c],eax => 0x804bf2b:call 0x80495d0 <__strcpy_chk@plt> 0x804bf30:mov eax,ebx 0x804bf32:call 0x804c5a0 0x804bf37:add esp,0x10 0x804bf3a:test eax,eax Guessed arguments: arg[0]: 0xbfffd42c --> 0x0 arg[1]: 0xbfffe672 ('A' <repeats 200 times>...) arg[2]: 0x1000 arg[3]: 0x0 [------------------------------------stack-------------------------------------] 0000| 0xbfffb700 --> 0xbfffd42c --> 0x0 0004| 0xbfffb704 --> 0xbfffe672 ('A' <repeats 200 times>...) 0008| 0xbfffb708 --> 0x1000 0012| 0xbfffb70c --> 0x0 0016| 0xbfffb710 --> 0x0 0020| 0xbfffb714 --> 0x0 0024| 0xbfffb718 --> 0x0 0028| 0xbfffb71c --> 0x0 [------------------------------------------------------------------------------] Legend: code, data, rodata, value Breakpoint 1, 0x0804bf2b in ?? () ``` 这里拷贝目标地址是bfffd42c,拷贝内容是畸形字符串,拷贝长度是0x1000,也就是畸形字符串长度,这个地方会导致bfffd42c栈溢出,会进入错误处理,那么这个函数的作用是什么呢? ``` .text:0804BF2B call ___strcpy_chk .text:0804BF30 mov eax, ebx .text:0804BF32 call sub_804C5A0 ``` 在执行结束后sub_804c5a0函数被调用,这个函数主要的功能就是处理strcpy之后dest目标地址存放的路径的内容。 ``` .text:0804C5A0 sub_804C5A0 proc near ; CODE XREF: .text:0804A4D4p .text:0804C5A0 ; .text:0804BF32p ... .text:0804C5A0 push esi .text:0804C5A1 push ebx .text:0804C5A2 mov esi, eax .text:0804C5A4 sub esp, 0Ch .text:0804C5A7 push (offset aInvalidFunctio+1Ah) ; modes .text:0804C5AC push eax ; filename .text:0804C5AD call _fopen .text:0804C5B2 add esp, 10h .text:0804C5B5 test eax, eax .text:0804C5B7 mov ebx, eax .text:0804C5B9 jz short loc_804C5CC .text:0804C5BB sub esp, 0Ch .text:0804C5BE push esi ``` 但是strcpychk的存在导致不通过,程序进入abort处理,但是通过checksec可以看到这个程序启用了较多防护机制,实际上poc中的代码是执行不了的。 ``` gdb-peda$ checksec CANARY : ENABLED FORTIFY : ENABLED NX : ENABLED PIE : disabled RELRO : Partial ``` 因此程序需要在strcpy之前对传入字符串做一个长度截断或者长度检查可以防止这个拒绝服务漏洞。