突破DEP之理论篇
DEP(Data Execution Prevention),当程序尝试在数据页面上执行指令时,CPU将抛出异常。DEP会阻止数据页(如默认的堆页、各种堆栈页以及内存池页)执行代码。
DEP有软件DEP(即SafeSEH)、硬件DEP。
要突破软件DEP参见突破SafeSEH
要突破硬件DEP可考虑:
- 攻击那些不支持硬件DEP的CPU - -||
- 攻击那些老版本的(早期的操作系统对DEP开关API的调用没有限制①)、或者不会自动启动DEP的系统 - -||
- 攻击没有开启DEP的程序:由于Windows无法确认有些第三方插件DLL是否支持DEP,所以涉及这些DLL的程序没有开启DEP;还有一些老版本的程序需要在数据页上产生可执行代码,因此也没有开启DEP
- 攻击会被加载进进程内存的小控件,如:
利用.NET控件进行攻击:.NET文件和PE文件结构相同,其.text等段会被映射到内存,so将其替换为shellcode,那么我们的shellcode就可以合法存在了
利用Java applet进行攻击:IE浏览器可以把Java applet加载到客户端,而加载进IE进程内存后这些控件所在内存空间都具有了可执行属性
以上四条看起来有点乱,但总而言之,突破DEP的精髓在于,想方设法把shellcode放在可读可写可执行的内存位置。
利用①可实施Ret2Libc
(Return-to-libc)攻击:
1)通过ret
跳转到ZwSetInformationProcess
函数,将DEP关闭,再转入shellcode执行 <== 不推荐使用,因为这个函数已经被废弃了
也可以:
2)通过ret
跳转到VirtualProtect
函数,将shellcode所在内存页设置为可执行状态,再转入shellcode执行
BOOL WINAPI VirtualProtect(
_In_ LPVOID lpAddress,//要改变属性的内存起始地址 ==> shellcode所在内存空间起始地址
_In_ SIZE_T dwSize,//要改变属性的内存区域大小 ==> shellcode大小
_In_ DWORD flNewProtect,//内存新的属性类型,设置为PAGE_EXECUTE_READWRITE(0x40)时该内存页为可读可写可执行 ==> 0x40
_Out_ PDWORD lpflOldProtect//内存原始属性类型保存地址 ==> 某个可写地址
);
也可以:
3)通过ret
跳转到VirtualAlloc
函数,开辟一段具有执行权限的内存空间,再复制shellcode到此,最后转入执行(如果在进程内存里能找到可读可写可执行的内存,可直接跳入memcpy函数将shellcode复制于此,然后...)
LPVOID WINAPI VirtualAlloc(
_In_opt_ LPVOID lpAddress,//申请内存区域的地址,如果这个参数是NULL,系统将会决定分配内存区域的位置,并且按64KB向上取整 ==> 选择一个未被占用的内存即可
_In_ SIZE_T dwSize,//申请内存区域的大小
_In_ DWORD flAllocationType,//申请内存的类型 ==> 0x00001000
_In_ DWORD flProtect//申请内存的访问控制类型,如读、写、执行等权限 ==> 0x00000040
);
======
一个小技巧:如果要让某个寄存器指向可读写内存,可以考虑把它指向栈空间。如:要让esi
执行可读写内存,可以使用
push esp
pop esi
Those who seek some sort of a higher purpose or 'universal goal', who don't know what to live for, who moan that they must 'find themselves'. You hear it all around us. That seems to be theofficial bromide of our century. Every book you open. Every drooling self-confession. It seems to be the noble thing to confess. I'd think it would be the most shameful one.