CMDHZ
本文发表在黑防2008的2期上,按照他们要求的间隔时间已经过了,所以贴上来。本文设计了用于演示的程序,一下子没有找到怎么发附件,所以需要的读者就向邮箱lisl03@gmail.com发 application mail吧。
ShellCode的编写好像是一个永远说不完的话题。在11期《黑客防线》上我写了《再谈绕过卡巴斯基主动防御的ShellCode编写》的文章。小弟最近在编写一个漏洞的利用程序时,遇到了在进程空间中安全搜索ShellCode的问题。小弟在网上搜索了一番也没有什么有用的东西。在为这个问题困扰了许久之后,小弟请教了一位大虾后才知道原来国外的一些大牛们早就作过这方面的深入研究了。在参阅了一些相关的资料后,小弟终于解决了如何安全搜索内存空间的问题。好东西不敢独享,把他写出来献给如我一样正在艰难学习中的菜鸟,大虾看了就飘过吧!
很多情况下在编写ShellCode的时候我们都会面临着如何安全地搜索进程空间,找到我们的可爱的没有被破坏得ShellCode的问题。例如,有些溢出程序对编码有着特殊得要求,比如会将0x 2F (‘/’)转化为0x 5C (‘/’)等等的情况,甚至还有不能出现0xFF的情况。这个时候可能不管你怎么变形都无法符合要求;有些文件格式型的溢出由于文件结构自身的特点,在溢出点附近不可能放入大得ShellCode。溢出产生的时候,我们都必须用一个简短的Search Code查找到原始的ShellCode后,再执行这个功能ShellCode来实现我们的溢出利用。这种通过设置一定得标志字节,由小ShellCode找在内存中查找大ShellCode的方法有一个有趣得叫法:Egg-Hunt.。
在栈溢出利用时,EIP开始在堆栈里执行后,由于堆栈在内存中的地址往往比较低:如0x0012XXXX,而原始ShellCode却在0x07BAXXXX远的高地址。直接搜索内存的时候会由于:违规访问未分配内存、用户断点、 浮点异常等等问题而造成系统的崩溃。于是在我们好不容易获得CPU控制权之际,却得到了如下的报错提示框,刚刚得到的CPU控制权就这样丢失了。
![](https://i-blog.csdnimg.cn/blog_migrate/50068a1d5b3fa80c8e75c202805f67a5.jpeg)
图一、内存搜索错误
![](https://i-blog.csdnimg.cn/blog_migrate/9652a1ae66838bdfca3c139ec2d768da.jpeg)
图二、异常详细信息
因此必须实现对进程空间的安全搜索,最终找到实现功能的ShellCode,并在那里安全着陆。对于这样Egg-Hunt的ShellCode的编写有如下三个基本要求:
搜索程序的鲁棒性:这样的要求主要体现在搜索程序必须要有处理“非法地址”访问的能力,才能够安全地搜索进程地址空间,否则对无效地址的访问将导致被溢出进程的崩溃。
搜索程序的简洁性:汇编代码的体积是编写搜索程序时需要考虑的一个非常重要的方面,因为绕过溢出环境对Search Code大小的限制是我们使用这种功两段式ShellCode的原因。
搜索程序的高效性:溢出的时候我们当然希望能够尽快跳转到ShellCode去执行我们希望的操作。否则将留下一个不能得到及时更新的屏幕将会是溢出特征的一个最好提示。
在以上三个对Egg-hunt的要求中,程序的鲁棒性是最重要的,因为在执行对进程地址空间搜索的时候,非法地访问毕竟是我们最常遇到的问题。我们当然不希望由于搜索内存失败而造成程序的崩溃,使我们丧失了执行ShellCode的机会。
那么下面我们将主要探讨一些在Windows平台下,常用的安全搜索内存空间的方法。
一、利用SHE机制安全搜索内存空间:
Windows系统中的SEH机制是大家在进行溢出攻击时常常利用的一种机制。在这里我们在执行进程空间搜索之前首先注册一个异常处理函数,用它来捕获并完成对“非法地址访问”及各种“运行时异常”的处理,以提高搜索程序的鲁棒性,使我们能够顺利地找到进程空间中的ShellCode。
为了对这样的方法的原理有更好的理解,我们再将Windows 系统中异常处理方面的内容再复习一下。
1、Windows的结构化异常处理(SEH)
Windows在创建线程时,操作系统会为每个线程分配TEB结构,并且将FS段选择器指向当前线程的TEB数据结构(结构的定义可以参见参考资料)。
Typedef struct _NT_TIB { Struct _EXCEPTION_REGISTERATION_RECORD * ExceptionList; PVOID StackBase; PVOID StackLimit; PVOID SubSystemTib; Union { PVOID FiberData; ULONG Version; }; PVOID ArbitaryUserPointer; Struct _NT_TIB * Self; } NT_TIB; |
偏移为0的_EXCEPTION_REGISTERATION_RECORD主要用于处理SHE,因此我们使用FS:[0]也就能够访问SEH。其结构定义如下:
EXCEPTION_REGISTERATION Struct Prev dd ? 前一个EXCEPTION_REGISTERATIONj结构 Hander dd ? 异常处理例程入口 _EXCEPTION_REGISTERATION end }; |
其中prev指向前一个_EXCEPTION_REGISTERATION的指针,因此线程的异常处理例程形成了一个链状结构。当系统处理异常时就查找异常处理链表,调用相应的异常处理函数执行对程序异常的处理。