- ·上一篇文章:DDoS攻击原理及防范(六)
- ·下一篇文章:XP系统反复注销 大量用户遭困扰
推荐:菜鸟版Expliot编写指南之PNP溢出漏洞分析+利用
一个月前和朋友聊天,谈到现在网络上蠕虫、病毒是越来越猖狂,前年的“冲击波”,去年的“震荡波”,今年还不知道又出什么呢?话音刚落,一个被命名为Zotob的蠕虫病毒已经在8月15日开始传播。后来的几天,该蠕虫的变种相继产生,对网络造成了一定的影响。Zotob蠕虫是基于Windows2000 以上版本的即插即用(PNP)服务中产生的堆栈溢出漏洞,远程攻击者通过TCP 445或139端口向该服务提交畸形请求,溢出后可能获取系统权限。大家的防范意识都比较强了,很多用户都及时打了补丁,而一般个人防火墙的默认规则也封堵了TCP 139或445端口,该漏洞的破坏力已经明显不如以前的“冲击波”们了。言归正传,我们还是来分析这个漏洞。
一、漏洞起因及影响范围
漏洞的起因前面已经简单提到了,我们可以参见漏洞公告。
从漏洞公告我们可以看出两点:
1.漏洞起因:Windows 2000版本以上的PNP服务存在远程堆栈溢出漏洞,“远程”是因为该服务可以通过RPC接口来远程调用。
2.影响范围:漏洞只对Windows 2000 有真正威胁,而要攻击XP和Windows2003均有一定的限制。因为对于这个RPC接口,如果在Windows 2000上则可以远程匿名进行调用;在 Windows XP SP0、SP1上,需要以一个有效账号登录后才可以调用;在Windows XP SP2和Windows 2003上,只有管理员组用户才能远程调用,其它账号只能本地调用。
二、远程溢出漏洞的宏定位分析
这部分工作我认为很重要,因此在本文中正好讲清楚一些。所谓“宏定位”,就是指我们应该对我们实现的目标进行预先的分析,调试漏洞是这样,做其它工作也是如此,这一步做好了我们在后面可以少走弯路。
1.对具有溢出漏洞的服务进程的归类。
这里我们将服务进程分为两类。一类是服务自身绑定了端口,可以是TCP 或UDP端口;另一类当然是服务进程自身没有绑定任何端口。对于前一类服务,远程机器直接通过传输层协议(TCP或UDP协议)+应用层协议(如,RPC协议、http协议)来访问服务,IIS、FTP、HTTP都属于这一类服务。如果他们服务存在漏洞,我们可以通过重复绑定端口、复用socket来绕过防火墙的检测。对于后一类服务,远程机器通过传输层协议+命名管道(IPC$)+应用层协议来访问服务的,这也就是为什么我们访问LSASS、WorkStation等服务的时候要先与远程机器建立IPC$空连接的原因。这类漏洞要的利用要躲避防火墙的检测实现起来要困难一些,这个我在后门会提到。
感染利用PNP溢出漏洞的蠕虫后我们的机器会弹出系统显示“系统处理程序c:\winnt\system32\services出乎意料的终止”关机提示框,根据以往的经验,我们可以看出该漏洞是存在于Services进程中,这一点和WorkStation服务一样,因此归为后一类。
2.服务进程接收缓冲区长度是否足够。
这个问题集中体现在用于接收请求的函数(如recv、recvfrom等)第3个参数len上。如果指定的len很小,我们是无法一次性传送功能复杂的很长的ShellCode的,这时就必须采用其他传送的方式,例如把ShellCode分段传送,在10期另一篇溢出文章《编写分段传送的ShellCode》有介绍。接收缓冲区长度问题一般在服务进程自身绑定了端口的溢出漏洞中出现,因此PNP服务中可以暂不考虑。
3.异常发生的位置。
这个问题是指我们向服务程序提交超长的请求后,会覆盖问题函数的返回地址EIP等指针。当函数返回的时候,跳转到我们覆盖数据指定的地址的时候可能发生异常;另外一种情况就是在该函数返回之前,由于我们覆盖了局部变量中其它指针,导致对其进行引用的时候发生异常。简而言之就是ret前与ret后发生异常的区别。对于ret后的异常,我们可能需要通过KiUserExceptionDispatcher和监视点的方法来联合定位溢出点,并且漏洞利用的方式有两种:改写EIP为jmp esp 地址或改写SEH指针;而对于ret前的异常,我们一般通过KiUserExceptionDispatcher来定位溢出点就够了,利用的时候也只能改写 SEH指针。我们预先并不知道PNP溢出漏洞属于哪一类,不过等下面进一步调试后就明确了。
4.如果是问题函数ret后异常,则判断该函数的调用约定。
这个问题是最容易被忽略的。如果我们能够采用jmp esp的利用方式的话,可能很多人会在覆盖jmp esp位置的紧接4个字节开始的地方连接ShellCode,问题就出在这里。
不管是Windows系统进程、第3方软件、还是我们自己用VC6、VC7编写的程序,只要和C/C++相关的函数,一般来说可以分为__cdecl和__stdcall两种调用约定。采用__cdecl的函数在返回需要调用者恢复实参占用的堆栈,也就是函数只执行返回指令为ret,我们把ShellCode接到保存的EIP后面是没问题的;而采用__stdcall在函数返回是执行指令ret n,自己恢复实参占用的堆栈,我们如果把ShellCode接到保存的EIP后面的话开始n个字节的代码就执行不到了。这也就是为什么我们在构造一些系统进程溢出漏洞(如,RPC、WorkStation、LSA等)攻击代码的时候jmp esp地址后要有若干保留字节的原因。好了,带着剩下的问题,我们继续。
三、PNP溢出漏洞的进一步分析+利用
现在的的牛人们利用编写漏洞代码的速度是越来越快了,蠕虫出来两、三天,攻击代码就已经公布出来了。既然有现成的,我们就直接拿过来用了。于是,我把www.xfocus.net 上公布的代码拿来整理后编译,执行,结果目标机器还是发生了异常。
幸好是用VMWare(+Windows 2000 SP4)作测试,否则用我自己的机器岂不麻烦?很显然,攻击代码存在问题,再看看网上代码中地址填充:
EvilRPC.SDA[76] = 0x3e;
EvilRPC.SDA[77] = 0x1e;
EvilRPC.SDA[78] = 0x02;
EvilRPC.SDA[79] = 0x75;
这个地址不是我们熟悉的地址,需要进一步分析。这样的漏洞分析,VMWARE和SoftICE的组合是再合适不过了,顺便向大家推荐:)。启动VMWARE中的SoftICE,设置断点:
bpx ntdll!KiUserExceptionDispatcher
发生任何异常,SoftICE都会先在这个函数第一条指令停顿下来。关于KiUserExceptionDispatcher函数及其参数的详细介绍,2004年黑防10期ISNO《我是怎样发现CCPROXY溢出漏洞的》一文中有详细介绍,我在05年8期中对Realplay溢出漏洞分析中也有详细的介绍,大家可以参考,这里我只结合本漏洞谈谈。
OK,重新攻击VMWare系统,果然弹出了SoftICE,并停留在函数KiUserExceptionDispatcher入口处。
输入命令addr,可以看到的确是Services进程空间发生了异常。输入命令:d (*(esp + 4) + b4), 得到异常
一、漏洞起因及影响范围
漏洞的起因前面已经简单提到了,我们可以参见漏洞公告。
从漏洞公告我们可以看出两点:
1.漏洞起因:Windows 2000版本以上的PNP服务存在远程堆栈溢出漏洞,“远程”是因为该服务可以通过RPC接口来远程调用。
2.影响范围:漏洞只对Windows 2000 有真正威胁,而要攻击XP和Windows2003均有一定的限制。因为对于这个RPC接口,如果在Windows 2000上则可以远程匿名进行调用;在 Windows XP SP0、SP1上,需要以一个有效账号登录后才可以调用;在Windows XP SP2和Windows 2003上,只有管理员组用户才能远程调用,其它账号只能本地调用。
二、远程溢出漏洞的宏定位分析
这部分工作我认为很重要,因此在本文中正好讲清楚一些。所谓“宏定位”,就是指我们应该对我们实现的目标进行预先的分析,调试漏洞是这样,做其它工作也是如此,这一步做好了我们在后面可以少走弯路。
1.对具有溢出漏洞的服务进程的归类。
这里我们将服务进程分为两类。一类是服务自身绑定了端口,可以是TCP 或UDP端口;另一类当然是服务进程自身没有绑定任何端口。对于前一类服务,远程机器直接通过传输层协议(TCP或UDP协议)+应用层协议(如,RPC协议、http协议)来访问服务,IIS、FTP、HTTP都属于这一类服务。如果他们服务存在漏洞,我们可以通过重复绑定端口、复用socket来绕过防火墙的检测。对于后一类服务,远程机器通过传输层协议+命名管道(IPC$)+应用层协议来访问服务的,这也就是为什么我们访问LSASS、WorkStation等服务的时候要先与远程机器建立IPC$空连接的原因。这类漏洞要的利用要躲避防火墙的检测实现起来要困难一些,这个我在后门会提到。
感染利用PNP溢出漏洞的蠕虫后我们的机器会弹出系统显示“系统处理程序c:\winnt\system32\services出乎意料的终止”关机提示框,根据以往的经验,我们可以看出该漏洞是存在于Services进程中,这一点和WorkStation服务一样,因此归为后一类。
2.服务进程接收缓冲区长度是否足够。
这个问题集中体现在用于接收请求的函数(如recv、recvfrom等)第3个参数len上。如果指定的len很小,我们是无法一次性传送功能复杂的很长的ShellCode的,这时就必须采用其他传送的方式,例如把ShellCode分段传送,在10期另一篇溢出文章《编写分段传送的ShellCode》有介绍。接收缓冲区长度问题一般在服务进程自身绑定了端口的溢出漏洞中出现,因此PNP服务中可以暂不考虑。
3.异常发生的位置。
这个问题是指我们向服务程序提交超长的请求后,会覆盖问题函数的返回地址EIP等指针。当函数返回的时候,跳转到我们覆盖数据指定的地址的时候可能发生异常;另外一种情况就是在该函数返回之前,由于我们覆盖了局部变量中其它指针,导致对其进行引用的时候发生异常。简而言之就是ret前与ret后发生异常的区别。对于ret后的异常,我们可能需要通过KiUserExceptionDispatcher和监视点的方法来联合定位溢出点,并且漏洞利用的方式有两种:改写EIP为jmp esp 地址或改写SEH指针;而对于ret前的异常,我们一般通过KiUserExceptionDispatcher来定位溢出点就够了,利用的时候也只能改写 SEH指针。我们预先并不知道PNP溢出漏洞属于哪一类,不过等下面进一步调试后就明确了。
4.如果是问题函数ret后异常,则判断该函数的调用约定。
这个问题是最容易被忽略的。如果我们能够采用jmp esp的利用方式的话,可能很多人会在覆盖jmp esp位置的紧接4个字节开始的地方连接ShellCode,问题就出在这里。
不管是Windows系统进程、第3方软件、还是我们自己用VC6、VC7编写的程序,只要和C/C++相关的函数,一般来说可以分为__cdecl和__stdcall两种调用约定。采用__cdecl的函数在返回需要调用者恢复实参占用的堆栈,也就是函数只执行返回指令为ret,我们把ShellCode接到保存的EIP后面是没问题的;而采用__stdcall在函数返回是执行指令ret n,自己恢复实参占用的堆栈,我们如果把ShellCode接到保存的EIP后面的话开始n个字节的代码就执行不到了。这也就是为什么我们在构造一些系统进程溢出漏洞(如,RPC、WorkStation、LSA等)攻击代码的时候jmp esp地址后要有若干保留字节的原因。好了,带着剩下的问题,我们继续。
三、PNP溢出漏洞的进一步分析+利用
现在的的牛人们利用编写漏洞代码的速度是越来越快了,蠕虫出来两、三天,攻击代码就已经公布出来了。既然有现成的,我们就直接拿过来用了。于是,我把www.xfocus.net 上公布的代码拿来整理后编译,执行,结果目标机器还是发生了异常。
幸好是用VMWare(+Windows 2000 SP4)作测试,否则用我自己的机器岂不麻烦?很显然,攻击代码存在问题,再看看网上代码中地址填充:
EvilRPC.SDA[76] = 0x3e;
EvilRPC.SDA[77] = 0x1e;
EvilRPC.SDA[78] = 0x02;
EvilRPC.SDA[79] = 0x75;
这个地址不是我们熟悉的地址,需要进一步分析。这样的漏洞分析,VMWARE和SoftICE的组合是再合适不过了,顺便向大家推荐:)。启动VMWARE中的SoftICE,设置断点:
bpx ntdll!KiUserExceptionDispatcher
发生任何异常,SoftICE都会先在这个函数第一条指令停顿下来。关于KiUserExceptionDispatcher函数及其参数的详细介绍,2004年黑防10期ISNO《我是怎样发现CCPROXY溢出漏洞的》一文中有详细介绍,我在05年8期中对Realplay溢出漏洞分析中也有详细的介绍,大家可以参考,这里我只结合本漏洞谈谈。
OK,重新攻击VMWare系统,果然弹出了SoftICE,并停留在函数KiUserExceptionDispatcher入口处。
输入命令addr,可以看到的确是Services进程空间发生了异常。输入命令:d (*(esp + 4) + b4), 得到异常

