Easy RM to MP3 Converter(2.7.3.700)栈溢出漏洞调试笔记

Debug_Orz 2014-10-13 17:41:00

0x00 基础知识


1 Windows环境

选取wmplayer.exe程序运行时的内存布局示意,包括栈,堆,加载模块(DLLs)和可执行文件本身。

Win32进程空间布局示意。

1.2 入口点(Entrypoint)

运行一个EXE的时候,会先根据IAT表加载相应的DLL,并且用GetProcAddress得到API的真实地址。也就是说EXE运行后,DLL的EP将是第一个被调用的地方,而EXE本身的EP应该是最后被调用的,但它是EXE本身代码的入口。

不同系统平台下反汇编结果。本节程序选取《逆向工程核心原理》一书中的HelloWorld.exe进行调试示意。

Windows Server 2008下反汇编结果(存在地址随机化,相同的exe程序,载入调试器后入口地址与XP下不同)。

Windows XP下反汇编结果。

F7 Step into。

004027A1地址处的RETN指令,用于返回到函数调用者的下一条指令(弹出ESP内容到EIP,然后跳转,0012FFC0处的值是004011A5,小端排序),一般是被调用函数的最后一句,即返回004011A5(JMP 0040104F)

EIP值为004011A5,ESP指针继续向下移动,ESP从0012FFC0指向0012FFC4(ESP+4)。

不同的开发工具生成的启动函数不同。同一种开发工具,产生的启动函数也随版本的不同而不同。

Call 00402524

1.3 函数调用步骤示意

过程描述 汇编代码
参数入栈
返回地址入栈
代码区跳转
栈帧调整 push 参数3
push 参数2
push 参数1
call (相当于push+jmp)
push ebp
mov ebp esp
sub esp,xxx

1.4 函数返回步骤示意

过程描述 汇编代码
栈回收
把ESP所指向内容弹出到EBP(相当于保存的上一栈的EBP弹出)
返回地址弹入EIP并Jump ADD ESP,XXX
POP EBP
RETN (相对于POP+JUMP)

函数栈帧示意。

1.5 栈溢出基础知识

1.5.1 原理示意

栈溢出就是缓冲区溢出的一种。 由于缓冲区溢出而使得有用的存储单元被改写,往往会引发不可预料的后果。程序在运行过程中,为了临时存取数据的需要,一般都要分配一些内存空间,通常称这些空间为缓冲区。如果向缓冲区中写入超过其本身长度的数据,导致缓冲区无法容纳,就会造成缓冲区以外的存储单元被改写,这种现象就称为缓冲区溢出。栈溢出原理示意入下图。

1.5.2 程序调试

调试带有字符串拷贝的简单程序示意。程序可以用Dev-C++ 4.9.9.2编译,小巧简单。程序代码如下。

#include <string.h> 
void do_something(char *Buffer)
{
     char MyVar[128];
     strcpy(MyVar,Buffer);
}
int main (int argc, char **argv)
{
     do_something(argv[1]);
}

调用函数,CALL function.00401290。

函数返回后的下一条执行地址压栈,在栈中可以看到004012EA,函数跳转到00401290。

进入子函数,PUSH EBP,EBP入栈。

MOV EBP ESP 改变栈底,让EBP指向ESP,EBP的内容(0x0022FF78)指向了前一个栈帧,所以[EBP+4]=004012EA。

开辟栈存储空间:SUB ESP,0x98

根据调试截图可知,如果[Buffer]的大小大于0x98字节,strcpy()函数将会覆盖保存的EBP(saved EBP)和保存的EIP(saved EIP),覆盖过程示意如下。

0x01 漏洞调试


2.1 漏洞测试环境

程序描述 备注
Easy RM to MP3 Converter 2.7.3.700 存在栈溢出漏洞的软件
Windows XP Pro SP3 En MSDN VL(不打任何补丁,关闭DEP) 模拟受害端
Kali-linux-1.0.9-i386 模拟攻击端
Windbg 6.12.0002.633 X86
Python 2.7.7
Immunity Debugger 1.85

2.2 Easy RM to MP3 Converter栈溢出调试过程

利用Perl和Python可以生成不同的m3u文件、POC进行测试。

打开Easy RM to MP3 Converter,加载具有10000个字符A的crash.m3u无效文件,我们发现目标软件捕获了该错误,跳出友好提示。 程序抛出一个错误,但是看起来这个错误被程序异常处理例程捕捉到了,程序并没崩掉。

调整字符个数,继续运行,目标软件在20000和30000之间可以崩溃掉。很明显,EIP 0x41414141是crash.m3u中的数据,说明程序返回地址被覆盖,EIP跳转到0x41414141,但找不到可执行的指令,所以报错。同时,从图中可以看出程序的EIP也可以被我们填充成一个指向恶意代码的地址。

如果使用二分法。用25000个A和5000个B填充m3u文件,如果EIP变为41414141 (AAAA)。那么返回地址就位于20000到25000之间。 如果EIP变为42424242 (BBBB)那么返回地址就位于25000到30000之间。

使用25000A+5000B,可以看到EIP为42424242(BBBB),所以返回地址位于25000到30000之间了。

根据调试信息,返回返回地址为42424242,说明ESP指向的返回地址已经弹出到EIP,则在内存中,栈顶指针ESP会指向EIP的下一个位置,如上图所示。 查看esp中的数据 d esp。

寻找存放shellcode的地址空间原理。

根据函数调用的堆栈平衡原理,缓冲区溢出之后,ESP应该停留在函数(这里假设为:XXCopy)调用之前所在位置上。也就是说,覆盖完EIP之后继续填充的数据都将保存在ESP所指地址中。

我们用BBBB重写了EIP和可以看到ESP所指的缓冲区。在我们调整脚本之前,需要精确的定位出来返回地址在缓冲区的位置,因为如果填充的都是AAAABBBB之类的,区分度不够高。调用metasploit中自带的工具。

root@kali:/opt/metasploit/apps/pro/msf3/tools# ./pattern_create.rb 5000

重写EIP前面需要覆盖的缓冲区长度。创建一个文件,填充25000+1069个A,再加4个B,EIP应该就会被重写成为42424242。

d esp

26061+4+4 = 26069

Buffer EBP EIP ESP 指向位置
A(x 26061) AAAA BBBB CCCCCCCCCCCCCCCCCCCCC
414141414141414141414141...41 41414141 4242424242
26061 bytes 4bytes 4bytes

当函数返回,BBBB被置入EIP中(pop ebp,retn),所以流程尝试到地址0x42424242(BBBB)执行。找内存空间存放我们的shellcode。

为了让应用程序崩溃,我们已经向内存中写入了26069 个A,我们已经向保存的EIP存储空间写入了一个新的值(函数返回执行时,RET将弹出并跳转到这个值),我们已经写了一堆的字符C。当应用程序崩溃时,可以查看所有这些寄存器(D ESP,D EAX,D EBX,D EBP,...)。如果你能在这些寄存器中的一个,看到缓冲区里的值(无论是A,还是C),那么你或许可以用shellcode取代它们的值,并跳转到该位置。在我们的例子中,我们可以看到,ESP似乎指向我们的C,所以理想情况下,我们会用实际的shellcode取代C,告诉EIP跳转到ESP的地址。

直接跳到一个内存地址不是一个好的方法(000ff730包含了字符串终止符(NULL: 00) ...所以你看到来自缓冲区第一部分的字母A...我们无法到达重写EIP后我们的数据了....另一方面,在Exploit使用内存地址直接跳转是非常不可靠的...因为内存地址会因为系统版本,语言等的不同而不同)

windbg中输入a,然后再输入jmp esp ,报错,直接回车,返回命令输入界面。然后u jmp esp之前的地址。

enter image description here

在地址7c90120e,你可以看到ffe4。这是操作码JMP ESP

现在,我们需要在这些加载的DLL中的某一个,找到这个操作码(opcode)。

查看WinDbg窗口,可以容易找到属于Easy RM to MP3应用程序的DLL。

如果我们能够在这些DLL中找到一个操作码,那么我们就可以在Windows平台上制作可靠的漏洞利用程序。

如果我们使用属于操作系统的DLL,那么我们可能会发现,漏洞利用程序在其他版本的操作系统上无法正常工作。

因此,我们在C:\Program Files\Easy RM to MP3 Converter\MSRMCcodec02.dll中搜索操作码。

此DLL在地址01c20000和020ed000之间加载。搜索操作码FF E4。

s 01c20000 020ed000 ff e4

当选择一个地址时,寻找空字节是很重要的。

你应该尽量避免使用地址中含有空字节。空字节将成为一个字符串结束符,那么缓冲区数据其余的部分将变得不可用。

s 70000000 l fffffff ff e4

因为我们希望把我们的shellcode放入ESP中(在覆盖的EIP之后放置载荷payload),从列表中选出的JMP ESP地址空间中不能有NULL字节。

空字节作为一个字符串结束,因此所有在它后面的内容会被忽略。

我们在覆盖的EIP之后放置我们的shellcode,这个地址不能包含空字节。

第一个地址起作用的地址是0x01ddf23a。

输入命令可以验证这个地址是否含有jmp esp(在地址01ccf23a处反汇编指令)

u 01ddf23a

0x02 漏洞利用


3.1 弹计算器

如果我们用0x01ccf23a 覆盖EIP,那么 jmp esp将会被执行。esp 包含了shellcode,所以我们就有了一个可用的exploit。首先我们可以用带有“NOP & break”的shellcode测试下。用Windbg调试,软件打开m3u文件。

再次运行程序,用windbg附加,运行,打开新的m3u文件。程序将会在地址000ff745暂停。那么说明jmp esp起作用了。esp开始于 000ff730, 它含有NOPs 指令直到 000ff744。

现在添加真实的shellcode,并开发exploit。再次打开,弹出计算器。

3.2 绑定端口

利用msfpaload生成shellcode,绑定某端口,例如8888。

Shellcode执行成功后,如果没有设置过防火墙,windows防火墙弹出拦截提示,unblock允许。

netstat –ano 查看网络连接情况,可以看到,打开了8888端口,查看进程号PID为388,程序为EasyRMtoMP3Converter.exe。

在Windows防火墙打开的情况下,ping不通,如果防火墙允许8888端口通信,telnet可以连接。

查看网络状态,与windows机器上显示一致。

0x03 问题说明


描述 备注
Metasploit每次生成不同的shellcode的不同输出。所以,如果你看自己的机器上每次看到不同的shellcode,则不必惊慌。 需要去掉坏字符 \x00\x0a\x0d\x1a
使用相同的命令,不同的系统,默认的编码器可能不同 msfpayload windows/shell_bind_tcp LPORT=8888 R | msfencode -b '\x00\x0a\x0d\x1a' -t perl
Kali系统中metasploit默认所使用的编码器与BackTrack不一致。 参考文献上使用的是Backtrack系统,其metasploit使用的默认编码器是x86/shikata_ga_nai,而Kali在不指定参数的情况下,使用的默认编码器是cmd/powershell_base64
Backtrack默认编码器x86/shikata_ga_nai
Backtrack系统metasploit所生成的shellcode
size 368
null
Kali默认编码器cmd/powershell_base64
Kali系统metasploit所生成的shellcode
size 985 null
使用Kali默认编码器生成的shellcode,程序执行后崩溃。 null
为了生成可绑定端口的的shellcode,在Kali系统中需要指定编码器
msfencode -e x86/shikata_ga_nai null

参考文献 1) https://www.google.com 2) https://www.corelan.be/index.php/2009/07/19/exploit-writing-tutorial-part-1-stack-based-overflows/ 3) https://www.corelan.be/index.php/forum/exploit-writing-debuggers/error-when-executed-u-unassemble-followed-by-the-address-that-was-shown-before-entering-jmp-esp/ 4) http://blog.csdn.net/yuzl32/article/details/6126592 5) http://extreme-security.blogspot.com/2013/02/stack-overflows-part-2-executing.html 6) http://cstriker1407.info/blog/a-reading-notes-of-the-devils-training-camp-msfpayload-using-the-tool-and-free-to-kill/ 7) http://www.securitysift.com/windows-exploit-development-part-1-basics/ 8) 《逆向工程核心原理》

评论

S

s2ck 2014-10-13 19:07:45

整篇文章跟《 逆向工程核心原理》里的内容没有关系,但《逆向工程核心原理》的确很好,特别适合我这种菜鸟看。

N

nzk1912 2014-10-14 08:26:46

大体意思是懂的,亲自操刀还是问题~小顶一下

L

lxj616 2014-10-14 13:22:01

精彩

B

BugMeOut 2014-10-17 20:43:18

好巧,最近也刚看了这篇。准备开搞第二篇了。楼主辛苦了。

T

tracyfan 2014-10-31 23:26:31

给pz跪了

D

Debug_Orz

Debug The World ~~

twitter weibo github wechat

随机分类

memcache安全 文章:1 篇
Ruby安全 文章:2 篇
木马与病毒 文章:125 篇
SQL注入 文章:39 篇
CTF 文章:62 篇

扫码关注公众号

WeChat Offical Account QRCode

最新评论

K

k0uaz

foniw师傅提到的setfge当在类的字段名成是age时不会自动调用。因为获取

Yukong

🐮皮

H

HHHeey

好的,谢谢师傅的解答

Article_kelp

a类中的变量secret_class_var = "secret"是在merge

H

HHHeey

secret_var = 1 def test(): pass

目录