首页
社区
课程
招聘
[原创]HEVD学习笔记之UAF
发表于: 2021-11-9 11:46 21296

[原创]HEVD学习笔记之UAF

2021-11-9 11:46
21296

实验环境以及HEVD介绍请看:HEVD学习笔记之概述           

释放重引用漏洞(UAF)产生的原因是对已经释放的内存区域进行使用,导致了内存崩溃或者任意代码的执行。比如下面这段代码

由于free掉buf1以后,没有及时地将buf1的指针清空,导致随后对buf1的操作将会有效,从而影响了buf2的数据。最终输出如下图:

所以要利用UAF漏洞,需要以下的几个步骤:

申请一块内存以后释放掉它,但是没有清空该内存的指针

重新申请一块同样大小的内存,此时这两个指针对指向同一块内存

对第一步的指针进行操作,它将会影响到第二步申请的指针指向的内存

在HEVD中,有4个函数是用来实现本次的漏洞,分别是

AllocateUAFObjectNonPagedPoolIoCtrlHandler:用来申请一块内存

UseUAFObjectNonPagedPoolIoCtrlHandler:对申请的内存的使用

FreeUAFObjectNonPagedPoolIoCtrlHandler:释放申请的内存

AllocateFakeObjectNonPagedPoolIoCtrlHandler:申请和第一步同样大小的内存并对其进行修改

该函数是函数地址表中的第5个函数,所以对应的IOCTL为0x222003 + 4 * 4。

程序将参数入栈以后就调用了AllocateUAFObjectNonPagedPoolCtrlHandler,继续看该函数

在该函数中,只是调用了AllocateUAFObjectNonPagedPool,继续跟进这个函数。

可以看到,该函数中首先申请了一块0x58大小,tag为Hack的内存,并将指针赋给ebx。

随后程序会将这段内存的前4个字节赋值为UAFObjectCallbackNonPagedPool,后面的字节赋值为'A',并将申请到的内存保存在全局变量中。而前4字节保存的函数只是一个简单的输出函数。

由此可知,AllocateUAFObjectNonPagedPoolIoCtrlHandler做的事情是,申请一块0x58大小的内存。该内存的前4字节赋值为一个函数地址,后面的字节赋值为'A'。而这块内存的地址也会被赋值到全局变量g_UseAfterFreeObjectNonPagedPool中。

该函数是函数表中的第6个函数,对应的IOCTL是0x222003 + 5 * 4。而该IOCTL的操作是对UseUAFObjectNonPagedPoolIoCtrlHandler的调用,而在该函数中会调用UseUAFObjectNonPagedPool。

在UseUAFObjectNonPagedPool中,函数首先会对全局变量g_UseAfterFreeObjectNonPagedPool进行判断,判断该变量中是否保存了内存地址

随后就是对地址的前四字节进行判断,是否保存了函数地址,如果保存了就调用这个函数

该函数是地址表中的第7个函数,对应的IOCTL是0x222003 + 6 * 4。而该IOCTL的操作是对FreeUAFObjectNonPagedPoolIoCtrlHandler的调用,而在该函数中会调用FreeUAFObjectNonPagedPool。

而在FreeUAFObjectNonPagedPool函数中,函数首先会判断g_UseAfterFreeObjectNonPagedPool保存的地址是否为0

如果地址不为0,函数就会调用ExFreePoolWithTag将这段内存释放掉

该函数在函数地址表中的第8个函数,对应的IOCTL为0x222003 + 7 * 4。

将IRP和CurrentStackLocation指针入栈以后就调用了AllocateFakeObjectNonPagedPoolIoCtrlHandler。

在该函数中,函数会将输入缓冲区的地址取出以后入栈,接着在调用AllocateFakeObjectNonPagedPool函数。

函数会申请一块0x58大,tag为Hack的内存,并将内存地址保存到edi和局部变量中。

接着函数会验证输入缓冲区的指针是否可读,然后将输入缓冲区的内容赋值到申请到的0x58字节的内存中,在对申请到的内存的最后一个字节赋值为0。

由上面分析可以知道,申请的0x58大小的内存中的前4个字节保存了一个函数地址。正常情况下,通过对UseUAFObjectNonPagedPoolIoCtrlHandler的调用就会调用程序分配的那个函数,如下图所示

可是,在释放内存的时候,程序没有对全局变量进行处理。这样,如果释放完内存以后,调用AllocateFakeObjectNonPagedPoolIoCtrlHandler的时候,程序会申请0x58大小的内存,这个时候就会得到和全局变量所指地址一样的内存区域,而此时我们通过构造输入缓冲区的前4字节来指定为ShellCode的函数地址,这样就会改变全局变量所指的内存的前4字节,这个时候在调用UseUAFObjectNonPagedPoolIoCtrlHandler的时候,就会调用指定的ShellCode函数地址

完整的exp代码如下:


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2022-1-19 18:03 被1900编辑 ,原因:
收藏
免费 3
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//