首页
社区
课程
招聘
[原创]初学之_过保护
发表于: 2023-5-5 19:26 10452

[原创]初学之_过保护

2023-5-5 19:26
10452

内存保护的安全性技术

  • (1)使用GS 编译技术,在函数返回地址之前加入了Security Cookie,在函数返回前首先检测Security Cookie 是否被覆盖,从而把针对操作系统的栈溢出变得非常困难。
  • (2)增加了对S.E.H 的安全校验机制,能够有效地挫败绝大多数通过改写S.E.H 而劫持进程的攻击。
  • (3)堆中加入了Heap Cookie、Safe Unlinking 等一系列的安全机制,为原本就困难重重的堆溢出增加了更多的限制。
  • (4)DEP(Data Execution Protection,数据执行保护)将数据部分标示为不可执行,阻止了栈、堆和数据节中攻击代码的执行。
  • (5)ASLR(Address space layout randomization,加载地址随机)技术通过对系统关键地址的随机化,使得经典堆栈溢出手段失效。
  • (6)SEHOP(Structured Exception Handler Overwrite Protection,S.E.H 覆盖保护)作为对安全S.E.H 机制的补充,SEHOP 将S.E.H 的保护提升到系统级别,使得S.E.H 的保护机制更为有效。

GS(Buffer Security Check)

1
2
3
4
5
6
int  test()
{
    char sz[10] = { 0 };
    memset(sz, 0x88, 9);
    return 0;
}
1
2
3
4
5
6
7
8
9
mov     eax, ___security_cookie ; rand->eax
xor     eax, ebp        ; xor
mov     [ebp+var_4], eax
//随机值___security_cookie xor ebp;置于local1;
//在函数末尾找到;
mov     ecx, [ebp+var_4]
xor     ecx, ebp        ; StackCookie
call    j_@__security_check_cookie@4 ; __security_check_cookie(x)
//调用安全检查;

1\1.png)
例如

1
2
3
4
5
6
7
void vuln(char* arg) 
{
 char buf[100];
 int i;
 strcpy(buf, arg);
 ...
}
1
2
3
4
5
6
copy of arg
i
buf
stack cookie
return address
arg

当栈中发生溢出时,Security Cookie 将被首先淹没,之后才是EBP 和返回地址。
在函数返回之前,系统将执行一个额外的安全验证操作过程中,系统将比较栈帧中原先存放的Security Cookie 和.data 中副本的值,如果两者不吻合,说明栈帧中的Security Cookie 已被破坏,即栈中发生了溢出。调用j____report_gsfailure去分发异常,不会给我们到ret的机会;
但是:The extra prologue and epilogue code can add a significant overhead to small functions.
For example, the following variables will cause the functions containing them to be protected by GS:

1
2
3
4
5
6
7
8
char a[5]; // protected, 5 byte array of elements of size 1
short b[3]; // protected, 6 byte array of elements of size 2
struct {
 char a;
} c[5]; // protected, 5 byte array of elements of size 1
struct {
 char a[5];
} d; // protected because the structure contains a string buffer

the variables below will not trigger the GS heuristic:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
char e[4]; // not protected, total size is less than 5 bytes
int f[10]; // not protected, array element size greater than 2
char* g[10]; // not protected, array element size greater than 2
struct {
 char a;
 short b;
} h[5]; // not protected, array element size greater than 2
struct {
 char a1;
 char a2;
 char a3;
 char a4;
 char a5;
} i; // not protected, the structure does not contain a string buffer

正如上面说的;gs机制并不都有使用,对性能开销比较大,可以使用#pragma strict_gs_check来进行强制使用;

绕过方案

未被保护内存绕过

正如上文说的the variables below will not trigger the GS heuristic: ;存在程序使用未被保护内存,那么可以直接使用以前溢出返回地址进行绕过;

异常处理绕过

需要先了解异常处理的一些机制;
2\2.png)

 

3\3.png)

 

我们可以这样思考,但现在无法淹没ret;是不是可以让shellcode长一点,导致淹没异常处理函数地址所在的栈区;触发异常使得通过异常处理函数地址让我们进入我们的shellcode;
但是这里需要注意;我们需要模拟一遍异常处理流程;

1
2
3
4
5
6
7
8
9
10
11
12
13
__try
{
    char sz[10] = { 0 };
    memset(sz, 0x88, 9);
    __asm mov eax, 0x00000000;
    __asm mov[eax], ebx;
 
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
    printf("hello");
    getchar();
}
1
2
3
4
004116FF    64:A1 00000000  mov eax,dword ptr fs:[0]
00411705    50              push eax
 
//这里将异常链push到栈中

给到地址;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
00411C80 55              push ebp
00411C81    8BEC            mov ebp,esp
00411C83    8B45 14         mov eax,dword ptr ss:[ebp+0x14]
00411C86    50              push eax
00411C87    8B4D 10         mov ecx,dword ptr ss:[ebp+0x10]
00411C8A    51              push ecx
00411C8B    8B55 0C         mov edx,dword ptr ss:[ebp+0xC]           ; GS.<ModuleEntryPoint>
00411C8E    52              push edx
00411C8F    8B45 08         mov eax,dword ptr ss:[ebp+0x8]           ; GS.<ModuleEntryPoint>
00411C92    50              push eax
00411C93    68 6C124100     push GS.0041126C                         ; ASCII E9,"o\t"
00411C98    68 04904100     push offset GS.__security_cookiemain_rea>
00411C9D    E8 D6F3FFFF     call GS.00411078
00411CA2    83C4 18         add esp,0x18
00411CA5    5D              pop ebp                                  ; vcruntim.788C4ED8
00411CA6    C3              retn

00411C9D E8 D6F3FFFF call GS.00411078;
00411078 /E9 393C0000 jmp GS._except_handler4_commonestroy_lis>
+; jmp 到 vcruntim._except_handler4_common
00414CB6 >- FF25 A4A04100 jmp dword ptr ds:[<&VCRUNTIME140D._excep>
; vcruntim._except_handler4_common

1
2
3
4
5
6
7
788C3698    E8 33FCFFFF     call vcruntim.788C32D0
788C369D    33C0            xor eax,eax
788C369F    33DB            xor ebx,ebx
788C36A1    33C9            xor ecx,ecx
788C36A3    33D2            xor edx,edx
788C36A5    33FF            xor edi,edi
788C36A7  - FFE6            jmp esi                                  ; GS.0041177A

最后在此调用了我们的异常处理函数;
这其中是否有对异常函数地址的检查;我们需要进一步认证;我们人为进行修改处理函数地址;
4\4.png)
将他修改为memset地址;
实际上还是调用原来的处理函数;那么我们现在尝试怎么办呢;
再进行更改;这说明一点当push进fs[0]头节点以后,在对hander进行修改;实际上无济于事;
回头进行检查,发现我们设置的是第二个异常链(失误);
再次设置发现,并没有跳转到memset;
再次设置
image.png5\5.png)
发生中断,说明通过了检查,合理猜测,在调用异常函数时,会检查是否在用户领空,多次测试,复合验证,
然后分析异常处理函数栈布局;

1
2
3
4
5
RetAddr:——except_handler();
param_1:_exceptionRecord;
param_1:_EstablisherFrame;
param_1:_ContextRecord;
param_1:_DispatcherContext;

我们关注;_ContextRecord;距离我们的之前栈结构
多了两个废弃参数;
使用pop xx;pop xx;ret
就可以实现;
而后使用EB 06短跳;不需要使用滑板指令就可以跳转到我们的shell code;
image.png\6.png)
上图为shellcode构造;
现在开始验证;
7\7.png)
符合预期;

覆盖虚函数绕过

...改天再学

同时替换.data和栈中安全因子

...改天再学;

DEP(Data Execution Protection)

关闭操作系统dep支持;
8\8.png)
技术思路;
DEP的本质就是取出内存可写区域的可在执行属性;从而通过将shellcode写入buffer伺机执行的方案不再有效;
但是我们可以使用Return oriented programming ROP方式去进行修改;
9\9.png)
(1)通过跳转到VirtualProtect函数将DEP 关闭后再转入shellcode 执行。
(2)通过跳转到VirtualProtect 函数来将shellcode 所在内存页设置为可执行状态,然后再
转入shellcode 执行。
(3)通过跳转到VIrtualAlloc 函数开辟一段具有执行权限的内存空间,然后将shellcode 复
制到这段内存中执行。

但是疑问接踵而来,我们不知道VirtualProtect函数地址;

返回导向编程(Return oriented programming)

是一种典型的代码复用技术:它通过复用以ret指令结束的代码片段来构造功能代码。当前,主流系统主要通过部署址空间布局随机化(Address Space Layout Randomization,ASLR)机制来缓解代码复用攻击;构造功能复杂的ROP代码比编写shellcode困难得多。在构造ROP代码的过程中,如果缺少某种类型的gadget或不能消除gadgets之间的副作用,都会导致构造失败

常见gadgets

对于 gadgets 能做的事情,基本上只要你敢想,它就敢执行。下面简单介绍几种用法:

  • 保存栈数据到寄存器
    • 将栈顶的数据抛出并保存到寄存器中,然后跳转到新的栈顶地址。所以当返回地址被一个 gadgets 的地址覆盖,程序将在返回后执行该指令序列。
    • 如:pop eax; ret
  • 保存内存数据到寄存器
    • 将内存地址处的数据加载到内存器中。
    • 如:mov ecx,[eax]; ret
  • 保存寄存器数据到内存
    • 将寄存器的值保存到内存地址处。
    • 如:mov [eax],ecx; ret
  • 算数和逻辑运算
    • add, sub, mul, xor 等。
    • 如:add eax,ebx; ret, xor edx,edx; ret
  • 系统调用
    • 执行内核中断
    • 如:int 0x80; ret, call gs:[0x10]; ret
  • 会影响栈帧的 gadgets
    • 这些 gadgets 会改变 ebp 的值,从而影响栈帧,在一些操作如 stack pivot 时我们需要这样的指令来转移栈帧。
    • 如:leave; ret, pop ebp; ret

构造rop链先等到以后学习;今天还有任务;
rop链布局;
10\10.png)

ASLR(Address space layout randomization)

ASLR 的出现使得shellcode 中的关键跳转只能在系统重启前,甚至只有程序的本次运行时
才能执行,这使得exploit 的难度大大增加。道高一尺,魔高一丈,任何一种保护技术都有一些
自身的弱点,攻击者已经用事实告诉人们ASLR 不是不可以突破的。
首先我们来看看ASLR 中最重要的部分——映像随机化。由于ASLR 将所有受保护模块的
加载基址都做了随机化处理,我们以前找到的通用跳板指令的地址也就不再固定,这些指令也
就失去了意义。但这个随机过程是不是完美无疵的呢?答案是否定的,细心的读者在看图9.6.1
的时候会发现一个现象,虽然模块的加载基址变化了,但是各模块的入口点(Entry 那列)地
址的低位2 个字节是不变的,也就是说映像随机化只是对加载基址的前2 个字节做了随机处理。

利用部分覆盖进行定位内存地址

11\11.png)
这个方法比较简单;没啥说的

Heap spray技术

此段分析;详见cve-2012-189;

参考文献

教材
0day2
Bypassing Browser Memory Protections
CTF all in one


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2023-5-5 19:41 被john_大白编辑 ,原因:
上传的附件:
收藏
免费 2
支持
分享
最新回复 (1)
雪    币: 3070
活跃值: (30876)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
也有部分图没了
2023-5-6 10:43
1
游客
登录 | 注册 方可回帖
返回
//