4.2 ; EXFIL
Challenge Description
PCAP captured on 2026-03-16 ; one day after the compromise of NODE 07. Something was exfiltrated. Decrypt it. Read it carefully.
Files provided: exfil.pcap
Required: handshake_key from 4.1 ; REMNANT
Overview
The PCAP contains C2 traffic using a custom application protocol (ECP) over TCP port 4433. Each data chunk is encrypted with AES-128-CBC, with per-chunk IVs derived from a base IV. Both the stream key and base IV are derived from the handshake key recovered in 4.1. Three of four chunks are present in the PCAP, the fourth is missing. An ACK packet contains a plaintext field pointing back to the Tier 2 INTERCEPT PCAP.
Step 1: Parse the PCAP
Open in Wireshark (https://www.wireshark.org) and filter by tcp.port == 4433.
The TCP stream carries a framed application protocol. Each frame begins with a
4-byte magic value 0x45435000 ("ECP\x00"), followed by type, sequence, length,
and payload.
Extract TCP payloads programmatically:
import struct
def parse_pcap(path):
with open(path, "rb") as f:
f.read(24) # skip global header
packets = []
while True:
hdr = f.read(16)
if len(hdr) < 16: break
_, _, inc_len, _ = struct.unpack("<IIII", hdr)
data = f.read(inc_len)
if len(data) < 54: continue
ip_ihl = (data[14] & 0x0f) * 4
tcp_off = 14 + ip_ihl
tcp_doff = (data[tcp_off + 12] >> 4) * 4
payload = data[tcp_off + tcp_doff:]
if payload:
packets.append(payload)
return packets
Parse ECP frames from the payloads:
ECP_MAGIC = 0x45435000
frames = []
for payload in packets:
if len(payload) < 8: continue
if struct.unpack(">I", payload[:4])[0] != ECP_MAGIC: continue
msg_type = payload[4]
seq = payload[5]
length = struct.unpack(">H", payload[6:8])[0]
body = payload[8:8+length]
frames.append({'type': msg_type, 'seq': seq, 'payload': body})
Types present: 0x01 HELLO, 0x02 DATA, 0x03 ACK, 0x04 FIN.
Step 2: Derive the Stream Key
The handshake key from 4.1 is a 32-byte hex string. Derive the stream key and base IV using HMAC-SHA256:
import hmac, hashlib
HANDSHAKE_KEY = bytes.fromhex("bbae799e...") # from beacon.enc in 4.1
STREAM_KEY = hmac.new(HANDSHAKE_KEY, b"EXFIL.STREAM.KEY", hashlib.sha256).digest()[:16]
STREAM_IV = hmac.new(HANDSHAKE_KEY, b"EXFIL.STREAM.IV", hashlib.sha256).digest()[:16]
Step 3: Decrypt the Data Chunks
Each DATA frame carries an AES-128-CBC encrypted chunk. The IV for chunk N is
STREAM_IV XOR N (where N is the sequence byte, zero-padded to 16 bytes):
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
def decrypt_chunk(ct, seq):
seq_iv = bytes(a ^ b for a, b in zip(STREAM_IV, seq.to_bytes(16, 'big')))
return unpad(AES.new(STREAM_KEY, AES.MODE_CBC, seq_iv).decrypt(ct), 16)
for frame in frames:
if frame['type'] == 0x02: # DATA
seq = frame['seq']
plaintext = decrypt_chunk(frame['payload'], seq)
print(f"--- chunk {seq} ---")
print(plaintext.decode())
Three DATA frames are present: sequence 1, 2, and 4. Sequence 3 is absent.
Each decrypted chunk contains a DATA field with a hex fragment of the final
signing key material, and chunk 4 contains the flag.
Step 4: Find the Missing Chunk
Chunks 1, 2, and 4 are present. Chunk 4 contains the assembly instruction:
ASSEMBLY ; CHUNKS 1+2+3+4 ; SIGNING.KEY. Three chunks are in hand. One is not.
There is no pointer. Chunk 3 does not appear anywhere in this PCAP. The question is where it came from.
The payload header in chunk 1 identifies the source node (ECHELON.NODE.07),
the operator (HANDLER.ARC), and the timestamp (2026-03-16). The exfiltration
happened on 2026-03-16, the day after the compromise. Go back to the earlier
captures from that node and audit every field, not just the ones that answered
the challenge at the time.
The X-Session-Trace response header in the Tier 2 INTERCEPT PCAP
(2026-03-14) contains the value f1e2d3c4b5a69788. That is chunk 3.
Step 5: Assemble the Signing Key
The four chunk DATA values concatenate to form the signing key material passed to 5.1 ; ECHELON:
chunk1.DATA : 7f3d9a1e2b4c8f0a6d5e9c3b7f2a1d8e
chunk2.DATA : 1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d
chunk3.DATA : f1e2d3c4b5a69788 (from Tier 2 PCAP)
chunk4.DATA : 9c8b7a6f5e4d3c2b1a0f9e8d7c6b5a4f
This value, combined with the C2 handshake key from 4.1 and the ACCESS.CERT.KEY
from the 3.3 heap artifact, feeds the final challenge.
Key Takeaways
C2 traffic that omits a payload chunk and includes a plaintext reference to another capture is realistic tradecraft misdirection. Operators sometimes deliberately fragment payloads across sessions to complicate forensic reconstruction. The lesson for defenders: every protocol field in every packet in every PCAP is potentially meaningful; partial analysis is not complete analysis.
Flag
ECHELON{exfil_left_a_trace}