by Mitja Kolsek, the 0patch Team
August 2021 Windows Updates brought a fix for CVE-2021-34484, found and reported by security researcher Abdelhamid Naceri. This vulnerability was considered by Microsoft to be an "arbitrary directory deletion" bug, allowing a locally logged-on attacker to delete a folder on the computer. This, combined with the fact that the attacker must also have credentials of another user who can locally log on to the same computer, made the bug seem fairly uninteresting.
However, Abdelhamid subsequently reviewed Microsotf's fix and found it to be incomplete, bypassable with a small change to the attack script. Furthermore, he confirmed the vulnerability was more impactful than described in Microsoft's advisory, namely enabling local privilege escalation from a regular user to System. Consequently, a write-up and proof of concept were published, which allowed us to analyze the vulnerability and create a micropatch for it.
The Vulnerability
The vulnerability lies in the User Profile Service, specifically in the code responsible for creating a temporary user profile folder in case the user's original profile folder is damaged or locked for some reason. Abdelhamid found that the process (executed as Local System) of copying folders and files from user's original profile folder to the temporary one can be attacked with symbolic links to create attacker-writable folders in a system location from which a subsequently launched system process would load and execute attacker's DLL.
The crux of the attack is in quickly creating a symbolic link in the temporary user profile folder (C:\Users\TEMP) so that when the User Profile Service copies a folder from user's original profile folder, it will end up creating a folder somewhere else - where the attacker would normally not have permissions to create one.
Microsoft, even though believing the vulnerability only allowed for deletion of an arbitrarily "symlinked" folder, made a conceptually correct fix: it checked whether the destination folder under C:\Users\TEMP was a symbolic link, and aborted the operation if so. The incompleteness of this fix, as noticed by Abdelhamid, was in the fact that the symbolic link need not be in the upper-most folder (which Microsoft's fix checked), but in any folder along the destination path.
Admittedly, this bug was not easy to reproduce, as it requires winning a race condition and that depends on lots of factors. Nevertheless, an actual attacker would have an unlimited number of attempts and would not be dismayed by that. A more significant obstacle for them would be obtaining additional user's credentials, which seem to be needed in order to exploit this vulnerability. As stated by Abdelhamid, "it might be possible to do it without knowing someone else password." but until someone finds a way to do so, we shall assume this to be a requirement.
While this vulnerability already has its CVE ID (CVE-2021-33742), we're considering it to be without an official vendor fix and therefore a "0day".
Our Micropatch
Our micropatch extends the incomplete security check from Microsoft's fix to the entire destination path by calling GetFinalPathNameByHandle and thus resolving any symbolic links it may contain. Then, by comparing the original path and the "resolved" path, it determines whether any symbolic links are present; if not, original code execution is resumed, otherwise the creation of a temporary user profile is aborted.
Our micropatch (green code blocks) injected in the original code of profext.dll. |
Source code of our micropatch:
MODULE_PATH "..\Affected_Modules\profext.dll_10.0.19041.1165_Win10-2004_64-bit_u202110\profext.dll"
PATCH_ID 708
PATCH_FORMAT_VER 2
VULN_ID 7184
PLATFORM win64
patchlet_start
PATCHLET_ID 1
PATCHLET_TYPE 2
PATCHLET_OFFSET 0x15065
N_ORIGINALBYTES 5
JUMPOVERBYTES 0
PIT Kernel32.dll!GetFinalPathNameByHandleW,Kernel32.dll!LocalAlloc,msvcrt.dll!_wcsicmp,profext.dll!0x150c8,Kernel32.dll!LocalFree
code_start
; original path is on rbx
mov rcx, 0 ; LMEM_FIXED
mov rdx, 208h ; number of bytes to allocate
sub rsp, 20h ; home space
call PIT_LocalAlloc ; allocates the specified number of bytes on the heap
add rsp, 20h ; restore stack pointer
mov rcx, [rsp+40h] ; hFile, handle to file
push rax ; save pointer to heap buffer for _wcsicmp
push rax ; save pointer to heap buffer for LocalFree
mov rdx, rax ; pointer to allocated memory
mov r9d, 0 ; type of returned result, FILE_NAME_NORMALIZED
mov r8d, 208h ; max length of Windows path, the size of lpszFilePath
sub rsp, 20h ; home space
call PIT_GetFinalPathNameByHandleW ; retrieve final path for the specified file
add rsp, 20h ; restore stack pointer
pop rcx ; pointer to allocated buffer
lea rcx, [rcx+8] ; GetFinalPathNameByHandleW returns path with \\?\, we get rid of that
mov rdx, rbx ; current path
sub rsp, 20h ; home space
call PIT__wcsicmp ; compare two null terminated paths
add rsp, 20h ; restore stack pointer
cmp rax, 0 ; are strings equal?
je END ; if equal, then no links exist, proceed with normal execution
pop rcx ; pointer to allocated buffer
call PIT_LocalFree ; free allocated buffer
call PIT_ExploitBlocked ; report exploit attempt
jmp PIT_0x150c8 ; error out
END:
pop rcx ; pointer to allocated buffer
call PIT_LocalFree ; free allocated buffer
; and continue with normal execution
code_end
patchlet_end
And the video of our micropatch in action. Without the micropatch, exploit works; with the micropatch, corrected code in User Profile Service determines that a destination path contains a symbolic link and aborts the creation of a temporary profile folder.
This micropatch was written for:
-
Windows 10 v21H1 (32 & 64 bit) updated with October or November 2021 Updates
- Windows 10 v20H2 (32 & 64 bit) updated with October or November 2021 Updates
- Windows 10 v2004 (32 & 64 bit) updated with October or November 2021 Updates
- Windows 10 v1909 (32 & 64 bit) updated with October or November 2021 Updates
- Windows Server 2019 64 bit updated with October or November 2021 Updates
Article Link: 0patch Blog: Micropatching Incompletely Patched Local Privilege Escalation in User Profile Service (CVE-2021-34484)