Browse CTFs New CTF Sign in

Parsing FTP Command and Response Traffic with Passive Mode Data Channel Reconstruction

osint_collection Difficulty 1–5 30 min certifiable

Theory

Why This Matters

The 2014 Target breach post-mortem identified FTP as the exfiltration channel: compressed archives of 40 million payment card records were transferred out of the network via FTP to a staging server in Miami before being moved offshore. Forensic analysts reconstructed the entire exfiltration — including exact file names, sizes, and transfer timestamps — by replaying the FTP control and data channel traffic from a network tap. FTP remains in widespread use in industrial environments, embedded systems, legacy banking infrastructure, and media production pipelines. Any analyst working incident response will encounter FTP traffic in PCAPs, and the ability to reconstruct credentials and file contents from that traffic is a foundational skill.

Core Concept

FTP (File Transfer Protocol) uses a split-channel architecture. The control channel (TCP port 21) carries human-readable commands and responses throughout the session. The data channel (TCP port 20 in active mode, or an ephemeral high port in passive mode) carries actual file content and directory listings, opened fresh for each transfer.

Key control-channel commands: USER (username), PASS (password — plaintext), LIST (directory listing), RETR (download file), STOR (upload file), PASV/EPSV (switch to passive mode — server responds with IP and port for data connection), PORT (active mode — client provides IP and port for server to connect back to), QUIT (end session).

FTP response codes: 2xx = success, 3xx = further action needed (e.g., 331 = "Password required"), 4xx/5xx = errors.

In passive mode (the modern default), the PASV command response contains the server's IP and port as a comma-separated tuple: (192,168,1,1,195,149) = IP 192.168.1.1, port 195*256 + 149 = 50069. Analysts must parse this to identify the data channel TCP connection.

FTPS (FTP over TLS) is signalled by the AUTH TLS command on the control channel; subsequent traffic is TLS-encrypted and cannot be read without key material.

Technical Deep-Dive

# View all FTP control-channel commands and responses
tshark -r capture.pcap -Y "ftp" -T fields 
  -e frame.number -e frame.time_relative 
  -e ip.src -e ip.dst -e ftp.request.command 
  -e ftp.request.arg -e ftp.response.code -e ftp.response.arg 
  -E header=y -E separator="|"

# Extract only credential lines (USER and PASS commands)
tshark -r capture.pcap 
  -Y "ftp.request.command == "USER" or ftp.request.command == "PASS"" 
  -T fields -e frame.time_relative 
  -e ftp.request.command -e ftp.request.arg

# List all files retrieved (RETR) or stored (STOR)
tshark -r capture.pcap 
  -Y "ftp.request.command == "RETR" or ftp.request.command == "STOR"" 
  -T fields -e frame.time_relative 
  -e ip.src -e ftp.request.command -e ftp.request.arg

# Follow a specific FTP control-channel stream in Wireshark:
# Right-click any FTP packet → Follow → TCP Stream
# This shows the full session transcript in ASCII

# Extract file content from FTP data channel stream N
# First identify the stream number: Wireshark Statistics → Conversations → TCP
# Find the data-channel conversation (short-lived, high port, large payload)
tshark -r capture.pcap -z "follow,tcp,raw,3" 2>/dev/null 
  | grep -v "^===" | xxd -r -p > extracted_file.bin
# (Replace stream 3 with the actual data-channel stream index)

# Detect FTPS (AUTH TLS command present)
tshark -r capture.pcap 
  -Y "ftp.request.command == "AUTH" and ftp.request.arg == "TLS"" 
  -T fields -e frame.number -e frame.time_relative -e ip.src -e ip.dst
# Python/Scapy: reconstruct FTP session and extract credentials
from scapy.all import rdpcap, TCP, Raw
from collections import defaultdict

pkts = rdpcap("capture.pcap")
streams = defaultdict(list)

for pkt in pkts:
    if pkt.haslayer(TCP) and pkt.haslayer(Raw):
        # Control channel: dst or src port 21
        sport, dport = pkt[TCP].sport, pkt[TCP].dport
        if sport == 21 or dport == 21:
            key = tuple(sorted([(pkt["IP"].src, sport),
                                (pkt["IP"].dst, dport)]))
            streams[key].append((sport == 21, pkt[Raw].load))

for key, msgs in streams.items():
    print(f"
=== FTP Stream {key} ===")
    for is_server, data in msgs:
        prefix = "S>" if is_server else "C>"
        try:
            print(f"{prefix} {data.decode(errors='replace').strip()}")
        except Exception:
            print(f"{prefix} [binary: {len(data)} bytes]")

Analytical Methodology

  1. Open the PCAP in Wireshark. Apply display filter ftp to isolate the control channel. Scroll through to identify USER and PASS commands — these appear as plaintext in the Info column.
  2. Apply filter ftp.request.command == "PASS" to jump directly to the password frame. Note the username (preceding USER command in the same stream) and password value.
  3. Right-click any control-channel frame and select Follow → TCP Stream. Read the entire session transcript to identify all files listed, retrieved, or stored, and any error messages that reveal server configuration.
  4. Identify PASV or EPSV responses to determine data channel ports. Parse the port number from the response argument. In Wireshark, the ftp-data dissector automatically associates data-channel streams — apply filter ftp-data to see them.
  5. For each RETR or STOR command, follow the corresponding ftp-data TCP stream. Right-click a ftp-data frame → Follow → TCP Stream → set encoding to RawSave as to write the raw file bytes to disk.
  6. Use tshark follow,tcp,raw,N for scripted extraction of multiple files. Pipe the hex output through xxd -r -p to recover binary content.
  7. Load the PCAP into NetworkMiner. The Files tab automatically detects and reassembles FTP data-channel transfers, providing a filename, size, MD5, and one-click save. This is faster than manual stream following for multi-file transfers.
  8. If AUTH TLS is present (FTPS), note that the data channel is also encrypted. The control channel commands up to and including AUTH TLS are plaintext; credentials and file names are encrypted after the TLS handshake completes.
  9. Correlate transfer timestamps with other PCAP events: did a STOR of a large archive file follow immediately after a database query or file access pattern visible elsewhere in the capture?

Common Analytical Errors

  • Missing data-channel streams by port filter: Analysts who filter only on tcp.port == 21 see only control traffic. The file content is on a separate TCP connection on a negotiated high port. Always follow up on ftp-data streams or use NetworkMiner's automatic reconstruction.
  • Confusing active and passive mode data channels: In active mode the server initiates the data connection back to the client; in passive mode the client initiates to the server. The direction of the TCP SYN on the data channel determines which mode is in use and which side's firewall policy is relevant.
  • Truncated stream follows: Wireshark's Follow TCP Stream truncates output at a display limit by default. For large file transfers, use tshark follow,tcp,raw or NetworkMiner to ensure complete extraction.
  • Treating 530 errors as evidence of no access: A 530 Login incorrect response followed immediately by a successful 230 Login successful on the same session indicates a credential guess that eventually succeeded. Count all 530 responses per source IP to detect brute-force attempts.
  • Overlooking the CWD and directory listing commands: CWD (change working directory) and LIST responses reveal the server's directory structure and file inventory, which provides context for what data was accessible even if no RETR commands are observed.

NICE Framework Alignment

Code Knowledge/Skill/Task Statement How This Card Develops It
K0046 Knowledge of intrusion detection systems and methodologies Recognising FTP credential theft and exfiltration patterns that IDS signatures detect: cleartext PASS, large STOR transfers, unusual hours
K0093 Knowledge of network protocols Understanding FTP's dual-channel architecture, active vs passive mode port negotiation, and the full command/response sequence
K0221 Knowledge of OSI model and network layers Relating FTP's application-layer (layer 7) command structure to the TCP connections at layer 4 that carry control vs data traffic separately
S0046 Skill in performing packet-level analysis Using Wireshark ftp/ftp-data filters, Follow TCP Stream, tshark stream extraction, and NetworkMiner file reassembly to recover credentials and file content
T0023 Collect intrusion artifacts for use in forensic analysis Reconstructing transferred files from FTP data-channel streams and preserving them with MD5 hashes as forensic exhibits

Further Reading

  • Network Forensics: Tracking Hackers Through Cyberspace — Sherri Davidoff & Jonathan Ham, Chapter 9: File Transfer Forensics (Prentice Hall)
  • The Practice of Network Security Monitoring — Richard Bejtlich, Chapter 6: Application Protocol Analysis (No Starch Press)
  • RFC 959: File Transfer Protocol — Postel & Reynolds (IETF)

Challenge Lab

Reinforce your learning with a hands-on generated challenge based on this card's competency.