c2

package
v0.0.0-...-e4d846e Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 1, 2026 License: MIT Imports: 25 Imported by: 0

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

Constants

This section is empty.

Variables

View Source
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

func AddNoise(data []byte) ([]byte, error)

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

func ApplyFronting(req *http.Request, frontDomain string, actualHost string)

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

func CryptoRandIntn(n int) int

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

func DecryptAESGCM(data, key []byte) ([]byte, error)

DecryptAESGCM decrypts an AES-256-GCM payload (exported for use by other packages). Expected input format: nonce (12 bytes) || ciphertext+tag.

func EncodeBeacon

func EncodeBeacon(beacon *config.Beacon, sessionKey []byte) ([]byte, error)

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

func MimicBrowserHeaders(req *http.Request)

MimicBrowserHeaders sets realistic browser headers on an HTTP request to make C2 traffic blend in with normal web browsing activity.

func NewFrontedClient

func NewFrontedClient(frontDomain string, timeout time.Duration) *http.Client

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

func RandomBrowserUA(browser string) string

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

func RandomizedTLSConfig() *tls.Config

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

func ShapePayload(data []byte, targetSize int) ([]byte, error)

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

func ShuffleCiphers(ciphers []uint16) []uint16

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

func StripNoise(data []byte) ([]byte, error)

StripNoise removes the noise padding added by AddNoise by reading the 4-byte big-endian length prefix.

func UnshapePayload

func UnshapePayload(data []byte) ([]byte, error)

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.

func (*DNSTransport) Send

func (d *DNSTransport) Send(data []byte) ([]byte, error)

Send encodes data as DNS subdomain labels and sends via TXT queries. The data is base32 encoded, chunked into DNS-safe labels, and sent as subdomain queries. Responses are decoded from TXT record values.

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.

func (*DoHTransport) Send

func (d *DoHTransport) Send(data []byte) ([]byte, error)

Send encodes data using the same DNS tunneling scheme as DNSTransport but sends queries over HTTPS to DoH resolvers using wireformat (application/dns-message).

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

func NewL2Channel(cfg *L2Config) (*L2Channel, error)

NewL2Channel creates a raw AF_PACKET socket bound to a specific interface.

func (*L2Channel) Close

func (ch *L2Channel) Close() error

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

func (ch *L2Channel) Send(payload []byte) error

Send transmits a raw Ethernet frame with the given payload. The frame bypasses all netfilter/iptables processing.

func (*L2Channel) SendRecv

func (ch *L2Channel) SendRecv(payload []byte) ([]byte, error)

SendRecv sends a payload and waits for a response. Simple request-response pattern.

func (*L2Channel) SetPromiscuous

func (ch *L2Channel) SetPromiscuous(enable bool) error

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.

func (*L2Channel) SetRecvTimeout

func (ch *L2Channel) SetRecvTimeout(seconds int, useconds int) error

SetRecvTimeout sets a receive timeout on the socket.

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL