Chapter 8

Follow Stream

Follow Stream reconstructs the full conversation of a TCP, UDP, HTTP, or TLS session from the individual packets — assembling the two directions into a readable conversation view. For a C2 session, it shows the attacker's commands and the victim's responses. For an HTTP session, it shows the full request and response including headers and body. This is how you see what actually happened at the application layer.

Scenario

You've identified a suspicious HTTP session: 47 requests at 60-second intervals from a workstation to an external IP on port 80. You need to see what each request contains — are these HTTP GETs for a static resource (normal update check), or is the request body varying (C2 check-in), or is there a response body containing encoded commands? Follow HTTP Stream shows you the complete request-response cycle for each HTTP session. Follow TCP Stream shows you the raw bytes of the TCP conversation if HTTP dissection isn't working.

Stream Types and When to Use Each

Stream typeWhat it showsWhen to use
Follow TCP StreamAll TCP payload bytes for a session, both directions, interleaved in orderUnknown protocols, raw shell sessions, when HTTP dissector isn't firing
Follow UDP StreamAll UDP datagrams in a "conversation" (same 5-tuple)DNS over UDP, QUIC (early packets), custom UDP protocols
Follow HTTP StreamDecoded HTTP headers and bodies, with chunked encoding reassembledHTTP C2 traffic, file downloads, POST body inspection
Follow TLS StreamDecrypted TLS stream (only if you have the session keys loaded)HTTPS analysis when you have SSLKEYLOGFILE or private key
Follow QUIC StreamQUIC stream data (requires QUIC dissection support)HTTP/3 traffic analysis

Following a TCP Stream

  Follow TCP Stream View
  ═══════════════════════════════════════════════════════════════════

  Right-click a packet → Follow → TCP Stream
  OR: Analyze menu → Follow → TCP Stream

  Stream display:
  ┌─────────────────────────────────────────────────────────────────┐
  │ [Red text = client → server direction]                          │
  │ [Blue text = server → client direction]                         │
  │                                                                  │
  │ GET /updates.rss HTTP/1.1\r\n                                   │
  │ Host: updates.microsoft.com\r\n                                 │
  │ User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)\r\n      │
  │ Accept: */*\r\n                                                  │
  │ \r\n                                                             │
  │                                                                  │
  │ HTTP/1.1 200 OK\r\n                                             │
  │ Content-Type: application/rss+xml\r\n                           │
  │ Content-Length: 47\r\n                                          │
  │ \r\n                                                             │
  │ 7b22636d64223a2263616c63"                                        │
  │ (hex-encoded command: {"cmd":"calc"})                            │
  └─────────────────────────────────────────────────────────────────┘

  Encoding options (bottom of stream window):
    ASCII → shows printable text (best for HTTP/commands)
    Hex   → shows raw hex (best for binary protocols)
    Raw   → raw bytes (save to file)
    EBCDIC, Hex dump, C arrays, YAML

  Save stream content: "Save as..." button → save to file for further analysis
  Stream number: noted in bottom-left — use tcp.stream == N filter to isolate

  Stream filter effect: Follow Stream auto-applies a filter like
  tcp.stream == 42 — showing only packets for that conversation.
  Clear the filter to return to all packets.

Following HTTP Streams — C2 Request Analysis

Texthttp-c2-stream-example.txt
Example: Cobalt Strike HTTP beacon (default profile, not obfuscated)

── REQUEST (client → server, red) ────────────────────────────────────
GET /jquery-3.3.1.min.js HTTP/1.1
Accept: */*
Cookie: __cfduid=BQDXJHAX...base64-encoded-checkin-data...
Host: updates.windowscdn.net
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5)
Connection: Keep-Alive
Cache-Control: no-cache

Forensic indicators:
├── URI path: /jquery-3.3.1.min.js (Cobalt Strike default — outdated version)
├── Cookie header: base64-encoded beacon check-in data (victim ID, metadata)
├── User-Agent: IE 9 on Windows Phone (extremely unusual for a 2026 workstation)
└── Host: windows CDN domain that doesn't match Microsoft's actual CDN

── RESPONSE (server → client, blue) ──────────────────────────────────
HTTP/1.1 200 OK
Content-Type: application/javascript
Content-Length: 223

// This is javascript!
/* 226 */
var y = function() {
    ...base64-encoded command data here...
}

Forensic indicators:
├── Content-Type: application/javascript (matches URI — superficially convincing)
├── Content body: "var y = function()" — CS default JavaScript wrapper
├── The base64 content is the encoded command from the team server
└── Content-Length matches exactly — no chunked encoding (CS default behavior)

This is the complete C2 exchange visible in Follow HTTP Stream.
If you didn't Follow Stream, you'd only see "HTTP GET" in the packet list.
The cookie and response body encoding are only visible here.

Following TLS Streams with SSLKEYLOGFILE

Bashtls-decryption-setup.sh