Table of Contents
Detecting covert channels in X.509 Digital Certificates using the Trisul LUA API
I saw a couple of blogs about a new way to create a C2 (Command and Control) channel using X.509 Certificates. This technique is described in Abusing X.509 Certificates for Covert Data Exchange 1) and the original link on the Fidelis Blog Whats missing is in front of us 2) and also on the Network Miner blog Examining a X.509 Covert Channel 3) I'd also like to mention the author Jason Reaves
In this technique the covert channel is built by stuffing chunks of data into X.509 Certificate Extensions, in this case the “Subject Key Identifier” aka SKI extension. This is usually a hash of 20 bytes. However this is not used in certificate validation and it appears current commercial network defenses are not checking if this contains a valid value. The C2 POC uses a large number of certificates with SKI values of 10,000 bytes !
Trisul vs Bro approaches to the same problem
Trisul extracts metadata from network traffic and makes them available to LUA Scripts. There are two streams your scripts can plug into.
- the Resource stream: these are shorter summaries of the meta data. For example the DNS Resources would be one line summary of question and answers. SSL Resources contain the DER format certificate chain.
- the FTS stream: a complete text dump in some canonical format. For example : The DNS FTS stream would contain documents with a full dump of all DNS fields - much like the DIG format. Similarly for SSL Certificates, the FTS stream passes text documents that mirror the `openssl x509` command.
You can see the different approach taken by Trisul NSM compared to Bro IDS. Instead of fine grained events preferred by Bro IDS, Trisul provides a text document. If you wanted to parse the document yourself, you can do that as well using LuaJIT FFI. Here is an example of FFI'ing into the OpenSSL BIGNUM library from a script
Analysing the sample PCAP in Trisul
The researchers have provided a sample PCAP file containing a POC of the channel 4). If you import the PCAP file into Trisul using
trisulctl_probe importpcap mimikatz_sent.pcap and navigate to SSL Certs FTS and then search for Key“ you can see the certificates in full text format. This is shown below.
Next you have to write a small LUA script that plugs into the FTS SSL Certs Stream. Your script will then get a chance to peek at each certificate out of the fast packet path. By moving this out of the Fast Packet Path 5) Trisul gives your scripts a large time budget a few seconds to process without incurring packet loss. The Trisul LUA API provides the FTS Monitor script for exactly this purpose.
I just put together a quick FTS Monitor LUA script on GitHub that demonstrates how you can pick apart the cert using a simple regex. The snippet is shown below
-- WHEN CALLED : a new FTS Document (X509 Cert) is seen onnewfts = function(engine, fts ) local _,_,ski = fts:text():find("X509v3 Subject Key Identifier:%s*(%S+)") if ski and ski:len() > 32 then T.count = T.count + 1 local hexski = ski:gsub("[:%s]","") local outf = io.open("/tmp/c2ski-"..engine:instanceid().."-"..T.count,"w") outf:write(hexski:hex2bin()) outf:close() end end,
What the above code snippet does is
- Use a Regex to capture the bytestring in X509v3 Subject Key
- If the SKI extension is greater than 32 characters then we suspect something fishy. You may even generate an alert at this point using the
- Open a tmp file the convert the hex to binary and dump the contents there.
If you place this script in the LUA folder
/usr/local/etc/trisul-probe/plugins/lua and re-run the PCAP file, then you would get a number of files in the tmp folder containing chunks of the Mimikatz binary. When you run the file command you can see the chunk that contain the PE Header show up. You can also do this as part of the script itself.
Reassembling the Mimikatz payload
This is a bit of a fun task. The C2 technique uses about 70+ certificates to transfer a payload of 785KB. The big issue for us is that the certificates show up in different TCP flows. It is a lot easier to do the reassembly in Network Miner or Wireshark but in live traffic analytics like Trisul the flows can go to different CPU/threads due to load balancing and there are no hints in the packets itself to order the payloads. The best option is to dump the chunks and then manually
cat them later using a timestamp as a loose ordering.
More about the Trisul Lua API
The Trisul LUA API allows you to build your own real time analytics tools on top of the Trisul platform. Note that Trisul is Free to use forever, except that if you are using the Web Interface and Database backend, then only the most recent 3 days can be reported on.
The trisul-scripts GitHub repo contains dozens of example scripts of all kinds. The Documentation is Open and Free to use for all. Give it a go.