我是逆向练习生,羽墨。
我正在从0开始学习二进制漏洞,如果你也跟我一样,不妨来看看小白学习的第一视角
首先,该函数判断异常处理函数地址是不是在加载模块的内存空间,如果属于加载模块的内存空间,校验函数将依次进行如下校验
(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)判断系统是否允许跳转到加载模块的内存空间外执行,如果允许则返回校验成功,否则返回校验失败。
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 表的信息在内存中是加密存放的,所以突破它的可能性也不大,这条路我们就先放弃吧。
利用S.E.H 的终极特权!这种安全校验存在一个严重的缺陷——如果S.E.H 中的异常函数指针指向堆区,即使安全校验发现了S.E.H 已经不可信,仍然会调用其已被修改过的异常处理函数,因此只要将shellcode 布置到堆区就可以直接跳转执行!
1.攻击返回地址绕过
2.虚函数绕过
3.从堆中绕过 : shellcode布置在堆中 ,SEH处理函数指向这个地址即可
4.利用未启用SafeSEH模块绕过 : 可以把这个模块的指令作为跳板,去执行shellcode
5.加载模块之外的地址绕过 :内存中有一些Map类型的映射文件,在这些文件中找到跳板指令覆盖SEH处理函数地址即可绕过
6.利用未启用SafeSEH的控件,且控件包含溢出漏洞可以被触发(IE浏览器控件)
1.我们使用上一篇中的代码,稍微修改来测试,关闭GS DEP ASLR, 开启 SafeSEH ,如果你有VC6 ,最好使用它来编译
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
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
;
}
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2022-5-3 16:35
被yumoqaq编辑
,原因: