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:

 

 

 

New home for Cobalt Strike malleable c2 profiles and scripts

The Cobalt Strike references (malleable c2 profiles, scripts, Elevate Kit, etc.) have been consolidated under a new GitHub account. https://github.com/cobalt-strike

We understand that many blog posts (and even our documentation) have references to the original links. The original links will be available for the time being but may not be in the future.

Update your references to use the new repositories. All future updates will be made under the new account.

Create listeners with an aggressor script – listener_create_ext

This short post is a follow up to the post “Manage Cobalt Strike with Services” where I described a method to automate Cobalt Strike teamservers by creating services.

In this post, I will take a closer look at the aggressor function that is used to create listeners listener_create_ext to expanded on the documentation and provide an example.

The documentation shows three arguments. Let’s focus on $3, the key/value pairs. The key/values control the settings used to setup a listener.

From the Documentation

listener_create_ext

Create a new listener.

Arguments

$1 - the listener name
$2 - the payload (e.g., windows/beacon_http/reverse_http)
$3 - a map with key/value pairs that specify options for the listener

Let’s break down the options with an aggressor script that creates an HTTP listener. I formatted the script to be easier to read and added comments to provide a bit of guidance.

listener_create_ext(
    "HTTP",                             # Listener name, use something unique across all teamservers (i.e., server1-http)
    "windows/beacon_http/reverse_http", # Listener type, remember, payloads are driven by listeners
    %(host => "stage.host",             # Staging host, Only one staging host can be set
        profile => "default",           # The profile variant name, variants are set in the malleable c2 profile
        port => 80,                     # Port for c2 communications
        beacons => "b1.host,b2.host",   # Comma separated list of beacon hosts
        althost => "alt.host",          # host header value
        bindto => 8080,                 # The port HTTP Beacon payload web server will bind to.
        strategy => "failover-5x",      # Host rotation strategy aka fail strategy
        proxy => "http://user:pass@proxy.host:8080" # Proxy host settings 
    ) 
);

This aggressor script will create a listener that looks like this in the GUI.

References:

  • https://www.cobaltstrike.com/aggressor-script/functions.html#listener_create_ext
  • https://www.cobaltstrike.com/help-http-beacon
  • https://blog.cobaltstrike.com/2021/06/23/manage-cobalt-strike-with-services/

 

Manage Cobalt Strike with Services

This post is part of a “Quality of Life” series, where tips and tricks will be shared to make using Cobalt Stike easier. 

Cobalt Strike is a post-exploitation framework and requires customization to meet your specific needs. This flexibility is one of the most powerful features of Cobalt Strike. While this is great, some may find it challenging to quickly set up a teamserver. Even if you are only conducting quick tests, consider building an automated deployment process using something as simple as a bash script or something more complex like a DevOps process based on tools like Ansible or Terraform. 

This post covers the aspect of considering adding to a deployment process to enhance teamserver automation. It does not cover complete infrastructure design. Several people in the security community have posted excellent design guidance.

Teamserver and Listener Automation

This post explores the automation of:

  • auto-starting teamserver using a random custom malleable c2 profile
  • creating listeners using a headless aggressor script

This process needs three files:

  • teamserver.service (controls the teamserver as a Linux service)
  • listener. service (controls the auto-creation of listeners as a Linux service)
  • listener_service.cna (aggressor script that specifies the parameters for the listeners)

These templates can be found here: https://github.com/vestjoe/cobaltstrike_services

Steps

Summary

I’ll summarize the steps here, but you should integrate these steps into an infrastructure deployment plan in actual practice. I demo the results of a practical example at the end of the post. 

Note: These scripts have been tested on Ubuntu server and may need to be adjusted based on your actual use case.

  • Update the service files to match your environment.
    • teamserver.service
    • listener.service
    • listener_service.cna
  • Copy the service files to your teamserver host
    • /etc/systemd/system/teamserver.service
    • /etc/systemd/system/listener.service
    • /opt/cobaltstrike/listener_service.cna
  • Register the new services
    • systemclt daemon-reload
  • Start the services
    • systemctl start teamserver.service
    • systemctl start listener.service
  • Test that everything works

Step Details

Note: The following steps show the details, but should broken down into deployment steps (ansible, terraform, etc.) that fit your own process.

1) Update the Teamserver Service Configuration File

This file is used to configure teamserver as a Linux service.

Use the template below as a starting point. Update the settings to match your environment and save it to a temporary location. (I’m using /tmp for this demo)

Specifically, you should update: 

  • WorkingDirectory: Set to the cobaltstrike directory
  • ExecStart: Set with your teamserver parameters
## TEMPLATE START

# teamserver.service

[Unit]
Description=Cobalt Strike Teamserver Service
After=network.target
Wants=network.target

[Service]
Type=Simple
WorkingDirectory=/opt/cobaltstrike
ExecStart=/opt/cobaltstrike/teamserver <TEAMSERVER IP> <PASSWORD> <PATH TO C2 PROFILE>

# Example
# ExecStart=/opt/cobaltstrike/teamserver `hostname -I` thisismypassword /opt/cobaltstrike/c2.profile

[Install]
WantedBy=multi-user.target

## TEMPLATE END

The malleable c2 profile can be any you create. I like to use randomly generated profiles for quick tests. https://github.com/threatexpress/random_c2_profile

2) Update the Listener Service Configuration File

The listener service uses agscript to run a headless aggressor script as a service. If you are not familiar with agscript, take a look at “Headless Cobalt Strike” in the manual https://www.cobaltstrike.com/aggressor-script/index.html

Use the template below as a starting point. Update the settings to match your environment and save them to a temporary location. (I’m using /tmp for this demo)

Specifically, you should update:

  • WorkingDirectory: Set to the cobaltstrike directory
  • ExecStart: Set with the values you need to run the agscript
## TEMPLATE START
# listener.service
[Unit]
Description=Cobalt Strike aggressor service
After=teamserver.service network.target
Wants=teamserver.service
StartLimitIntervalSec=33

[Service]
Restart=on-failure
RestartSec=10
WorkingDirectory=/opt/cobaltstrike
ExecStartPre=/bin/sleep 60
ExecStart=/bin/bash /opt/cobaltstrike/agscript <TEAMSERVER IP> <TEAMSERVER PORT> <USER to LOGON TO COBALTSTRIKE> <TEAMSERVER PASSWORD> <PATH TO listener_service.cna>
# Example
# ExecStart=/bin/bash /opt/cobaltstrike/agscript 127.0.0.1 50050 listener_service thisismypassword /opt/cobaltstrike/listener_service.cna

[Install]
WantedBy=multi-user.target
## TEMPLATE END

Headless Aggressor Script

This example aggressor script is used to create and start an HTTP, HTTPS, and SMB listener with all the needed parameters. It is a regular aggressor script and can be loaded manually through the Cobalt Strike client or run headless using agscript. 

Use the template below as a starting point. Update the settings to match your environment and save them to a temporary location. (I’m using /tmp for this demo)

The script uses the listener_create_ext function. Take a look at the support documentation for additional options.

At a minimum, change the following to match your environment.

  • HTTP Listener
    • listener name
    • host
    • althost
  • HTTPS Listener
    • listener name
    • host
    • althost
  • SMB Listener
    • listener name
    • port
## TEMPLATE START
println("
###################################################################
 CobaltStrike Aggressor Script          
 Author: Joe Vest
 Description: Headless script to create listeners
###################################################################");

println('listener_service.cna: Loading listener_service.cna...');

on ready{
    println('listener_service.cna: Creating HTTP Listener...');
    listener_create_ext("HTTP", "windows/beacon_http/reverse_http", %(host => "iheartredteams.com", port => 80, beacons => "iheartredteams.com", althost => "iheartredteams.com", bindto => 80));

    println('listener_service.cna: Creating HTTPS Listener...');
    listener_create_ext("HTTPS", "windows/beacon_https/reverse_https", %(host => "iheartredteams.com", port => 443, beacons => "iheartredteams.com", althost => "iheartredteams.com", bindto => 443));
    
    println('listener_service.cna: Creating SMB Listener...');
    listener_create_ext("SMB", "windows/beacon_bind_pipe", %(port => "mojo.5887.8051.34782273429370473##"));

    sleep(10000);

}
## TEMPLATE END

Copy the Files to the Appropriate Location

sudo cp /tmp/teamserver.service /etc/systemd/system/teamserver.service
sudo cp /tmp/listener.service /etc/systemd/system/listener.service
sudo cp /tmp/listener_service.cna /opt/cobaltstrike/listener_service.cna

Register and Start the New Services

sudo systemclt daemon-reload
sudo systemctl start teamserver.service
sudo systemctl start listener.service

Test to Make Sure Everything is Working as Expected

Teamserver should be running, and the script should have created the listeners. If so, test a few payloads and commands to make sure everything works as expected.

Consider Adding this Process to an Infrastructure Deployment Process

These manual steps and templates provide a means to automate some of the Cobalt Strike but can be enhanced further through a more formal process.

For example, I do this in a couple of ways:

  • I use simple bash scripts and the AWS CLI to deploy and configure a test environment.
  • I create ansible roles to automate the deployment and configuration of a teamserver as part of a larger deployment script.

Demonstrating a Practical Example

In this demo, I show how I fully automate the deployment and configuration of the range I used for quick realistic testing to AWS LightSail. The deployment is fully automated and includes settings to protect the teamserver from direct public access. 

 

Range Highlights

The script results in a small test range that follows this traffic pattern

  1. Beacon reaches out to a valid Cloud front redirector. These cloud redirectors are really just HTTP proxies. (https://www.blackhillsinfosec.com/using-cloudfront-to-relay-cobalt-strike-traffic/)
  2. Traffic is redirected to the Apache redirector. (again, just another HTTP proxy that applies our logic)
  3. Apache forwards the HTTP to the teamserver.

Services Running

The agscript user logon event (listener_service) can be seen in the Event Log.

The listeners are automatically created based on the service settings.

References


 

Interested in Trying Cobalt Strike?

REQUEST A QUOTE

There’s a New Deputy in Town

It’s been less than a month since I joined the Cobalt Strike team. My first impressions of this team have been overwhelmingly positive. As Raphael transitioned out, He left us with a message “Cobalt Strike is in good hands.” I couldn’t agree more.

What can you expect from me? I’m here to provide input and guidance to Cobalt Strike’s overall direction, but more importantly, I’m here to interact with and learn from the community to help drive the best improvements. I encourage you to reach out with questions or discussions on offensive or defensive security topics. Consider following us on Twitter @joevest, @CoreAdvisories, and @HelpSystemMN if you’d like to keep up with the latest news on Cobalt Strike, Core Security, or HelpSystems. You can also find me hanging out in the BloodhoundGang #aggressor channel on Slack.

I titled this post “There’s a new deputy in town.” You may hear my voice more than others on the team, but I am not the sheriff. I’m just the newest member of a fantastic team. We all play different but crucial roles. I’m excited to start this new journey with this great team.

SSL certificate verification failure

UPDATE: This has now been fixed. I’ve amended this post to reflect that.

If you ran the Cobalt Strike update program today, you may have seen an error message about the failed SSL certificate verification for www.cobaltstrike.com:

The update program pins the certificate for this server. When the certificate does not match what the update expects, the update program gives a warning. This is by design and is so that you can be confident that you’re getting the update from HelpSystems.

The change that caused the error has been reverted and the issue has been addressed. No further action is required on your part, and updates should now be working again.

We’d like to offer our sincere apologies for any inconvenience that this issue caused, and thank you for your patience while the issue was resolved.

Simple DNS Redirectors for Cobalt Strike

This post, from Ernesto Alvarez Capandeguy of Core Security’s CoreLabs Research Team, describes techniques used for creating UDP redirectors for protecting Cobalt Strike team servers. This is one of the recommended mechanisms for hiding Cobalt Strike team servers and involves adding different points which a Beacon can contact for instructions when using the HTTP channel.

Unlike HTTP Beacons, DNS Beacons do not contact the team server directly, but use the DNS infrastructure for carrying messages. In theory, the team server should be referenced in the DNS records so that all queries for the Command and Control (C2) domain are delivered properly. This would mean exposing the team server to the Internet, which is not desirable.

Just as HTTP redirectors can be used to hide the team server from outside scrutiny, a DNS redirector can be used for the same thing. In the case of DNS, redirectors are just one part of the solution, as alternative domains are also necessary in case the original domain is taken down. We will not cover these aspects here, as we’ll be concentrating on the redirection part.

Redirecting TCP traffic is straightforward. There is a very delimited set of data that clearly defines what constitutes a network connection (or flow). The state is explicit and can be easily determined from the packet stream. There are several generic proxies (e.g. SOCAT) that can simply proxy TCP connections on the user space. Options for secure proxying of TCP connections are also available (stunnel and SSH port forwarding are two well-known examples).

The situation is radically different for UDP. This is due to a few factors:

  • UDP is packet oriented, while TCP is byte/connection oriented.
  • UDP is stateless and keeping track of UDP “connections” requires second guessing the “connection” state.
  • UDP is handled very differently from TCP in userland.

In a TCP proxy operation, a connection is clearly defined. This connection can transmit EOF messages, so the proxy would always be aware of the state of the connection and would unambiguously know when it should release the connection resources.

UDP is more challenging, since without a way of directly sensing the DNS transaction state, SOCAT cannot know when to release the connection resources.

Simple Redirector Construction

The obvious solution for building a DNS redirector would be to use a DNS server. There are several choices for these, with differing features. We won’t touch on these options in this article, but will instead focus on simple redirectors that can be installed on minimal Linux systems and have a very small footprint.

Our redirectors will be based on the concept of diverting a UDP flow from the redirector’s local port to the team server in a way that the team server has to send the response back to the redirector, which will relay it to the Beacon.

There are two ways of achieving this goal: piping ports together and NAT.

Port Piping

We are all familiar with the concept of piping from a network port. Anyone can do it using netcat or an equivalent tool. Anyone with experience with any of these tools will also know that redirecting UDP traffic is sometimes problematic. A DNS redirector also has these problems, but they can be kept bounded.

For these tests, we are going to use SOCAT, a UNIX tool used to connect multiple types of inputs and outputs together. This tool can do the same thing as netcat but is more versatile.

Naive SOCAT Redirector

Before we jump into the solution, we should try to see the problems. Let’s attempt a naive approach to a DNS channel redirector. We can execute a straight SOCAT, and launch a Beacon pointed to our redirector, which will be executing the following:

# socat udp4-listen:53 udp4:teamserver.example.net:53

The initial installation works, and we see the ghost Beacon in the team server. However, any further communication fails. Monitoring the DNS traffic, we see the following:

# tcpdump -l -n -s 5655 -i eth0  udp port 53
 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 5655 bytes
 
05:40:26.453966 IP 173.194.91.156.62931 > redirector.example.net.53: 55757% A? 7242b4ba.cobalt-domain.example.net. (51)
05:40:26.454317 IP redirector.example.net.56494 > teamserver.example.net.53: 55757% A? 7242b4ba.cobalt-domain.example.net. (51)
05:40:26.454593 IP teamserver.example.net.53 > redirector.example.net.56494: 55757- 1/0/0 A 0.0.0.0 (100)
05:40:26.454687 IP redirector.example.net.53 > 173.194.91.156.62931: 55757- 1/0/0 A 0.0.0.0 (100)
05:41:26.689753 IP 172.253.219.11.49854 > redirector.example.net.53: 56196% A? 7242b4ba.cobalt-domain.example.net. (51)
05:42:27.217514 IP 172.253.219.11.61868 > redirector.example.net.53: 28170% A? 7242b4ba.cobalt-domain.example.net. (51)
05:43:27.532055 IP 173.194.91.156.49467 > redirector.example.net.53: 59203% A? 7242b4ba.cobalt-domain.example.net. (51)
05:44:27.653780 IP 173.194.91.77.59444 > redirector.example.net.53: 14169% A? 7242b4ba.cobalt-domain.example.net. (51)
05:45:27.770012 IP 173.194.91.141.62374 > redirector.example.net.53: 52473% A? 7242b4ba.cobalt-domain.example.net. (51)
05:46:28.051530 IP 172.253.219.7.39179 > redirector.example.net.53: 26440% A? 7242b4ba.cobalt-domain.example.net. (51)
05:47:28.190316 IP 173.194.91.74.45768 > redirector.example.net.53: 41092% A? 7242b4ba.cobalt-domain.example.net. (51)

Well, the Beacon checked in fine, but after the first DNS request the pipeline stalls. This is because the UDP protocol is stateless. SOCAT never got the idea that the first transaction was over and is still waiting for data from the same source port, ignoring all the others.

This can easily be solved by telling SOCAT to fork for every packet it sees. Below we show our second attempt at doing a SOCAT redirector:

# socat udp4-listen:53,fork udp4:teamserver.example.net:53
 
# tcpdump -l -n -s 5655 -i eth0  udp port 53
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 5655 bytes
05:53:45.783953 IP 173.194.91.129.48083 > redirector.example.net.53: 3962% A? 7242b4ba.cobalt-domain.hlmnet.net. (51)
05:53:45.784730 IP redirector.example.net.34472 > teamserver.example.net.53: 3962% A? 7242b4ba.cobalt-domain.hlmnet.net. (51)
05:53:45.784860 IP teamserver.example.net.53 > redirector.example.net.34472: 3962- 1/0/0 A 0.0.0.0 (100)
05:53:45.784954 IP redirector.example.net.53 > 173.194.91.129.48083: 3962- 1/0/0 A 0.0.0.0 (100)
05:54:00.847401 IP 173.194.91.83.48991 > redirector.example.net.53: 57475% A? 7242b4ba.cobalt-domain.hlmnet.net. (51)
05:54:00.848289 IP redirector.example.net.46902 > teamserver.example.net.53: 57475% A? 7242b4ba.cobalt-domain.hlmnet.net. (51)
05:54:00.848436 IP teamserver.example.net.53 > redirector.example.net.46902: 57475- 1/0/0 A 0.0.0.0 (100)
05:54:00.848541 IP redirector.example.net.53 > 173.194.91.83.48991: 57475- 1/0/0 A 0.0.0.0 (100)
05:54:15.917608 IP 173.194.91.156.35560 > redirector.example.net.53: 29854% A? 7242b4ba.cobalt-domain.hlmnet.net. (51)
05:54:15.918490 IP redirector.example.net.55342 > teamserver.example.net.53: 29854% A? 7242b4ba.cobalt-domain.hlmnet.net. (51)
05:54:15.918615 IP teamserver.example.net.53 > redirector.example.net.55342: 29854- 1/0/0 A 0.0.0.0 (100)
05:54:15.918719 IP redirector.example.net.53 > 173.194.91.156.35560: 29854- 1/0/0 A 0.0.0.0 (100)

Our Beacon is now alive and communicating well! SOCAT now waits for packets coming from new sources and forwards them to our team server. While everything appears to be normal, this is unfortunately not the case, as this redirector will not work for long. Let’s inspect the process table:

# ps 
  PID TTY          TIME CMD
5365 pts/0    00:00:00 sudo
5366 pts/0    00:00:00 bash
5864 pts/0    00:00:00 socat
5865 pts/0    00:00:00 socat
5866 pts/0    00:00:00 socat
5867 pts/0    00:00:00 socat
5868 pts/0    00:00:00 socat
5869 pts/0    00:00:00 socat
5870 pts/0    00:00:00 socat
5871 pts/0    00:00:00 socat
5883 pts/0    00:00:00 socat
5886 pts/0    00:00:00 socat
5888 pts/0    00:00:00 socat
5889 pts/0    00:00:00 socat
5890 pts/0    00:00:00 socat
5891 pts/0    00:00:00 socat
5903 pts/0    00:00:00 socat
5904 pts/0    00:00:00 socat
5908 pts/0    00:00:00 socat
5910 pts/0    00:00:00 socat
5911 pts/0    00:00:00 socat
5912 pts/0    00:00:00 socat
5913 pts/0    00:00:00 socat
5914 pts/0    00:00:00 socat
5923 pts/0    00:00:00 ps

This does not look good. SOCAT processes are piling up. Let’s stress the redirector a bit by requesting a few screenshots and then check the process table:

# ps | grep socat | wc -l
3489

If we weren’t root, we would have run out of process slots long ago. Even the superuser will eventually have problems with this redirector:

socat udp4-listen:53,fork udp4:teamserver.example.net:53
2021/03/02 06:09:57 socat[5864] E fork(): Resource temporarily unavailable

As expected, we ran out of resources. Worse, we still have several thousand SOCAT processes waiting. The problem was caused because SOCAT does not notice that a transaction has run out, and still keeps its resources allocated.

Working UDP SOCAT Redirector

Now that we understand the problems involving UDP proxying, we can build a functional solution. The trick is telling SOCAT to drop the connections as soon as the transaction is complete. Telling SOCAT to apply a 5 second inactivity timeout should do the trick:

 # socat -T 5 udp4-listen:53,fork udp4:teamserver.example.net:53

In the example above, we told SOCAT that if no data is seen for five seconds, it should close the socket and assume that no further communication is needed.

While five seconds is a reasonable default timeout, we can attempt to optimize this value. To fine tune the timeout, we should understand the problem we’re facing. A DNS request is sent to our reflector, which is relayed to the team server. Once the team server answers, the transaction is over.

This limits our timeout to something we can control: the round-trip time between the redirector and the team server, including the time needed to process the request. A reasonable value would be twice the RTT between the hosts, to have some safety margin. Since our test hosts are in the same LAN, a timeout of one second should be more than enough for our example.

Below we show the process usage for five and one second timeouts:

The graph shows that the number of SOCAT processes rises as soon as there is activity, but the timeout causes the number of active processes to reach a plateau and stay at a certain value, depending on the activity and the timeout.

Working SOCAT UDP/TCP Redirector

We now have a working redirector. We can also use SOCAT for UDP to TCP translation. For every UDP packet received, we can fork and open a TCP connection, sending the DNS data via TCP. It is very important not to recycle connections, because UDP is packet oriented while TCP is not. We should never put more than one packet within a TCP connection, because two packets might be joined or split. In theory, SOCAT might decide to split a DNS request in two UDP packets, but this does not happen in practice. You should know that there is always that risk when doing UDP to TCP translations.

We tell SOCAT to take traffic from port 53, and for each packet, to open a connection to port 9191/tcp on the team server. The timeout is set to one second, which might be a bit too low, considering that TCP is involved:

# socat -T 1 udp4-listen:53,fork tcp4:teamserver.example.net:9191

Since we’re encapsulating our data within TCP, we need to run the following in the team server:

# socat -T 10 tcp4-listen:9191,fork udp4:127.0.0.1:53

Let’s now try generating some traffic and see what happens.

The dip in the middle represents a lapse in activity. The quick timeout allows for fast recovery. Overall, it’s not bad, but we also need to see how many open connections we have.

The numbers are somewhat high because TCP requires a wait period when a connection is closed from the client side. This is needed in case some control messages are lost and should not be removed for the protocol to operate properly. This is not a problem, though, because the number of resources allocated reach an equilibrium. A few RTT after the activity goes down, the resource usage drops as well.

Once we have the translation capability, we can take advantage of it. With DNS over TCP connections, we can take advantage of other proxying utilities, like stunnel or SSH’s port forwarding, and attempt to hide the team server from public scrutiny. The team server can be kept in an isolated network, without being exposed to the Internet.

NAT Based Redirectors

Another possible solution involves NAT. The concept behind a NAT redirector is to apply two NAT operations to incoming packets. The packet must be redirected to the team server, but at the same time, the packet must also be translated so that it appears to come from the redirector.

Failing to apply the second operation will cause the team server to answer the DNS query itself. The response will be ignored, as it will come from a different DNS server.

For our NAT redirector, we use Linux’s IPTABLES.

IPTABLES Based Redirector

IPTABLES is also well suited for use as a redirector. The Linux kernel’s NAT system automatically keeps track of connection state, even for UDP traffic. The detection is based on timers and inactivity, but the system is well developed and very stable.

The advantage of IPTABLES redirectors is that they’re lightning fast, incredibly efficient, and robust. Unlike SOCAT redirectors, iptables cannot convert from one protocol to another as IPTABLES works by packet mangling.

To create a working redirector, two things need to happen at the same time. Once a DNS query reaches the redirector, it must be redirected to the team server. This requires a DNAT operation.

However, if DNAT is used alone the packet will be diverted without changing the source address. As we already explained, this is not a good result, so we’ll also need to execute a SNAT operation.

The decision for doing the double NAT needs to be taken before any of the operations take place, as the DNAT change in the PREROUTING rule will erase important information present in the packet (namely whether this packet is addressed to the redirector or not).

To execute both operations simultaneously, we call the MARK target in the PREROUTING chain, and match the packet using every parameter of interest. Once the packet is marked, we can apply all operations both in the PREROUTING and POSTROUTING chains, completely changing the packet.

One final detail is that IP forwarding must be enabled in the redirector, since all these operations count as a forward, even if the packet is sent through the same interface it came in.

In the end, there are four commands that need to be called:

#enable IP forwarding
echo "1" > /proc/sys/net/ipv4/ip_forward

#Mark incoming DNS packets with the tag 0x400
iptables -t nat -A PREROUTING -m state --state NEW --protocol udp --destination my.ip.address 
--destination-port 53 -j MARK --set-mark 0x400

#For every marked packet, apply a DNAT and a SNAT (in this case, a MASQUERADE)
iptables -t nat -A PREROUTING -m mark --mark 0x400 --protocol udp 
-j DNAT --to-destination teamserver.example.net:53
iptables -t nat -A POSTROUTING -m mark --mark 0x400 -j MASQUERADE

Evaluating the capabilities listed in the proc filesystem, we see that we have 65,536 entries in the translation table (proc/sys/net/netfilter/nf_conntrack_max), and 16,384 buckets (/proc/sys/net/netfilter/nf_conntrack_buckets). This indicates that even at peak capacity, the lookups should be quick. These are default values and can be easily changed by writing a new number to the file, if necessary.

The system keeps track of the traffic passing through the redirector, so no action is needed for returning packets since they are translated back automatically.

To evaluate the performance of the redirector, we can measure the number of active NAT entries and how this number changes as the system is loaded. To measure this, we can read /proc/sys/net/netfilter/nf_conntrack_count.

Our experiment starts with a Beacon signaling at 15 second intervals. The Beacon is then made to signal continuously, followed by a high activity period. Once this activity period is over, the Beacon is reconfigured to its initial value of 15 seconds between polls.

In the test above we can see that the number of occupied slots depends on the network activity. With just one Beacon polling at 15 second intervals, the amount of conntrack slots is less than 10. If we switch to no delay, the value quickly grows to about 500, depending on availability throughput. When heavy activity is requested, the connection states steadily rise to 2500 and plateaus at 2700. Once activity ceases, connection tracks decrease until around 90 seconds, at which point they are all expired and the value stabilizes below 10.

IPTABLES redirectors perform quite well with very modest resources, even with default settings. This is not surprising, given the nature of the Linux kernel. Redirectors like this one can easily be deployed on the smallest computers or cloud instances. IPTABLES redirectors, once set up, are pretty much foolproof.

Summary

In this article, we saw three different implementations of DNS Beacon redirectors. Though these implementations have different advantages and disadvantages,  they are ultimately all very usable.

The IPTABLES based redirector is the quickest with the smallest footprint, being included by default in the kernel, and needing just four commands.

The SOCAT based redirectors are similar, the main difference being whether traffic is converted to TCP or not. UDP redirectors are simplest, but TCP redirectors have an advantage in the sense that TCP connections are easier to encapsulate, which is an advantage in special cases, like when the traffic must be tunneled via SSH.

Resource usage Speed Versatility Ease of Use Stability
SOCAT TCP 0 ++ + 0
SOCAT UDP + + + ++ +
IPTABLES ++ ++ 0 ++ ++

 

Raphael’s Transition

Friday was my last day at HelpSystems. I spent the day on the #Aggressor channel on Slack, put some final touches on a 12 month roadmap document, and worked with my colleagues to remove myself from a few systems I had originally designed. I had planned to get a blog post out yesterday, but the day ran right up to my dinner plans!

Cobalt Strike is in great shape. The product is no longer the efforts of one person. There’s a full research and development team behind it. Greg Darwin is the leader. You’ll see his announcements here and on the Cobalt Strike Technical Notes mailing list. Twitter announcements for Cobalt Strike will come from @CoreAdvisories as well.

You’ve seen the work of our R&D team. 4.3 was their release. I provided guidance, but they 100% carried it.

The team is filled with very senior software folks. All come from security backgrounds (one of our engineers was tech lead of HelpSystems’ server antivirus product). The forward mantra is to keep the product stable and to continue to give more flexibility into the product’s attack chain.

The above team was three folks one week ago. A fourth engineer joined this week. And, we’re recruiting our hacker-in-residence as well. The hacker-in-residence will pick up some aspects of my role: input on the overall product direction, providing subject matter expertise on offense topics, and interacting with and helping all of us learn from you.

You have a bigger ally now. HelpSystems’ business strategy in this space is simple. As red teaming succeeds as a practice, we’ll succeed as a business. Cobalt Strike is in good hands.

I want to thank you for the opportunity to work with you for the past decade. It was the greatest privilege of my career. For me, the biggest thrill in this work wasn’t related to the technology. It was watching your careers, seeing your successes, and feeling a small supporting role in it. Thanks for having me as part of it.

Cobalt Strike 4.3 – Command and CONTROL

Cobalt Strike 4.3 is now available. The bulk of the release involves updates to DNS processing but there are some other, smaller changes in there too.

DNS updates

We have added options to Malleable C2 to allow DNS traffic to be masked. A new dns-beacon block allows you to specify options to override the DNS subhost prefix used for different types of request. All existing options relating to DNS have also been moved inside this block. The affected options are: dns_idle, dns_max_txt, dns_sleep, dns_ttl, maxdns, dns_stager_prepend and dns_stager_subhost.

Something that you should be aware of is that the addition of the dns-beacon block means that in order for them to be processed, these existing options need to be defined inside the block. Values for these options outside of the dns-beacon block in existing profiles will be ignored.

dns-beacon {
    # Options moved into 'dns-beacon' group in 4.3:
    set dns_idle             "1.2.3.4";
    set dns_max_txt          "199";
    set dns_sleep            "1";
    set dns_ttl              "5";
    set maxdns               "200";
    set dns_stager_prepend   "doc-stg-prepend";
    set dns_stager_subhost   "doc-stg-sh.";
    
    # DNS subhost override options added in 4.3:
    set beacon               "doc.bc.";
    set get_A                "doc.1a.";
    set get_AAAA             "doc.4a.";
    set get_TXT              "doc.tx.";
    set put_metadata         "doc.md.";
    set put_output           "doc.po.";
    set ns_response          "zero";
}

Another change related to DNS is the addition of functionality to allow a DNS Beacon to egress using a specific DNS resolver, rather than the default DNS resolver for the target server. A new DNS Resolver field has been added to the DNS listener configuration dialog to facilitate this change.

Rounding out the DNS changes, a smaller change is the addition of a customization option related to how the server responds to NS record requests. We have noticed that some DNS resolvers do not allow the DNS Beacon to successfully egress to their team server due to unexpected NS record requests being injected into the communications. Prior to this release, the team server would drop the NS requests and if certain DNS resolvers fail to receive responses to those requests, DNS communications would fail. To get around this issue, we have added another option (ns_response) to the new dns-beacon block to allow the response to those requests to be customized.

Host rotation

We have made improvements to evasion in the DNS and HTTP/S Beacons by adding a host rotation strategy option. Prior to this release, a close examination of DNS and HTTP/S traffic would reveal a round robin pattern of host processing. A new host rotation strategy option in the listener configurations for the DNS and HTTP/S Beacons allows you to use different strategies for rotating through hosts. The options include the existing round robin rotation plus three new options – random, rotate on failure, and rotate after a set period of time.

Quality-of-life updates

Outside of the main DNS theme to the release, we have made a couple of a smaller, quality-of-life changes; the first of which is the addition of a PowerShell IEX option in Scripted Web Delivery. The new powershell IEX option outputs a shorter IEX command that can be pasted directly into a PowerShell console.

Another quality-of-life change is the option to prefix console messages with a timestamp. This option can be turned on or off via the console preferences dialog.

User agent handling

One final update to mention involves how requests from certain user agents are handled. The default behaviour of the team server prior to this release has been to block requests from user agents starting with “curl”, “lynx” or “wget” with a 404 response. We have received feedback that this causes problems for some users that want their server to be able to respond to requests from traffic that appears to be coming from certain user agents. To address this, we have added a block_useragents option to the http-config block within the Malleable C2 profile. This allows you to specify which user agents to respond to.

To see a full list of what’s new in Cobalt Strike 4.3, please check out the release notes. Licensed users can run the update program to get the latest version. To purchase Cobalt Strike or ask about evaluation options, please contact us for more information.

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