0X00 前言
打算尝试些有点难度的东西 本来是想去调CVE-2015-0057
这个漏洞然后去写POC
的 但弄了一下午 发现只是了解了漏洞的原理以及触发流程 或许如此 然后也没有现成的POC
去让我模仿去编写 以前碰到POC
之后总是C2C
觉得这样无法使自己成长起来 首先踏出的第一步应该是根据思路去编写“自己”的POC
慢慢来吧 所以找了许久之后 还是用CVE-2016-3308
来实现我的第一步 大致了解之后貌似还是和菜单相关的东西 so~ 前面写的一些可以联系起来?
0X01 漏洞原理
CVE-2016-3308
的漏洞是在win32k!xxxInsertMenuItem
函数中 该函数调用两次MNLookUPMenuItem
函数 第一次调用MNLookUpItem
进行查找uItem
所代表的tagItem
更新当前菜单为目标菜单项所属菜单 第二次调用之前 会调用DesktopAlloc
为tagItem
重新申请堆内存 由于地址已经改变 所以第一次查到的tagItem
地址也发生了改变 所以会第二次调用MNLookUpItem
重新查找tagItem
地址 但第二次查找时 使用的菜单项还是第一次的 所以我们就可以做些事情 下面再细说吧
0X02 触发
一些分析
先看看xxxInserMenuitem
函数 该函数用于在指定位置插入一个菜单项
1 | BOOL xxxInsertMenuItem( |
再来看看xxxMNLookUPMenuItem
函数 该函数中 先判断菜单是否有子菜单 有的话就递归查找 没有的话判断子菜单是否符合要求
1 | PITEM MNLookUpItem( |
在xxxInserMenuitem
函数中 第一次调用:
1 | if ( uItem != -1 ) |
当我们要插入的当前菜单tagMenu->cItem>tagMenu->cAlloced
时 然后使用DesktopAlloc
函数来重新为tagItem
申请堆内存 然后也就来到了我们的第二次调用MNLookUpItem
函数重新查找tagItem
地址
1 | v13 = *(_DWORD *)(v5 + 28); |
接下来使用memmove
[函数](memmove, wmemmove | Microsoft Docs)将待插入的位置后面所有元素移了一个单位 这个函数的第三个参数 是通过地址来计算需要复制的字节数 在通过第二次MNLookUpItem
进行查找时 查找的菜单仍然是第一次调用MNLookUpItem
后的菜单 没有进行更新 假如我们返回的v6
是菜单的子菜单内容 此时v6
指向的是子菜单 则此时就会出现严重的错误 因为计算出来的长度在逻辑上没有意义 并且有可能发生堆溢出
1 | v26 = ++*(_DWORD *)(v5 + 32); |
那么如何改变这个呢? 在第一次调用MNLookUpItem
和第二次调用MNLookUpItem
函数之间 有这样一段代码
1 | if ( !(*(_BYTE *)(v5 + 20) & 1) ) |
编写POC
首先来再来看看 如何将uItem
置为1
当我下断点进行验证的时候 发现了到达将uItem
置为1并不容易 不过到达这里还是很容易的 下的断点如下
1 | ba e1 win32k!xxxInsertMenuItem+0xf3 |
1 | if ( v6 && !fByFosition ) //这个if语句不能通过 当我创建的是一个窗口的时候 就无法对v9进赋值 从而导致下一个if无法通过 也就无法到达uItem=1 |
所以需要将fByFosittion
设置为false
就可以到此处
emmmmm
还有一点 就是函数DesktopAlloc
这个函数为tagItem
函数申请内存 每次申请8个 第9个的时候 会重新分配
1 | if ( *(_DWORD *)(v5 + 52) ) |
所以就有了如下poc
其实代码的流程很清晰 我逐步在代码中解释一下
1 | #include <Windows.h> |
emmmm
总结一下过程
1 | -->首先是创建一个菜单 |
0X03 总结
好吧 这个POC
的编写过程我都是费了好大劲加上问师傅和师傅们的博客才了解到的 先是无法到达uItem
=1那个点 因为自己在创建窗口的时候 只能到达它的上面 无论我做什么都无法到达 经过多次调试的fail
发现 我需要将fByFosittion
设置为false
才可以到达此处 接下是无法理解使用DesktopAlloc
每次分配的是8个内存 当我使用IDA
来跟踪参数 或者使用WinDbg
来动态调试 依然没有得到有效的信息 emmmm
最后问了师傅解决了问题
0X04 链接
用到的一些函数定义:memmove