首页
论坛
课程
招聘
[原创]EXP编写学习 之 绕过SafeSEH(五)
2022-5-3 16:27 8699

[原创]EXP编写学习 之 绕过SafeSEH(五)

2022-5-3 16:27
8699

前言

我是逆向练习生,羽墨。

 

我正在从0开始学习二进制漏洞,如果你也跟我一样,不妨来看看小白学习的第一视角


亡羊补牢 :SafeSEH

SafeSEH对异常处理的保护原理

  • 编译选项/SafeSEH启动 , VS2003以后默认启用
  • 生成SafeSEH表,放在PE文件中,调用异常处理函数的时候,将地址与SafeSEH表中的地址比较
  • 检查异常处理链是否位于当前程序的栈中,如果不在栈中,则程序终止异常处理函数的调用
  • 检查异常处理函数指针是否在程序的栈中,如果指向当前栈中,则终止异常处理函数的调用
  • 前面两项检查都通过后,程序调用一个全新的函数 RtlIsValidHandler ,对异常处理函数的有效性进行验证

RtlIsValidHandler检测原理

首先,该函数判断异常处理函数地址是不是在加载模块的内存空间,如果属于加载模块的内存空间,校验函数将依次进行如下校验

 

(1)判断程序是否设置了IMAGE_DLLCHARACTERISTICS_NO_SEH 标识。如果设置了这个标识,这个程序内的异常会被忽略。所以当这个标志被设置时,函数直接返回校验失败。
(2)检测程序是否包含安全S.E.H 表。如果程序包含安全S.E.H 表,则将当前的异常处理函数地址与该表进行匹配,匹配成功则返回校验成功,匹配失败则返回校验失败。
(3)判断程序是否设置ILonly 标识。如果设置了这个标识,说明该程序只包含.NET 编译人中间语言,函数直接返回校验失败。
(4)判断异常处理函数地址是否位于不可执行页(non-executable page)上。当异常处理函数地址位于不可执行页上时,校验函数将检测DEP 是否开启,如果系统未开启DEP 则返回校验成功,否则程序抛出访问违例的异常。

 

如果异常处理函数的地址没有包含在加载模块的内存空间,校验函数将直接进行DEP 相关检测,函数依次进行如下校验

 

(1)判断异常处理函数地址是否位于不可执行页(non-executable page)上。当异常处理函数地址位于不可执行页上时,校验函数将检测DEP 是否开启,如果系统未开启DEP 则返回校验成功,否则程序抛出访问违例的异常。
(2)判断系统是否允许跳转到加载模块的内存空间外执行,如果允许则返回校验成功,否则返回校验失败。

 

RtlIsValidHandler允许异常函数执行的情况

1)异常处理函数位于加载模块内存范围之外,DEP 关闭。
2)异常处理函数位于加载模块内存范围之内,相应模块未启用SafeSEH(安全S.E.H 表为空),同时相应模块不是纯IL。
3)异常处理函数位于加载模块内存范围之内,相应模块启用SafeSEH(安全S.E.H 表不为空),异常处理函数地址包含在安全SEH表中。

 

分析一下这三种情况的可行性。
(1)现在我们只考虑SafeSEH,不考虑DEP。排除DEP 干扰后,我们只需在加载模块内存范围之外找到一个跳板指令就可以转入shellcode 执行,这点还是比较容易实现的。

 

(2)在第二种情况中,我们可以利用未启用SafeSEH 模块中的指令作为跳板,转入shellcode执行,这也是为什么我们说SafeSEH 需要操作系统与编译器的双重支持。在加载模块中找到一个未启用的SafeSEH 模块也不是一件很困难的事情。

 

(3)这种情况下我们有两种思路可以考虑,一是清空安全S.E.H 表,造成该模块未启用SafeSEH 的假象;二是将我们的指令注册到安全S.E.H 表中。由于安全S.E.H 表的信息在内存中是加密存放的,所以突破它的可能性也不大,这条路我们就先放弃吧。

利用SafeSEH的缺陷

利用S.E.H 的终极特权!这种安全校验存在一个严重的缺陷——如果S.E.H 中的异常函数指针指向堆区,即使安全校验发现了S.E.H 已经不可信,仍然会调用其已被修改过的异常处理函数,因此只要将shellcode 布置到堆区就可以直接跳转执行!

绕过SafeSEH

1.攻击返回地址绕过

 

2.虚函数绕过

 

3.从堆中绕过 : shellcode布置在堆中 ,SEH处理函数指向这个地址即可

 

4.利用未启用SafeSEH模块绕过 : 可以把这个模块的指令作为跳板,去执行shellcode

 

5.加载模块之外的地址绕过 :内存中有一些Map类型的映射文件,在这些文件中找到跳板指令覆盖SEH处理函数地址即可绕过

 

6.利用未启用SafeSEH的控件,且控件包含溢出漏洞可以被触发(IE浏览器控件)

实践利用加载模块之外的地址

1.我们使用上一篇中的代码,稍微修改来测试,关闭GS DEP ASLR, 开启 SafeSEH ,如果你有VC6 ,最好使用它来编译

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <stdio.h>
#include <Windows.h>
 
int zero = 0;
 
int MyException()
{
    printf("Error OverFlow %d\n", zero);
    return 1;
}
 
void __stdcall test(char* str, char* out)
{
    char buf[0x500] = { 0 };
 
    __try
    {
        strcpy(buf, str);
        zero  = 1 / zero;
 
    }
    __except (MyException())
    {
 
    }
}
 
 
int main(int arc, char** argv)
{
    char buf1[200];
    test(argv[1], buf1);
    return 0;
}

2.先用IDA查看一下代码,因为我用VS2019编译, 编译器会扩展SEH

 

 

可以看到, 这里使用了第3代的异常处理模型 ,往栈中放入了不少东西,会影响我们的偏移

 

用od插件搜索一下,都开启了SafeSEH保护

 

 

3.调试一下看看,可以看到,输入0x500个字节的A后, 还差12个字节才可以覆盖到Handler

 

 

修改参数 ,再次调试查看

 

 

好的,现在可以看到,Handler已经被覆盖为 C , 那么现在需要找到跳板地址来跳到shellcode

 

之前已经看过,所有模块都启用了SafeSEH,那么我们需要找到加载模块之外的跳板地址,内存映射查看 MAP类型的地址

 

那么我们需要什么样的跳板指令呢

 

 

观察寄存器,发现eax指向我们溢出的缓冲区,那么是否可以利用 jmp eax , call eax,来跳转到shellcode执行(答案是不行,eax是一个易失寄存器,在转到异常处理函数的过程中会被修改)

 

好的, Next先不管,Handler需要什么样的跳板指令呢,按照之前利用SEH的总结, 我们需要 pop pop ret指令

 

随便填写一个地址测试是否成功转到该地址 ,我们在MAP类型内存映射中,找到了 0x7FFA5BE8地址,7FFA2017 它的指令是 jmp eax

 

 

 

好的,修改Handler为这个地址, 看一下是否可以转到这个地址执行 ,答案是可以,但是无法下断跟踪(且提示访问0地址)

 

之后我又选择了一个 pop ret指令的地址, 没办法,只能找到这个指令了,推算一下, 也就是 jmp [esp+4]

 

根据微软的解释 EstablisherFrame 是此函数的固定堆栈分配的基地址 ,也就是我们得到的地址是 系统设置的异常处理函数的ebp(好吧,日后详细研究一下)

 

 

好的好的,可以看到程序已经转到栈上执行,如果有合适的跳板指令可以利用(没办法了,我使用win10进行测试)

结语

1.可以看到限制我们进行漏洞利用的因素有很多,我们不得不研究新的手段来对抗微软的保护机制

 

2.经过测试,如果你不是使用加载模块地址之外的地址,确实会与safeSEH表来进行对比,会提示异常 无效的异常处理程序

 

3.经过这次实践,碰到了各种各样的问题,此时才能理解前人的智慧,不得不佩服

参考资料

0day2


【看雪培训】《Adroid高级研修班》2022年夏季班招生中!

最后于 2022-5-3 16:35 被yumoqaq编辑 ,原因:
收藏
点赞1
打赏
分享
打赏 + 50.00雪花
打赏次数 1 雪花 + 50.00
 
赞赏  Editor   +50.00 2022/06/21 恭喜您获得“雪花”奖励,安全圈有你而精彩!
最新回复 (2)
雪    币: 3
活跃值: 活跃值 (1350)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
咖啡_741298 活跃值 2022-5-4 17:13
2
0
x64的完全不一样了
雪    币: 3591
活跃值: 活跃值 (2088)
能力值: ( LV7,RANK:140 )
在线值:
发帖
回帖
粉丝
yumoqaq 活跃值 3 2022-5-4 17:48
3
0
咖啡_741298 x64的完全不一样了
从头开始研究吧,没办法。。
游客
登录 | 注册 方可回帖
返回