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