Vendor: Dell / PC-Doctor
Vendor URL: https://www.dell.com/support/contents/en-uk/article/product-support/self-support-knowledgebase/software-and-downloads/supportassist
Versions affected: SupportAssist for Windows version 3.7 or higher, between 2020-08-28 and 2020-10-22
Systems Affected: Windows
Author: richard.warren[at]nccgroup[dot]com
Advisory URL: https://www.dell.com/support/kbdoc/000184012
CVE Identifier: CVE-2021-21518
Risk: CVSSv3.1: 7.8 (AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H)

Summary

When running PC-Doctor modules, the Dell SupportAssist service attempted to load DLLs from a world-writable directory. Furthermore, it did not validate the signature of libraries loaded from this directory, leading to a “DLL Hijacking” vulnerability.

Impact

Successful exploitation of this issue would allow a low privileged user to execute arbitrary code with SYSTEM privileges. Note that whilst this vulnerability did affect default installs of SupportAssist, the vulnerable component was only distributed to systems that were running version 3.7 or higher through August 28th 2020 to October 22nd 2020.

Details

SupportAssist exposes a range of functionality via a desktop GUI component, allowing the user to carry out a number of tasks, on-demand, via the GUI. For example, launching a hardware scan or performing disk cleanup. This is achieved through the use of IPC with a WebSocket server, which then launches the requested task as a separate process (referred to as a PCDr module), which, due to the nature of the tasks, are often run with higher privileges (e.g. SYSTEM).

During testing it was identified that whilst launching one of these tasks, the PCDr module process that was launched would attempt to load DLLs from a predictable subdirectory of the C:WindowsTemp folder, which was writable by low privileged users – leading to a DLL hijacking issue. By placing a DLL within the predictable temp folder, the DLL would be loaded within the privileged process.

Root Cause Analysis

The root cause of this issue was identified to be due to the use of the Fody.Costura development package. Costura is a popular development library which is used to merge multiple .NET assemblies (i.e. an executable and multiple DLLs) into a single package for ease of distribution. Details about how Costura works to merge managed dependencies can be found in this blog post by Ryan Cobb. However, for unmanaged dependencies the process is slightly different. Rather than using AssemblyResolve events to handle and load embedded dependencies from memory at runtime – DLLs are instead written to a subdirectory of the users %TMP% folder – which for the SYSTEM user is C:WindowsTemp. The subdirectory name is generated using the MD5 sum of the embedded dependencies. For example, if the project contained a single unmanaged dependency named foo.dll with the MD5 hash of 3F2F72ED1DD8689DF5CE3D1617A51CDD, then the following structure would be created:

  • C:WindowsTemp3F2F72ED1DD8689DF5CE3D1617A51CDDfoo.dll

The following code is then inserted by Costura at compile-time and executed via a module level static constructor named Attach:

Once the embedded DLL dependencies have been written to the temporary folder, the PreloadUnmanagedLibraries and InternalPreloadUnmanagedLibraries functions are called. The code for the Costura InternalPreloadUnmanagedLibraries function is shown below:

This function first creates the temporary folder, before dropping the embedded DLLs into the directory. It then calls the SetDllDirectory API, which adds the specified directory to the DLL search path for the current process. This means that any DLLs that the current process attempts to load which are not found in the directory from which the application loaded, will be searched for in this directory.

LoadLibrary is then called on any dropped DLLs in order to preload them and ensure that any later calls to LoadLibrary return a handle to the previously (pre)loaded library. However, no call to SetDllDirectory(NULL) is called after, meaning that the search directory set in the SetDllDirectory remains for the process (and its descendants [see below]) lifetime.

Microsoft documents two specific remarks relating to the usage of SetDllDirectory:

Firstly, when SetDllDirectory is used, Safe DLL Search is effectively disabled, since the directory specified in the SetDllDirectory call is the second directory to be searched (after the current directory).

However, more importantly they note that SetDllDirectory affects child processes too (as long as the parent isn’t running as a protected process). What this means is that if a process running as SYSTEM calls SetDllDirectory with an lpPathName of a writeable directory, before creating a child process – the child process would also inherit the same search directory. This pattern leads to potential DLL hijacking issues if the child process attempts to load any DLLs which do not exist in the application directory.

Due to this pattern, a DLL hijacking issue was introduced into SupportAssist. During August 2020, a PC-Doctor Add-on was distributed via the Dell SupportAssist auto-update repository which used the Fody.Costura package. According to the update manifest, this plugin was distributed to any SupportAssist install running PCDr versions 6.0.7193.573 and greater at the time, as shown in the following screenshot:

These Add-on DLLs are automatically installed and loaded by the SupportAssist DSAPI.exe process, which runs as SYSTEM. This is the same process which is responsible for later launching the PCDr module processes launched at the request of the user (via the GUI application). Therefore, due to the use of Costura in an Add-on DLL in the parent process, a DLL hijacking issue is introduced in the child process. As many of the launched PcDr modules load DLLs that are not contained in the KnownDlls list, this issue is exploitable by launching several different “tasks”. An attacker simply has to place a missing DLL within the C:Temp directory, before launching a PCDr module, either via the GUI or through the Websocket IPC channel.

Proof of Concept

A Proof-of-Concept exploit, which leveraged this issue to achieve SYSTEM code execution without GUI interaction, was developed and shared with Dell. A screenshot showing successful exploitation is shown below:

Recommendation

This vulnerability was reported to the Dell PSIRT team on 2020-10-20. As a result, the vulnerable component was removed from the update repository on 2020-10-22, preventing further downloads of the vulnerable component. An update was also pushed via the auto-update mechanism to remove any existing installs of the vulnerable component.

To ensure that the vulnerable component has been removed, check for the following directories:

  • %ProgramData%PCDr7240AddonsUpgrade.7193.Part2_1
  • %ProgramData%PCDr7193AddonsUpgrade.7193.Part2_1

The SHA256 hash of the vulnerable DLL is:

  • 9853ae8bc48bdaa6135453b85f4add6c4c0b1b84c81d73b244b6e424d92577cd

The following Yara rule can be used to identify DLLs using the Costura library to load unmanaged DLLs:

rule costura_usage
{
    meta:
        description = "Identifies PE files using the Costura.Fody package"
    strings:
        $ = "Costura" ascii
        $ = "Timeout waiting for exclusive access" wide
        $ = "SetDllDirectory" ascii
        $ = { 00 00 41 (3?|4?) 00 (3?|4?) 00 (3?|4?) 00 (3?|4?) 00 (3?|4?) 00 (3?|4?) 00 (3?|4?) 00 (3?|4?) 00 (3?|4?) 00 (3?|4?) 00 (3?|4?) 00 (3?|4?) 00 (3?|4?) 00 (3?|4?) 00 (3?|4?) 00 (3?|4?) 00 (3?|4?) 00 (3?|4?) 00 (3?|4?) 00 (3?|4?) 00 (3?|4?) 00 (3?|4?) 00 (3?|4?) 00 (3?|4?) 00 (3?|4?) 00 (3?|4?) 00 (3?|4?) 00 (3?|4?) 00 (3?|4?) 00 (3?|4?) 00 (3?|4?) 00 (3?|4?) 00 00 }
    condition:
        uint16(0) == 0x5A4D and all of them
}

Vendor Communication

2020-10-20: Issue reported to Dell PSIRT
2020-10-22: Vulnerable component removed from the PC-Doctor repository
2020-12-20: Dell PSIRT confirm that the vulnerability has been remediated
2021-03-10: Advisory released by Dell
2021-03-10: Advisory released by NCC Group

About NCC Group

NCC Group is a global expert in cybersecurity and risk mitigation, working with businesses to protect their brand, value and reputation against the ever-evolving threat landscape. With our knowledge, experience and global footprint, we are best placed to help businesses identify, assess, mitigate & respond to the risks they face. We are passionate about making the Internet safer and revolutionizing the way in which organizations think about cybersecurity.

Published Date: 2021-03-10

Written by: Richard Warren