Application whitelisting is a strong control. Implemented correctly it will stop unskilled attackers before they get a foothold in the network, and slow down or trigger detection for skilled attackers. But for application whitelisting to be successful, it has to be implemented correctly.
As I am partial to using OS built-in security features instead of adding on extra layers of software, and potentially introducing new vulnerabilities, I think Device Guard looks like one of the best options on the market for enterprises running Windows 10. You won’t even have to bother with salespeople and license costs.
In the next few blog posts I will outline some bypass techniques I discovered when exploring the attack surface of User Mode Code Integrity (UMCI). UMCI is the part of Device Guard responsible for controlling which executables, DLL’s, and scripts that are allowed to run in user space, and how they are limited in their behavior. Executables and DLL’s that are not allowed by the deployed policy cannot be loaded, and scripts are constrained in their behavior. The bypasses I present all relate to signed binaries, as digital signatures are a very common basis for application whitelisting policies in dynamic environments, since it allows applications to be updated, as long as the new executables have been signed by the same signer.
The techniques I am going to describe in this post and the next are likely to be usable if a bypass is needed for a policy that was created by following the steps outlined in Microsoft's own guide for deploying Device Guard, “Steps to Deploy Windows Defender Application Control”. In the guide, the command shown for creating the initial policy is:
New-CIPolicy -Level PcaCertificate -FilePath $InitialCIPolicy –UserPEs 3> CIPolicyLog.txt
Edit, April 11: The command in the guide now uses "-Level FilePublisher", see the note at the bottom of the post for more information.
Edit 2, April 25: And the guide is using "-Level PcaCertificate" again. It seems they restructured the guide and in the process the command was changed back to the original. The updated guide can be found here.
The New-CIPolicy Powershell cmdlet will scan the system for binaries and use that data to create a Device Guard policy. The “-level PcaCertificate” parameter ensures that if a signed executable or DLL is present, the highest available certificate in the signatures certificate chain will be added as an allow rule to the policy.
The resulting policy will contain a lot of allow rules based on Microsoft certificates. It is by abusing executables or scripts signed by these certificates that most bypasses work. Bypasses using signed Microsoft executables are most often serviced by Microsoft by adding deny rules to the bypass policy included in the deployment guide. Signed Microsoft executables will be the focus of a few of my later posts.
However, Windows machines are rarely limited to using only software provided by Microsoft. And if any installed software is signed, they will also leave certificates in the resulting policy. The following image shows part of a policy created from a basic installation on a virtual machine, without any tools installed outside of the Windows update process:
So at least one non-Microsoft signer. And after installing Virtualbox Tools:
Now two more signers can be found in the policy. Such signers will exist in almost any policy created by using “-level PcaCertificate”. By testing basic installations of some laptops from different vendors, I found the following examples of certificates left by user-mode components of driver packages from different vendors.
And by installing some common software and creating a policy, the following examples were found:
By having such certificates in the policy, finding signed binaries to bypass UMCI becomes a whole lot easier. And since some of these certificates are very common, finding a bypass method for those will allow an attacker to bypass UMCI on almost any deployment of Device Guard where the policy was created with the “PcaCertificate” level.
An obvious source of such bypass methods are execution environments like Python. The following list shows some available Python distributions where the binaries have been signed with potentially useful certificates:
All of these Python environments can be deployed by unzipping a directory containing just the needed files, without further modifications to the host. Just grab the necessary files out of an installation and zip them.
By deploying the zipped folder to a host that allows executables signed with this signature, an attacker gains full access to everything Python can do. If an attacker does not want to rewrite his or her tools to Python, a script leveraging ctypes could be used to bootstrap a process of loading an arbitrary DLL without calling LoadLibrary, thereby bypassing the User Mode Code Integrity check.
The following code shows how a blob of shellcode can be executed in the Python process:
from ctypes import * shellcode = open(“payload.bin”,”rb”).read() proc = windll.kernel32.OpenProcess(0x1F0FFF, False, windll.kernel32.GetCurrentProcessId()) mem = windll.kernel32.VirtualAllocEx(proc, 0, len(shellcode), 0x1000, 0x40) windll.kernel32.WriteProcessMemory(proc, mem, shellcode, len(shellcode), 0) windll.kernel32.CreateRemoteThread(proc, None, 0, mem, 0, 0, 0)
By running a reflective loader payload we can load arbitrary unsigned DLL’s. Creating such a payload is easy with sRDI by Nick Landers. I used the following command to generate my payload:
Python.exe ConvertToShellcode.py unsignedcode.dll
This will create a file named unsignedcode.bin, which can be deployed and run as the payload in the above Python script. If the code you are deploying needs to stay in memory, like in the case of a backdoor, you can avoid having an unsightly Python process dangling in Task Manager if you load the DLL in a more inconspicuous process. Just change the process id in the above code.
The Python distributions listed above should cover a very large base of Device Guard deployments. For near total coverage, I would like an option for policies containing the very common “Symantec Class 3 SHA256 Code Signing CA”. I wasn’t able to find a Python interpreter signed with this in its certification path. The Oracle Java Runtime looks like another possible execution environment, since it is signed with this certificate. But, it seems the only option to call native functions in Java relies on dynamically compiled and loaded DLL’s, something that would be blocked by Device Guard, as these DLL’s won’t be signed.
Another option could be a signed executable which is vulnerable in a way that allows shellcode to be executed. In my next post I’ll show how this can be accomplished.
Read part 2 here.
Following the steps in Microsoft's Device Guard deployment guide, specifically using the level of “PcaCertificate” to generate a policy, will almost certainly allow an attacker to bypass the policy and deploy arbitrary code in user space.
Note, April 11: This post was written to address an issue with Microsoft's Device Guard Deployment Guide. I reported these observations to Microsoft on the 16th of February, but could not get a commitment to a change of the guide.
Microsoft has since chosen to address the issue, and the command in the guide was recently changed to use the more specific level of "FilePublisher".
The security ramifications of using the original command from the guide still stands though, and policies deployed using the old command are still likely to be vulnerable to the described bypass method.
Note 2, April 25: Microsoft updated the guide again, and unfortunately it's back to using "-Level PcaCertificate".