A prototype malware C2 channel using x509 certificates over mTLS
First off, why would I open source this?
MITRE ATT&CK only talks about stolen or self-signed certs, and NDRs (as far as I can tell) pay very little attention to the content of x509 certificates outside of who is the issuing CA. In general x509 certificates are trusted and allowed to pass through our firewalls with impunity. But in essence they are just files that can easily contain malicious payloads like any other. We trust and ignore them because they are a core component to an encryption process that we’ve come to take for granted. The primary goal of this project is to bring a heightened awareness to a class of security indicator that we have come to trust, and highlight methods that can be used to detect malicious uses of it.
I always wondered if threat actors have ever used x509 certificates as part of their C2 communication, not to encrypt the network traffic, but to actually embed the C2 communication in the x509 cert. After searching for something like this in the wild for 5 years I finally decided to just code it myself to see if it's possible...it is.
Every single encrypted message sent over HTTPS/TLS is enabled by the transfer of an x509 certificate. When establishing a TLS handshake (figure below), during the fourth step the server sends its x509 certificate to the client. The client verifies the certificate, compares the encryption algorithms the server supports and chooses which algorithm to use for all further communication.
As this diagram shows, this is only a one-way transfer of the x509 certificate from the server to the client. This does not lend itself well to C2 communication because there is no way for the client to respond back to the server. At best, it could only be used as a one-way data transfer mechanism (see prior art section below).
But there is another type of TLS session called mutual TLS Authentication (mTLS), where both the client and the server exchange x509 certificates as a way to authenticate each other.
As the figure above shows, during mutual authentication the server’s x509 certificate is sent to the client for authentication, and then the client’s x509 certificate is sent to the server for authentication. This exchange of artifacts represents an opportunity to create a 2-way communication channel for C2 servers.
Since the server and client certificates are exchanged by the underlying SSL library there isn't an opportunity for the client to pull the message out of the server's cert, run the command, and generate a response certificate all within a single mTLS connections. This means the C2 channel needs to be designed such that the request-reply exchange takes place over two different mutual TLS connections, kind of like a pseudo-half duplex transmission mode.
The request/response process follows the following steps:
After I got this working I was pretty proud of myself for being all creative and stuff.
Then I ran across this BSides talk in 2018 by Jason Reaves who wrote a malware binary dropper using x509 certs over TLS. A year later Jason published this paper detailing a full 2 way communication channel using mTLS.
mTLS requires that both the client and the server's certificates are signed by the same CA cert, so the first step is to generate your own CA private key / certificate pair
Create root CA private key:
openssl genrsa -des3 -out hmCA.key 2048
note: The passphrase will prevent anyone who gets your private key from generating a root certificate of their own.
Create root CA certificate
openssl req -x509 -new -nodes -key hmCA.key -sha256 -days 1825 -out hmCA.pem
Copy the generated key and cert files into the certs/ca_certs
folder. The project comes with a demo
key/cert pair, so you can skip this step if you want.
Start the client:
python client.py
Start the server:
python server.py
I never want to release something potentially malicious without also detailing how to detect it in your network logs.
You'd think detecting this type of TLS pattern would be easy, but it's not that simple. One of the main tells of this C2 channel is its half-duplex style of communication; it takes two mutual authentication flows to complete a full request/reply between the server and the client. This will then happen multiple times as the server is sending different commands to the client.
This means you should look for:
This seems like a slam dunk set of detection rules, but like I said before it's not that easy. Turns out there are a set of enterprise services that also have a similar mTLS traffic pattern, including
Several of these seem to be asset/device management services, so in theory they should be sending the same set of certificates each time they run through all their devices. You could look to see if there are sets of multiple mTLS session repeating every N hours, and then see if the cert hashes between two different sets of mTLS sessions match, or mostly match. Also, potentially look for the client certs to be different for each mTLS session, but the same server cert across all sessions.
SSL inspection is one way to potentially block this type of C2 communication channel as the SSL inspection server would not have the malicious CA cert needed to authenticate the client certificate.