In this blog post, we examine the vendor-supplied patch addressing CVE-2018-6661. The vulnerability was initially reported to Intel Security (McAfee) in June 2017 and disclosed publicly in April 2018. Additionally, we contacted McAfee regarding the issues discussed in this post in August 2018.
Contributors: Omar El-Domeiri and Gaurav Baruah
At Exodus, we often encounter failed patches or discover adjacent zero-day vulnerabilities while conducting n-day vulnerability research. In 2018, our team has identified 24 publicly disclosed vulnerabilities that were reportedly patched but, in fact, were still vulnerable because the patch did not address the root cause. Failed patches can leave users at risk even if they vigilantly keep up with software updates and security advisories.
There are many reasons why a vendor-supplied patch may fail to improve the security of the software. In some instances, a patch may actually increase the attack surface and consequently introduce new vulnerabilities. While in other instances, a patch may be incomplete, leaving avenues by which the patch can be bypassed and the vulnerable code triggered. Often incomplete patches are the result of a vendor specifically patching for the PoC they receive from disclosure without addressing the root cause. In the case of CVE-2018-6661, we discovered an incomplete patch that left multiple ways for attackers to bypass the patch.
A publicly disclosed vulnerability for the Intel Security (McAfee) True Key software remains exploitable despite multiple vendor-supplied patches. Any logged in user, including the Guest account, can send a series of crafted requests to the True Key service to execute arbitrary code via a DLL-side loading attack vector. As a result, unprivileged users can escalate privileges to NT AUTHORITY\SYSTEM on any Windows machine with True Key installed.
True Key is a password manager supporting several methods of sign-in including face and fingerprint, email, master password or by using a trusted device. It is freely available for Windows, Mac OS X, Android and iOS devices but requires a subscription to store more than 15 passwords. Until recently, True Key was bundled with Adobe Flash and required users to opt-out during installation.
When True Key is installed on Windows it includes an always running service that listens on TCP port 30,000 on the loopback interface 127.0.0.1 which runs with SYSTEM privileges. The service coordinates functionality across various components of the True Key software by providing RPC mechanisms. In the case of this vulnerability, we are interested specifically in the SecureExecute RPC method which launches executables trusted by McAfee where trust is verified by digital signature.
By examining the vendor’s patch, we can see that the patch only addresses the problem within the McAfee.TrueKey.Sync.exe and only for one of its DLL dependencies, namely the McAfee.TrueKey.SDKLibAdapter import.When the program is run, the dot net runtime will dynamically load DLL dependencies required by the program. We can identify the direct dependencies by the imports at the top. Since Windows searches for DLLs in a specified order outlined in Microsoft’s documentation it is possible to provide a modified DLL within the same folder so that it will be imported. It should be noted that System imports are contained in the known DLLs list and can not be used in this way by an attacker.
The patch enforces that the SDKLibAdapter library must be found in the C:\Program Files\TrueKey folder (C:\Program Files\McAfee\TrueKey in more recent versions) which can not be written to by an unprivileged user. However, the binary also imports the NLog logging library and does not enforce a path constraint for the corresponding DLL. The patch is incomplete because it overlooks this and hence the nlog.dll can be utilized to allow arbitrary code execution just as the McAfee.TrueKey.SDKLibAdapter.dll could be used in versions prior to the patch. Furthermore, any other McAfee signed binary can be used to exploit the vulnerability as long as the binary depends on a DLL outside the list of known DLLs. There are multiple ways to go about finding DLL dependencies.
Reversing True Key
Upon inspection of the decompiled TrueKey service binary, it is clear that it is an Apache Thrift based service.
Thrift is a software library and set of code-generation tools developed at Facebook to expedite development and implementation of efficient and scalable backend services. Its primary goal is to enable efficient and reliable communication across programming languages by abstracting the portions of each language that tend to require the most customization into a common library that is implemented in each language. Specifically, Thrift allows developers to define datatypes and service interfaces in a single language-neutral file and generate all the necessary code to build RPC clients and servers.
Examining the code auto-generated by thrift for the SecureExecute command, we can gather the data types expected for such a request to the service.From this code, we can create our own thrift file for the subset of the RPC service that is necessary for exploitation.
The SecureExecute method takes two parameters — a 32-bit integer clientId and a string specifying the path to an executable file to run. Before executing a RPC request, the service verifies that the clientId matches a known value that it has issued previously.
The handler for the SecureExecute API request will create a SecureExecuteCommand object, wrap it in a CheckedCommand object and pass it to the runner.Sync() method which will call the CheckedCommand object’s Execute() method. CheckedCommand verifies that the clientId supplied in the request matches an existing ClientId that the service has already issued. If so, then it calls the Execute() method of the wrapped object which in this instance is a SecureExecuteCommand object.
SecureExecuteCommand.Execute() will inspect the requested executable to ensure that the file has been digitally signed by McAfee before spawning a child process running the executable.
So in order to get the service to actually execute a binary, we must provide it with a valid clientId and the binary must be signed by McAfee. ClientIds are issued via the RegisterClient method whose sole parameter consists of a YAPClient struct that can contain any number of optional fields. On registration, the service verifies that the client is a trusted client by checking the port field from the YAPClient struct. The port field is used to find the corresponding PID listening on that port and then the service checks that the executable associated with that PID has been digitally signed by McAfee.
In order to exploit the vulnerability, we will need to send a SecureExecute request to the True Key service requesting that it execute the McAfee.TrueKey.Sync.exe in a folder that contains a modified nlog.dll. There are multiple utilities available, such as dnSpy, for modifying a compiled dot net executable or DLL directly. Since the McAfee.TrueKey.Sync.exe calls the GetCurrentClassLogger() method, we modified this method to launch a child process that executes a file containing our payload within the same folder.
The exploit will function as intended even though our modifications do not adhere to the method’s type signature. The return value of Process.Start() is not a Logger object and any further use of the value returned from this method will likely throw an error, but once this code has executed we can utilize the child process running our payload to gain escalated privileges.
Initially, we send a RegisterClient request to the True Key service to get a valid clientId. Since we know that the service itself listens on port 30,000, our RegisterClient request will specify that value for the port field in the YAPClient struct. In effect, the service will verify that it trusts itself as a valid client and respond with a new clientId.
With a valid clientId in hand, we send a SecureExecute request with that clientId and an executablePath pointing to our copy of the McAfee.TrueKey.Sync.exe within a folder containing our modified nlog.dll. The dot net runtime will load our modified nlog.dll and when the GetCurrentClassLogger() method is called our pop.exe payload will be executed.
We’ve written the exploit as a metasploit module and here is a demonstration:
Active exploitation can be detected by inspecting loopback traffic to port 30,000 for SecureExecute requests where the executablePath parameter does not start with the C:\Program Files\McAfee\TrueKey prefix.
Microsoft has an informative article on the topic of Dynamic-Link Library Security with recommendations for how developers can safeguard their applications against this kind of attack. At the application level, the SecureExecute method should reject any requests where the executablePath does not begin with a prefix to a known write-protected folder such as C:\Program Files\McAfee\TrueKey. Additionally, the RegisterClient method should treat the port specified in the request as untrusted user input and verify the client in a more secure manner. If your organization does not rely on True Key then uninstalling this software will remove the vulnerable service.
About Exodus Intelligence N-Day Subscription Offering
In addition to internally discovered zero-day vulnerabilities, Exodus Intelligence also offers a feed comprised of threats that have been publicly disclosed by outside organizations or the vendors themselves. Subscribers of our n-day offering gain access to a collection of vetted, reliable exploits and corresponding documentation enabling them to ensure their defensive measures have been implemented properly. This is critically important in cases where the vendor-supplied patch fails to address the root cause, since the existence of a patch may falsely assure users they are no longer at risk.
We disclosed the failed patch to McAfee and they published an update in response. However, we tested the latest version available (126.96.36.199 as of September 7th, 2018) and found that it remains vulnerable requiring no changes to our exploit.