Sliver, Havoc, and Metasploit
As detection of Cobalt Strike improved, red teams and threat actors diversified to alternative C2 frameworks: Sliver (an open-source Go-based framework), Havoc (a newer framework targeting the same operator market as Cobalt Strike), and Metasploit's Meterpreter (the original offensive framework). Each has distinctive network characteristics. Understanding all three alongside Cobalt Strike gives a detection engineer coverage of the majority of real-world C2 frameworks encountered in incident response.
A nation-state intrusion uses Sliver as their primary implant framework. You see encrypted mTLS (mutual TLS) traffic on port 31337 — Sliver's default mTLS transport. Unlike Cobalt Strike, Sliver requires the client to present a certificate during the TLS handshake (mutual authentication). In PCAP: both sides present certificates during the handshake, the client certificate is generated by Sliver's internal CA, and the JA3 matches Sliver's Go TLS fingerprint. The port 31337 is also a distinctive default.
Framework Network Fingerprints
| Framework | Default Protocol | Default Port | Key Identifier |
|---|---|---|---|
| Cobalt Strike (default) | HTTP/HTTPS | 80/443 | Java TLS JA3, IE7 UA, /submit.php |
| Sliver (mTLS) | Mutual TLS (raw TCP) | 31337 | mTLS (client cert), Go TLS JA3 |
| Sliver (HTTP) | HTTP/HTTPS | 80/443 | Go TLS JA3, /rpc.php URI |
| Sliver (DNS) | DNS tunneling | 53 | High-frequency DNS to one domain |
| Havoc | HTTPS | 443 | Custom Demon agent JA3, specific staging URI |
| Metasploit (Meterpreter) | HTTPS reverse shell | 443 | Specific JA3, large initial data transfer, no SNI |
| Metasploit (staged) | HTTP | 4444 | Non-standard port, stage download, small MSF headers |
| Brute Ratel | HTTPS | 443 | Distinctive HTTP profile, specific URI patterns |
Sliver Detection
#!/bin/bash
PCAP="$1"
echo "=== Sliver mTLS (port 31337 or non-standard TLS) ==="
# mTLS: TLS where client also presents a certificate (handshake type 11 from client side)
tshark -r "$PCAP" -n \
-Y "tls.handshake.type==11 and tcp.srcport != 443 and tcp.srcport != 8443" \
-T fields \
-E separator="\t" \
-e frame.time_epoch -e ip.src -e ip.dst -e tcp.srcport \
| sort | uniq -c | sort -rn | head -20
echo ""
echo "=== Non-standard TLS ports with client certificates (Sliver mTLS) ==="
tshark -r "$PCAP" -n \
-Y "ssl.handshake.certificate and not (tcp.port==443 or tcp.port==8443 or tcp.port==8080)" \
-T fields \
-E separator="\t" \
-e ip.src -e ip.dst -e tcp.dstport \
| sort | uniq -c | sort -rn | head -20
echo ""
echo "=== Sliver HTTP mode (Go UA, /rpc.php path) ==="
tshark -r "$PCAP" -n \
-Y "http.user_agent contains \"Go-http-client\"" \
-T fields \
-E separator="\t" \
-e frame.time_epoch -e ip.src -e ip.dst -e http.request.uri \
| head -20
echo ""
echo "=== TLS with client certificate (mutual TLS) ==="
# Count Certificate messages sent by clients (not servers)
# Client certs appear before the server Certificate in the handshake
tshark -r "$PCAP" -n -Y "tcp.dstport!=443 and tls.handshake.type==11" \
-T fields -E separator="\t" \
-e ip.src -e ip.dst -e tcp.dstport \
| sort | uniq -c | sort -rn | head -20
Metasploit Meterpreter Detection
#!/bin/bash
PCAP="$1"
echo "=== Metasploit default port 4444 ==="
tshark -r "$PCAP" -n \
-Y "tcp.port==4444" \
-T fields \
-E separator="\t" \
-e frame.time_epoch -e ip.src -e ip.dst -e tcp.flags
echo ""
echo "=== Meterpreter HTTPS: TLS with no SNI, large initial data ==="
# Meterpreter often connects with no SNI and sends a large initial data blob
tshark -r "$PCAP" -n \
-Y "tls.handshake.type==1 and not tls.handshake.extensions_server_name" \
-T fields \
-E separator="\t" \
-e frame.time_epoch -e ip.src -e ip.dst -e tcp.dstport \
| head -30
echo ""
echo "=== Known Metasploit JA3 ==="
# Metasploit uses Ruby's OpenSSL; JA3: de9f2c7fd25e1b3afad3e85a0226a4c4
echo "Known Metasploit JA3: de9f2c7fd25e1b3afad3e85a0226a4c4"
echo "Would need Zeek ssl.log or custom JA3 script to match"
echo ""
echo "=== Non-standard TLS ports (MSF often uses 4444, 8443) ==="
tshark -r "$PCAP" -n \
-Y "tls and (tcp.port==4444 or tcp.port==8443 or tcp.port==9443)" \
-T fields \
-E separator="\t" \
-e ip.src -e ip.dst -e tcp.dstport \
| sort | uniq -c | sort -rn | head -20
Sliver, Havoc, and several other newer C2 frameworks are written in Go. Go's crypto/tls standard library produces a distinctive JA3 fingerprint — the default cipher suites, extensions, and curves offered by Go's TLS client are different from Chrome (BoringSSL), Firefox (NSS), or Java. This means any C2 framework using Go's default TLS configuration can be identified by JA3 as "Go-based application" even if the operator hasn't customized anything else. The Go TLS default JA3 (which varies by Go version) is a starting point for clustering C2 traffic. Go developers can manually specify cipher suites and extensions to mimic browser fingerprints, but this requires explicit effort and is often not done in default framework configurations. When you see a Go TLS JA3 in your environment from a host that shouldn't be running Go applications, that's worth investigating.
Q & A
Q: How do I keep my C2 detection signatures current as new frameworks emerge?
C2 framework network signatures change with every new version and every operator customization. Strategies for staying current: (1) Subscribe to framework release notes: Sliver, Havoc, and Brute Ratel publish release notes; watch for changes to default profiles, ports, and TLS configurations. (2) Run frameworks in your own lab: the most reliable way to get current signatures is to run the framework yourself, capture traffic, and extract the JA3/JARM/URI patterns. This also gives you known-good data for testing your own detection stack. (3) Follow threat intel reports: Mandiant, CrowdStrike, Recorded Future, and similar firms regularly publish detailed C2 traffic analysis when they encounter new or updated frameworks in real intrusions. These reports include updated JA3 hashes, PCAP examples, and IOC lists. (4) Maintain a JA3 database: use a tool like Suricata with the ja3-and-ja3s rules, or Zeek with the ja3 package, and collect all JA3 hashes seen in your environment. When a new C2 framework appears in the wild, you can retroactively search your JA3 database to see if it appeared before the discovery.