-
-
[原创]HEVD池溢出系列
-
发表于: 2021-5-20 11:06 9860
-
由于新接触到了一个知识点,花了些时间去学习windows7内核池的一些知识。
这个漏洞的复现过程实在是太过于精美,并且在这过程间补充到了不少的知识,打算就池溢出做一期笔记。
内核池实际上是windows中类似于堆的一种动态内存结构。两者的利用在我看来是十分相似的。
将池溢出之前,我们不妨先回顾以下堆溢出
有CTF经验的朋友们应该不陌生堆溢出
那么如何完成一次堆溢出利用呢?
可以做出如下的假设:
堆块是系统分配给程序的空间,堆块在系统中是连续的一段内存,那么如果我们可以为某个带函数指针的对象申请一段内存空间,并且通过堆溢出修改我们的函数指针指向shellcode,那么我们即可完成堆溢出利用。
但是理想和现实总是存在差距的,好在可以将理想照进现实
那么不妨从这个思路开始
按照我的思路,分析漏洞时需要有三个部分的思考
但是由于HEVD本身就是一个漏洞复现的靶场,由于存在源码,所以我们可以省去最后一步做分析。
但我认为,复现或者挖掘漏洞的过程中,从哪里来也是很重要且具有挑战性的工作
使用IDA定位到漏洞位置
那么我们先简单的编制一个poc,证明漏洞的存在
在之前的分析中,我们已经知道了是由于HEVD!memcpy
没有对size进行判断从而导致了漏洞的发生,那么我们首先通过windbg下断点到HEVD!memcpy
运行我们的poc
查看池状态,当然,之前我们下了断点,此时记得执行p命令
查看当前池块内容
试着多发送8个字节的内容
我们发现后续的池块由于结构被破坏,导致了无法被识别
此时系统也会发生蓝屏
此时我们已经彻底明白了,漏洞“是谁”
但是,我们简单布置的poc,多溢出的字节会由于破坏的后续池块的结构而导致系统的BSOD
也就是,我们的“到哪去”并不顺利
那么,我们应该更具体地构想,这段内存应该到哪里去
根据之前所讲的,由于C++面向过程的特性,我们可以向申请的堆块(池)中为某些特定对象申请空间,进而通过溢出控制其函数指针从而执行shellcode
当然,对象的大小也必须是合适的,由于我们的池块大小为0x1F8+8=0x200
因此选择CreateEventA
函数,CreateEventA
申请出Event对象的大小为0x40,0x40 * 8 == 0x200
先申请大量的event对象,再释放掉部分的event,这将会在内存中造成一些空洞,从而得以在这段空间中申请到kernel buffer,此时再申请kernel buffer将会保证下一个位置是一个Event对象
申请大量的event对象后
那我们随便取出一个event对象查看内部结构,首先我们查看windows中object的结构
index的值为0xC,所在obTypeIndexTable
表中的偏移为0xC
所谓obTypeIndexTable
表是指,xp直接在OBJECT_HEADER
里保存了POBJECT_TYPE
指针,而Win7里把所有的对象类型放在了一个表里,这个表叫做obTypeIndexTable
查看该表内容,并定位到0xC的位置
可见Event对象保存在此处
查看该对象结构
这里我们选用CloseProcedure
函数作为修改的函数,理由是,在之后的源码中,我们发现会有
函数来释放这段空间
可是接下来的问题,怎么能够去修改到CloseProcedure
函数的呢?我们并不能通过池溢出直接修改到这个函数的指针
但是我们能修改到index的索引
ObTypeIndexTable
第0个索引指向0地址(0x00000000)
利用此思路,我们可以构建如下的利用思路
exp写的不是很优雅,建议从参考链接中获取两位师傅的博客
拖了很久才完成这一部分的利用,emmmm,总体收获还是蛮大的,离不开50u1w4y师傅的帮助,exp也是参考了他的exp,故而就不张贴出来了。
当然复现的过程中也从这些师傅的博客中获取了很多知识,十分感谢他们
https://50u1w4y.github.io/site/HEVD/nonPagedpooloverflow/#0x00
https://bbs.pediy.com/thread-252665.htm
#include<stdio.h>
#include<windows.h>
int
main() {
ULONG bReturn
=
0
;
HANDLE hevDevice;
ULONG BytesReturned;
hevDevice
=
(HANDLE)CreateFileA(
"\\\\.\\HackSysExtremeVulnerableDriver"
,
0xC0000000
,
0
, NULL,
0x3
,
0
, NULL);
char buf[
0x1f8
]
=
{
0
};
if
(!hevDevice) {
printf(
" failed to get handle"
);
}
RtlFillMemory(buf,
0x1f8
,
'a'
);
DeviceIoControl(hevDevice,
0x22200f
, buf,
0x1f8
, NULL,
0
, &bReturn, NULL);
return
0
;
}
#include<stdio.h>
#include<windows.h>
int
main() {
ULONG bReturn
=
0
;