前言
CVE-2021-34486是在ETW请求更新周期性捕获中的UAF漏洞,可以通过分配可控的缓冲区,释放,二次使用该缓冲区来执行任意代码。
**01 **影响版本
https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-34486
**02 **ETW相关
ETW是内核中一个高效的事件追踪机制,可以记录系统内核或者应用程序的事件到日志文件。
ETW主要由三部分组成:
Controllers(事件控制器),用来开关event trace 会话 和 Providers。
Providers(事件提供器), 用来提供事件。
Consumers(事件消耗器),用来处理事件。
Sessions(事件管理器),用来管理和刷新事件。
**03 **逆向分析
在NtTraceControl函数中,通过FunctionCode(0x25)来控制调用EtwpUpdatePeriodicCaptureState函数。
__int64 __fastcall NtTraceControl(
unsigned int a1,
unsigned int *a2,
unsigned int a3,
volatile void *a4,
unsigned int Length,
unsigned int *a6)
{
···
case 0x25u:
if ( v18 < 0xC )
goto LABEL_61;
NumOfGuids = *((unsigned __int16 *)LoggerId + 4);
if ( (unsigned int)NumOfGuids <= 0x10 )
{
DueTime = *((_DWORD *)LoggerId + 1);
if ( DueTime - 1 > 3 )
{
if ( 16 * NumOfGuids + 12 == v18 )
{
if ( (_WORD)NumOfGuids )
Guids = (char *)LoggerId + 12;
EtwpUpdatePeriodicCaptureState(*(_DWORD *)LoggerId, DueTime, NumOfGuids, Guids);
···
}
EtwpUpdatePeriodicCaptureState函数的参数的逆向,其中第二个参数DueTime来源于EtwpUpdatePeriodicCaptureState函数中相关使用进行逆向得出,由于第二个参数DueTime只在函数最后使用,而ExSetTimer是用来设置定时器的时间,所以可知参数二为定时器时间。
__int64 __fastcall EtwpUpdatePeriodicCaptureState(
unsigned int LoggerId,
unsigned int DueTime,
unsigned __int16 NumOfGuids,
char *Guids)
{
···
v18 = 0xFFFFFFFFFF676980ui64 * DueTime;
LoggerContext_->RelativeTimerDueTime = v18;
ExSetTimer((ULONG_PTR)PeriodicCaptureStateTimer, v18, 0i64, (__int64)&v24);
···
}
再配合动态调试可知,第一次进入EtwpUpdatePeriodicCaptureState,rdx为0,因为并未设置定时器时间,然后观察参数3
r8和r9内存的值可知,参数3代表GUID的数量,参数4代表GUID。
0: kd> ba e1 nt!EtwpUpdatePeriodicCaptureState
0: kd> g
Breakpoint 0 hit
nt!EtwpUpdatePeriodicCaptureState:
fffff801`7793aeb4 48895c2410 mov qword ptr [rsp+10h],rbx
1: kd> r
rax=ffffab0db805824c rbx=000000000000001c rcx=000000000000001f
rdx=0000000000000000 rsi=ffffab0db8058240 rdi=0000000000000000
rip=fffff8017793aeb4 rsp=ffffcc8e375c69d8 rbp=ffffcc8e375c6b80
r8=0000000000000001 r9=ffffab0db805824c r10=fffff80177000000
r11=0000000000001001 r12=ffffab0db805824c r13=000000f50d73f420
r14=000000000000001c r15=ffffe50a8e67b000
iopl=0 nv up ei pl nz na pe nc
cs=0010 ss=0018 ds=002b es=002b fs=0053 gs=002b efl=00040202
nt!EtwpUpdatePeriodicCaptureState:
fffff801`7793aeb4 48895c2410 mov qword ptr [rsp+10h],rbx ss:0018:ffffcc8e`375c69e8=000000000000001c
1: kd> dd r9
ffffab0d`b805824c 14f8138e 580b3b61 09264b54 60e48a37
ffffab0d`b805825c 006d0061 03030000 3066744e 00780065
ffffab0d`b805826c 00000065 b6a5d9a0 ffffab0d b8142468
ffffab0d`b805827c ffffab0d 03ccb'586 000000a0 00000000
ffffab0d`b805828c 00000000 0303ff00 74705041 0064006e
ffffab0d`b805829c 0077006f 42424242 42424242 42424242
ffffab0d`b80582ac 42424242 42424242 42424242 00380061
ffffab0d`b80582bc 00340031 03030000 64536553 00320065
所以可得出当前的结构为
typedef struct _ETW_UPDATE_PERIODIC_CAPTURE_STATE
{
ULONG LoggerId;
ULONG DueTime;
ULONG NumOfGuids;
GUID Guids[ANYSIZE_ARRAY];
} ETW_UPDATE_PERIODIC_CAPTURE_STATE, * PETW_UPDATE_PERIODIC_CAPTURE_STATE;
而EtwpUpdatePeriodicCaptureState函数中的TimerContextInfo结构,分配了EtwU池标记的 0x30
字节的pool,只能配合逆向进行动态调试得到相关结构为:
typedef struct _CONTEXTINFO
{
WORK_QUEUE_ITEM WorkItem;
ULONG64 Unknown;
USHORT LoggerId;
UCHAR Padding[6]; //不重要数据用padding填充
} CONTEXTINFO, *PCONTEXTINFO;