Windows UAF 漏洞CVE-2021-34486分析
typedef struct _ETW_UPDATE_PERIODIC_CAPTURE_STATE { ULONG LoggerId; ULONG DueTime; //system time units (100-nanosecond intervals) ULONG NumOfGuids; GUID Guids[ANYSIZE_ARRAY]; } ETW_UPDATE_PERIODIC_CAPTURE_STATE, * PETW_UPDATE_PERIODIC_CAPTURE_STATE; |
__int64 __fastcall EtwpUpdatePeriodicCaptureState(unsigned int LoggerId, unsigned int DueTime, unsigned __int16 NumOfGuids, GUID *Guids) { ... // 如果没有定时器存在则直接创建定时器 if ( !LoggerContext_->ExTimerObject ) { TimerContextInfo = (CONTEXTINFO *)ExAllocatePoolWithTag(NonPagedPoolNx, 0x30ui64, 'UwtE'); // 创建回调函数参数,类型为_WORK_QUEUE_ITEM TimerContextInfo_ = TimerContextInfo; if ( !TimerContextInfo ) goto RETURN_ERROR_C0000017; TimerContextInfo->LoggerId = LoggerId;//InBuff1.LoggerId TimerContextInfo->Unknown = v22; TimerContextInfo->WorkItem.WorkerRoutine = SendCaptureStateNotificationsWorker; // worker的回调函数 TimerContextInfo->WorkItem.Parameter = TimerContextInfo; // worker回调函数的参数,也就是SendCaptureStateNotificationsWorker的参数 TimerContextInfo->WorkItem.List.Flink = 0i64; LoggerContext_->ExTimerObject = ExAllocateTimer((PEXT_CALLBACK)PeriodicCaptureStateTimerCallback, TimerContextInfo, 8u); // 保存定时器 } ExTimerObject = (PEX_TIMER)LoggerContext_->ExTimerObject; LoggerContext_->DueTime = 0xFFFFFFFFFF676980ui64 * DueTime; ExSetTimer((ULONG_PTR)ExTimerObject); // 超时时间以秒计算,为负数 LODWORD(LoggerContext_->ExTimerState) = 1; goto RETURN_1; ... RETURN_1: if ( (_InterlockedExchangeAdd64(pLock, 0xFFFFFFFFFFFFFFFFui64) & 6) == 2 ) ExfTryToWakePushLock(pLock); KeAbPostRelease((ULONG_PTR)pLock); RETURN_2: EtwpReleaseLoggerContext(LoggerContext_, 0i64); return (unsigned int)res_EtwpCheckNotificationAccess; } |
__int64 __fastcall EtwpUpdatePeriodicCaptureState(unsigned int LoggerId, unsigned int DueTime, unsigned __int16 NumOfGuids, GUID *Guids) { ... { ... FREE_POOLS_AND_RESET: GuidsPool = (void *)LoggerContext_->GuidsPool; if ( GuidsPool ) { ExFreePoolWithTag(GuidsPool, 0); LoggerContext->GuidsPool = 0i64; LOWORD(LoggerContext->NumOfGuids) = 0; } ... } if ( (_DWORD)NumOfGuids_ ) { while ( 1 ) // 循环判断用户传入的guid是否具有访问权限,如果有一个不满足就进入FREE_POOLS_AND_RESET分支 { res_EtwpCheckNotificationAccess = EtwpCheckNotificationAccess( &Guids[v4].Data1, (__int64)&LoggerContext_->field_0[0x124]); if ( res_EtwpCheckNotificationAccess < 0 ) break; if ( ++v4 >= (int)NumOfGuids_ ) goto ALL_GUIDS_HAVE_NOTIFICATION_ACCESS_OK; } res_EtwpCheckNotificationAccess = 0xC0000022; v8 = 0; goto FREE_POOLS_AND_RESET; } ALL_GUIDS_HAVE_NOTIFICATION_ACCESS_OK: ... } |
void __fastcall SendCaptureStateNotificationsWorker(CONTEXTINFO *TimerContextInfo) { ... if ( TimerContextInfo ) { LoggerContext = (LOGGERCONTEXT *)EtwpAcquireLoggerContextByLoggerId( TimerContextInfo->Unknown, LOWORD(TimerContextInfo->LoggerId), 0); if ( LoggerContext ) { pLock = &LoggerContext->Lock; ExAcquirePushLockExclusiveEx((ULONG_PTR)&LoggerContext->Lock, 0i64); LODWORD(LoggerContext__->ExTimerState) = 0; if ( *(_DWORD *)&LoggerContext__->field_0[336] ) { // 在第二个请求中我们已经将这个数量设置为空,所以后面会进入LABEL_31分支 NumOfGuids = LOWORD(LoggerContext__->NumOfGuids); if ( (_WORD)NumOfGuids ) { ... if ( (int)EtwpBuildNotificationPacket(v10, v23, v15, &v19) >= 0 ) { EtwpSendDataBlock(v12, v19); EtwpUnreferenceDataBlock(v19); } ... if ( LOWORD(LoggerContext__->NumOfGuids) && !LODWORD(LoggerContext__->ExTimerState) ) { ExSetTimer(LoggerContext__->ExTimer); LODWORD(LoggerContext__->ExTimerState) = 1; v2 = 1; } ... ... } } if ( (_InterlockedExchangeAdd64(pLock, 0xFFFFFFFFFFFFFFFFui64) & 6) == 2 ) ExfTryToWakePushLock(pLock); KeAbPostRelease((ULONG_PTR)pLock); EtwpReleaseLoggerContext(LoggerContext__, 0i64); if ( v2 ) // 这里没有进入上面分支所以不会设置为0 return; goto LABEL_31; // } } // 最终释放了之前的WORK_QUEUE_ITEM参数 LABEL_31: ExFreePoolWithTag(TimerContextInfo, 0); } |
漏洞修复
__int64 __fastcall EtwpUpdatePeriodicCaptureState(unsigned int LoggerId, unsigned int DueTime, unsigned __int16 NumOfGuids, GUID *Guids) { ... ExAcquirePushLockExclusiveEx(EtwpLoggerContext1 + 688, 0i64); CallbackContext1 = *(_QWORD *)(EtwpLoggerContext1 + 1080); // 取出之前创建的Context if ( CallbackContext1 ) // 如果存在了CallbackContext则进入 goto LABEL_31; if ( !(_WORD)v4 ) { LABEL_24: if ( (_InterlockedExchangeAdd64((volatile signed __int64 *)(EtwpLoggerContext1 + 688), 0xFFFFFFFFFFFFFFFFui64) & 6) == 2) ExfTryToWakePushLock(EtwpLoggerContext1 + 688); KeAbPostRelease(EtwpLoggerContext1 + 688); goto LABEL_27; } CallbackContext = ExAllocatePool2(64i64, 72i64, 0x55777445i64); // 设置LoggerContext+1080位置为创建的CallbackContext *(_QWORD *)(EtwpLoggerContext1 + 1080) = CallbackContext; CallbackContext1 = CallbackContext; ... Pool2 = (void *)ExAllocatePool2(256i64, 16 * v4, 0x55777445i64); *(_QWORD *)(CallbackContext1 + 24) = Pool2; if ( Pool2 ) { *(_WORD *)(CallbackContext1 + 16) = v4; memmove(Pool2, (const void *)InputBuffer_kernel_C, 16 * v4); if ( !*(_QWORD *)(CallbackContext1 + 8) ) { // 回调函数的参数变成了LoggerContext Timer = ExAllocateTimer((__int64)PeriodicCaptureStateTimerCallback, EtwpLoggerContext1, 8u); *(_QWORD *)(CallbackContext1 + 8) = Timer; if ( !Timer ) { ExFreePoolWithTag(*(PVOID *)(CallbackContext1 + 24), 0); *(_QWORD *)(CallbackContext1 + 24) = 0i64; *(_WORD *)(CallbackContext1 + 16) = 0; goto LABEL_11; } *(_QWORD *)(CallbackContext1 + 56) = EtwpLoggerContext1; *(_QWORD *)(CallbackContext1 + 48) = SendCaptureStateNotificationsWorker; *(_QWORD *)(CallbackContext1 + 32) = 0i64; // WORK_QUEUE_ITEM 的开始位置 } *((_QWORD *)&v21 + 1) = 0xFFFFFFFFFFFFFFFFui64; v17 = *(_QWORD *)(CallbackContext1 + 8); v18 = 0xFFFFFFFFFF676980ui64 * a2; *(_QWORD *)CallbackContext1 = v18; ExSetTimer(v17, v18, 0i64, (__int64)&v21); *(_DWORD *)(CallbackContext1 + 64) = 1; goto LABEL_24; } ... } void __fastcall PeriodicCaptureStateTimerCallback(__int64 Timer, __int64 EtwpLoggerContext) { if ( ExAcquireRundownProtectionCacheAwareEx( *(PEX_RUNDOWN_REF_CACHE_AWARE *)(*(_QWORD *)(*(_QWORD *)(EtwpLoggerContext + 1096) + 448i64) + 8i64 * *(unsigned int *)EtwpLoggerContext), 1u) ) { // EtwpLoggerContext + 1080 就是CallbackContext,+32位置就是WORK_QUEUE_ITEM 的开始位置 ExQueueWorkItem((PWORK_QUEUE_ITEM)(*(_QWORD *)(EtwpLoggerContext + 1080) + 32i64), NormalWorkQueue); } } |
参考链接
https://www.pixiepointsecurity.com/blog/advisory-cve-2021-34486.html