0x00前言
昨晚看师傅们当年的博客 愈发觉得自己菜。。。害 还是开始吧 这应该是最后一部分了 未初始化堆变量
0x01漏洞原理
我们将上一篇的原理复制过来?其实也差不多 动态申请内存后可能不会去初始化 未初始化的指针会有不确定的值 而此时对其引用就会产生无法预期的行为 我们日常使用的malloc()函数就不会初始化 还有就是aligned_alloc() 而alloc()可以进行初始化
函数分析
函数的执行流程是 先去分配池空间 若我们的输入不等于MagicValue 就会对未初始化的池进行调用 然后导致。。。。
1 | NTSTATUS |
0x02漏洞分析
照旧 先下断点
1 | bp HEVD!TriggerUninitializedMemoryPagedPool+178 |
当我使用官方exp的时候 发现无法查看到exp的位置 Callback的位置存储的并不是exp 但确实是可以提权成功的 这一点有点疑惑 难道说官方的exp并没有将exp放在该位置?所以我又去看了下TJ师傅的文章
看到了师傅先使用poc进行验证 我们已经做过那么多了(我指的是这个系列) 一路走过来 我们已经知道利用IO控制码可以传入用户输入的值 具体可以参考这里 我们需要做的是 将Callback指向我们shellcode
我想 我还是将poc的图放在文章中吧 说不定有人看到呢 使用TJ师傅的代码了
1 | #include<stdio.h> |
确实是我们输入的值 此时的Callback当然是没有值的 因为我们还没有将shellcode输入其中
0x03漏洞分析
我们的思路就是(其实和栈差不多) 先堆喷 控制堆中的数据 然后触发漏洞去执行我们的shellcode
堆喷
我们使用CreateEventA来进行堆喷 我们使用的是分页池 无法申请很多Event对象 但结构中的lpName参数 是分配在分页池中的 并且可以操控
1 | HANDLE CreateEventA( |
Lookaside Lists最多有256个0x20的块 windows在申请内存时会优先使用快表申请内存 不适合时才会使用空表 所以我们将使用快表结构 我们需要将shellcode放在函数的+0x4的位置 然后利用循环设置不同的lPname
1 | VOID GenerateObjectNameWithPayloadTrampoline(UCHAR Name[], UINT32 Length, ULONG_PTR Pivot) { |
0x04补丁分析
在安全版本中 将UninitializedMemory置为NULL 然后安全的调用了回调函数
0x05经验总结
最后了 其实最后两个思路有点相似 未初始化算是一类的吧 在池溢出的时候就了解到一些池的知识了 算是皮毛吧 需要看的还是很多的