Micropatching Incompletely Patched Local Privilege Escalation in User Profile Service (CVE-2021-34484)

 


 

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: 

  1. Windows 10 v21H1 (32 & 64 bit) updated with October or November 2021 Updates
  2. Windows 10 v20H2 (32 & 64 bit) updated with October or November 2021 Updates
  3. Windows 10 v2004 (32 & 64 bit) updated with October or November 2021 Updates
  4. Windows 10 v1909 (32 & 64 bit) updated with October or November 2021 Updates
  5. Windows Server 2019 64 bit updated with October or November 2021 Updates
While some older Windows versions also seem to be theoretically affected, the vulnerable code is different there, making the window for winning the race condition extremely narrow and probably unexploitable.
 
 
Micropatches for this vulnerability will be free until Microsoft has issued an official fix. If you want to use them, create a free account in 0patch Central, then install and register 0patch Agent from 0patch.com. Everything else will happen automatically. No computer reboots will be needed.
 

We'd like to thank Abdelhamid Naceri for finding this issue and sharing details, which allowed us to create a micropatch and protect our users. Thanks also to Will Dormann for useful tips on reproducing this issue.

To learn more about 0patch, please visit our Help Center.


 


 

Article Link: 0patch Blog: Micropatching Incompletely Patched Local Privilege Escalation in User Profile Service (CVE-2021-34484)