文章发表于:https://www.ch35tnut.site/zh-cn/vulnerability/cve-2023-36874-windows-error-reporting-service-eop/
基本信息
Windows error resporting service中存在权限提升漏洞,当攻击者可以创建符号链接及目录时,可以利用这个漏洞提升至SYSTEM权限。
影响版本
略
环境搭建
-
Windows 10 21H2 6月补丁
技术分析&调试
补丁对比
diff wercplsupport.dll,主要改了CWerComReport::SubmitReport,wercplsupport.dll是Windows error reporting 服务的主dll文件。
对比发现补丁直接阻断了后续CAutoImpersonate::ImpersonateUserHighestPrivs
和CWerComReport::_SubmitReport
的调用
//未修复
__int64 __fastcall CWerComReport::SubmitReport(
CWerComReport *this,
unsigned __int16 *a2,
unsigned int a3,
struct IWerReportSubmitCallback *a4,
unsigned __int16 **a5,
unsigned int *a6)
{
int v10; // ebx
int v12; // [rsp+30h] [rbp-18h] BYREF
__int64 v13; // [rsp+38h] [rbp-10h]
v13 = -2i64;
v12 = 2;
if ( !CAutoImpersonate::g_bEnableImpersonate
|| (v10 = CAutoImpersonate::ImpersonateUserHighestPrivs((CAutoImpersonate *)&v12), v10 >= 0) )
{
v10 = CWerComReport::_SubmitReport((CWerComReport *)((char *)this - 24), a2, a3, a4, a5, a6);
}
CAutoImpersonate::~CAutoImpersonate((CAutoImpersonate *)&v12);
return (unsigned int)v10;
}
// 修复代码
__int64 __fastcall CWerComReport::SubmitReport(
CWerComReport *this,
unsigned __int16 *a2,
unsigned int a3,
struct IWerReportSubmitCallback *a4,
unsigned __int16 **a5,
unsigned int *a6)
{
int v11; // ebx
int v12; // [rsp+30h] [rbp-18h] BYREF
__int64 v13; // [rsp+38h] [rbp-10h]
v13 = -2i64;
if ( (unsigned __int8)wil::details::FeatureImpl<__WilFeatureTraits_Feature_MSRC80633_DisableWerCplSupport>::__private_IsEnabled(&`wil::Feature<__WilFeatureTraits_Feature_MSRC80633_DisableWerCplSupport>::GetImpl'::`2'::impl) )
return 0x80004001i64;
v12 = 2;
if ( !CAutoImpersonate::g_bEnableImpersonate
|| (v11 = CAutoImpersonate::ImpersonateUserHighestPrivs((CAutoImpersonate *)&v12), v11 >= 0) )
{
v11 = CWerComReport::_SubmitReport((CWerComReport *)((char *)this - 24), a2, a3, a4, a5, a6);
}
CAutoImpersonate::~CAutoImpersonate((CAutoImpersonate *)&v12);
return (unsigned int)v11;
}
根据函数名CAutoImpersonate::ImpersonateUserHighestPrivs可知,该函数为模拟用户最高的权限并提交report
动态调试
开启Problem Reports Control Panel Support
服务,对应路径为C:WindowsSystem32svchost.exe -k netsvcs -p
。使用oleviewdotnet查询Problem Reports Control Panel Support
服务对应的ole信息
对应的COM接口的CLSID为
-
CLSID: 0E9A7BB5-F699-4D66-8A47-B919F5B6A1DB
-
AppID: 136A0DC7-DF5C-4271-A2AC-15DF1A1323F2查看这个COM的接口信息
class __declspec(uuid("6620c14b-70ae-4d4e-a4f6-91a7dcc582c2")) IErcLuaSupport : public IUnknown {
public:
virtual HRESULT __stdcall Proc3(/* Stack Offset: 8 */ IWerStoreFactory** p0);
};
class __declspec(uuid("4904c154-426f-4c88-8ec2-4543d18670f7")) IWerStoreFactory : public IUnknown {
public:
virtual HRESULT __stdcall Proc3(/* Stack Offset: 8 */ IWerStore** p0);
virtual HRESULT __stdcall Proc4(/* Stack Offset: 8 */ IWerStore** p0);
};
class __declspec(uuid("1e3a0e4f-1412-444f-8a94-fc6a09cd4195")) IWerStore : public IUnknown {
public:
virtual HRESULT __stdcall Proc3();
virtual HRESULT __stdcall Proc4(/* Stack Offset: 8 */ BSTR* p0);
virtual HRESULT __stdcall Proc5(/* Stack Offset: 8 */ BSTR p0);
virtual HRESULT __stdcall Proc6(/* Stack Offset: 8 */ BSTR p0, /* Stack Offset: 16 */ IWerReport** p1);
virtual HRESULT __stdcall Proc7(/* Stack Offset: 8 */ BSTR p0, /* Stack Offset: 16 */ BSTR* p1);
};
class __declspec(uuid("d01b8f28-0bd1-4652-a415-8229f5ee506c")) IWerReport : public IUnknown {
public:
virtual HRESULT __stdcall Proc3(/* Stack Offset: 8 */ int64_t* p0);
virtual HRESULT __stdcall Proc4(/* Stack Offset: 8 */ int64_t* p0);
virtual HRESULT __stdcall Proc5(/* Stack Offset: 8 */ BSTR* p0);
virtual HRESULT __stdcall Proc6(/* Stack Offset: 8 */ IWerKeyValueList** p0);
virtual HRESULT __stdcall Proc7(/* Stack Offset: 8 */ IWerKeyValueList** p0);
virtual HRESULT __stdcall Proc8(/* Stack Offset: 8 */ IWerStringList** p0);
virtual HRESULT __stdcall Proc9(/* Stack Offset: 8 */ int64_t* p0);
virtual HRESULT __stdcall Proc10(/* Stack Offset: 8 */ int64_t* p0);
virtual HRESULT __stdcall Proc11(/* Stack Offset: 8 */ BSTR* p0);
virtual HRESULT __stdcall Proc12(/* Stack Offset: 8 */ BSTR* p0);
virtual HRESULT __stdcall Proc13(/* Stack Offset: 8 */ IWerStringList** p0);
virtual HRESULT __stdcall Proc14(/* Stack Offset: 8 */ IWerStringList** p0);
virtual HRESULT __stdcall Proc15(/* Stack Offset: 8 */ int64_t* p0);
virtual HRESULT __stdcall Proc16(/* Stack Offset: 8 */ struct Struct_1* p0);
virtual HRESULT __stdcall Proc17(/* Stack Offset: 8 */ int64_t* p0);
virtual HRESULT __stdcall Proc18(/* Stack Offset: 8 */ int64_t* p0);
virtual HRESULT __stdcall Proc19(/* Stack Offset: 8 */ int64_t* p0);
virtual HRESULT __stdcall Proc20(/* Stack Offset: 8 */ BSTR p0, /* Stack Offset: 16 */ BSTR* p1);
virtual HRESULT __stdcall Proc21(/* Stack Offset: 8 */ BSTR* p0);
virtual HRESULT __stdcall Proc22(/* Stack Offset: 8 */ int64_t p0, /* Stack Offset: 16 */ int64_t* p1, /* Stack Offset: 24 */ int64_t* p2, /* Stack Offset: 32 */ BSTR* p3, /* Stack Offset: 40 */ BSTR* p4);
virtual HRESULT __stdcall Proc23(/* Stack Offset: 8 */ int64_t p0, /* Stack Offset: 16 */ BSTR* p1);
virtual HRESULT __stdcall Proc24(/* Stack Offset: 8 */ BSTR p0, /* Stack Offset: 16 */ int64_t p1, /* Stack Offset: 24 */ IWerReportSubmitCallback* p2, /* Stack Offset: 32 */ /* unique */BSTR* p3, /* Stack Offset: 40 */ /* unique */int64_t* p4);
virtual HRESULT __stdcall Proc25();
};
这里需要知道Windows的COM模型,COM模型定义了二进制标准,以支持组件复用。将操作系统API抽象成了接口,可以通过接口的标识符实例化COM对象并通过COM对象调用服务接口。即
当使用COM接口调用error reporting 服务并提交错误报告时,error reporting会启动 C:WindowsSystem32wermgr.exe
,并且启动时权限为 NT AUTHORITYSYSTEM
。
追溯调用栈查看此事件的调用栈,wer!WerpAuxmdMapFile+0x3887d
处调用了CreateProcessW
wer!WerpAuxmdMapFile+0x3887d
位于 UtilLaunchWerManager
函数内,代码如下
__int64 __fastcall UtilLaunchWerManager(
const unsigned __int16 **a1,
__int64 a2,
__int64 a3,
void *a4,
void **a5,
void **a6,
unsigned int a7,
void **a8)
{
....
WCHAR Buffer[264]; // [rsp+148h] [rbp+40h] BYREF
v43 = -2i64;
v39 = a1;
v8 = a5;
lpValue = a8;
0, 0x208ui64);
0i64; =
0i64; =
.....
goto LABEL_67;
}
v11 = StringCchCatW(Buffer, 0x104ui64, L"\wermgr.exe");
v12 = v11;
if ( v11 >= 0 )
{
v12 = CString::Sprintf((CString *)lpCommandLine, L""%s" ", Buffer);
if ( (v12 & 0x80000000) != 0 )
{
if ( WPP_GLOBAL_Control != (HKEY)&WPP_GLOBAL_Control && ((_BYTE)WPP_GLOBAL_Control[7] & 1) != 0 )
{
*)WPP_GLOBAL_Control + 2), 20i64, &WPP_80b9a2815f1633611b5141c011dbf465_Traceguids, Buffer);
goto LABEL_37;
}
goto LABEL_38;
}
v13 = 0;
v14 = lpCommandLine[0];
while ( v13 < 0xE )
{
.....
v19 = CString::Append((CString *)lpCommandLine, v40[0]);
if ( v19 >= 0 || WPP_GLOBAL_Control == (HKEY)&WPP_GLOBAL_Control || ((_BYTE)WPP_GLOBAL_Control[7] & 1) == 0 )
{
v14 = lpCommandLine[0];
}
....
if ( UpdateProcThreadAttribute(v10, 0, 0x20002ui64, lpValue, 8i64 * a7, 0i64, 0i64) )
{
112; =
v45 = v10;
if ( CreateProcessW(Buffer, v14, 0i64, 0i64, 2, 0x80000u, 0i64, 0i64, &StartupInfo, &hObject) )
{
v12 = 0;
}
......
}
向上追溯调用栈,UtilLaunchWerManager函数由 CReportManager::ReportProblemOutOfProcess调用, 再上层函数为CReportManager::ReportProblem,CReportManager::ReportProblem由ReportHandleInstance::SubmitReport调用,在上层函数为WerpSubmitReportFromStore。在wecplsupport!DllCanUnloadNew+0x2bf2处调用了wer.dll!WerpSubmitReportFromStore函数。
wercplsupport!DllCanUnloadNew+0x2bf2
实际位于 wercplsupport!CWerComReport::_SubmitReport
函数内,代码如下。
__int64 __fastcall CWerComReport::_SubmitReport(
void **this,
unsigned __int16 *a2,
unsigned int a3,
struct IUnknown *a4,
unsigned __int16 **a5,
unsigned int *a6)
{
......
v24 = &CStubUI::`vftable';
if ( a4 )
((void (__fastcall *)(struct IUnknown *))a4->lpVtbl->AddRef)(a4);
v25 = a4;
v23[0] = 0i64;
TokenHandle = 0i64;
v26 = 0;
v10 = a5;
if ( a5 )
{
SysFreeString(*a5);
*v10 = 0i64;
}
WerApiLock = CWerApiAutoLock::TryGetWerApiLock((CWerApiAutoLock *)v23, (struct CWerComReport *)this);
if ( WerApiLock >= 0 )
{
.....
}
else
{
CurrentThread = GetCurrentThread();
if ( OpenThreadToken(CurrentThread, 0xF01FFu, 1, &TokenHandle) || GetLastError() == 1008 )
{
.....
}
else
{
WerApiLock = WerpSubmitReportFromStore(
*((void **)this[5] + 4),
a2,
this[4],
(struct IReportUI *)((unsigned __int64)&v24 & -(__int64)(a4 != 0i64)),
&v21,
a3,
(enum _WER_SUBMIT_RESULT *)&v20);
.....
}
_SubmitReport由 CWerComReport::SubmitReport调用,而
CWerComReport::SubmitReport为IWerReport接口公开的函数。
__int64 __fastcall CWerComReport::SubmitReport(
CWerComReport *this,
unsigned __int16 *a2,
unsigned int a3,
struct IWerReportSubmitCallback *a4,
unsigned __int16 **a5,
unsigned int *a6)
{
int v10; // ebx
int v12; // [rsp+30h] [rbp-18h] BYREF
__int64 v13; // [rsp+38h] [rbp-10h]
v13 = -2i64;
v12 = 2;
if ( !CAutoImpersonate::g_bEnableImpersonate
|| (v10 = CAutoImpersonate::ImpersonateUserHighestPrivs((CAutoImpersonate *)&v12), v10 >= 0) )
{
v10 = CWerComReport::_SubmitReport((CWerComReport *)((char *)this - 24), a2, a3, a4, a5, a6);
}
CAutoImpersonate::~CAutoImpersonate((CAutoImpersonate *)&v12);
return (unsigned int)v10;
}
所以可以总结出调用链:wecplsupport!CWerComReport::SubmitReport->
wecplsupport!CWerComReport::_SubmitReport->wer.dll!WerpSubmitReportFromStore...->CreateProcessW
问题在于在调用CreateProcessW时,CreateProcessW会使用攻击者设置的文件重定向,但将使用调用CreateProcessW的进程的security token设置进程的context,而不是模拟token来设置进程的security context。
也就是攻击者可以通过文件重定向将 C:WindowsSystem32
重定向到攻击者可控目录,并且在可控目录写入恶意 wermgr.exe
,当触发CreateProcessW时,CreateProcessW将使用攻击者控制的目录的wermgr.exe文件而不是系统在C:WindowsSystem32
目录下的wermgr.exe文件。并且该进程上下文继承了调用进程的上下文,即继承了wer服务的权限。
动态调试
在 UtilLaunchWerManager
断点
bp wer!UtilLaunchWerManager
调试器断下
0:006> g
Breakpoint 2 hit
wer!UtilLaunchWerManager+0xf3:
00007ffb`7b11a23f e87cb3f7ff call wer!StringCchCatW (00007ffb`7b0955c0)
0:006> rrcx
rcx=00000041e2efbce0
补丁分析
前面知道补丁直接阻断了后续调用_submit,也就没办法再调用CreateProcess,从而阻断了调用链。
PoC:
https://github.com/Wh04m1001/CVE-2023-36874
需要注意的是运行poc需要使用不在admin
组的用户,新增用户运行
net user test 123456 /add
参考链接
https://www.crowdstrike.com/blog/falcon-complete-zero-day-exploit-cve-2023-36874/
原文始发于微信公众号(闲聊趣说):CVE-2023-36874 Windows 错误报告服务权限提升漏洞
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论