You are on a box over SSH. There is no desktop, no Wireshark, and something on the network is talking to an address nobody can explain. Learning how to use tcpdump is how you answer that question with the one tool that is already installed, in a terminal that is 80 columns wide.
Tcpdump prints packets. That is the whole product. It has been doing it since 1988, it is on nearly every Linux and BSD system you will ever log into, and it is still the fastest way to find out what a machine is actually sending. It is a core skill for penetration testing, for incident response, and for the forensics half of any CTF. Open the Packet Pursuit lab in another tab as you read: it is a capture file with a flag split across three protocols, and everything below applies to it directly.
TL;DR: Tcpdump is a command line packet capture tool built on libpcap. The command you will use most is sudo tcpdump -i eth0 -n 'tcp port 80': pick an interface with -i, skip name resolution with -n, and put a BPF filter in quotes at the end. Add -w capture.pcap to save it and open the same file in Wireshark later. Learning to use tcpdump is really learning two things: how to read one output line, and how to write a filter that removes everything you do not care about.
What Is Tcpdump?
Tcpdump is a command line tool that captures packets from a network interface and prints a one line summary of each one. It can also write the raw packets to a .pcap file, which is the same format Wireshark reads, so a capture taken on a server with no GUI opens perfectly on your laptop.
Van Jacobson, Sally Floyd, Vern Paxson and Steven McCanne wrote it in 1988 at the Lawrence Berkeley Laboratory Network Research Group. It is BSD licensed and it sits on top of libpcap, the capture library that also powers Wireshark, Nmap, Snort and Suricata. When people say "the pcap format", they mean the file libpcap writes.
The current stable release is 4.99.6, published on 30 December 2025, and the Kali package tracks it. Ubuntu 24.04 LTS is still on 4.99.4, and for everything in this article the two behave identically.
One thing to get straight early, because it saves a lot of confusion later.
Tcpdump does not decode application protocols the way Wireshark does. It understands headers beautifully: Ethernet, IP, TCP, UDP, ICMP, DNS, ARP. Above that it mostly hands you bytes. There is no "Follow HTTP Stream", no protocol tree, no click-to-expand. What you get instead is speed, a filter language that runs in the kernel, and a binary that is already on the target.
Installing Tcpdump and the Permission Problem Nobody Warns You About
On Kali it is installed. On Debian or Ubuntu it is one command:
sudo apt update
sudo apt install tcpdump
Check what you got:
tcpdump --version
tcpdump version 4.99.4
libpcap version 1.10.4 (with TPACKET_V3)
OpenSSL 3.0.13 30 Jan 2024
Capturing packets needs root, or the raw socket capabilities that normally come with it. So every capture command below starts with sudo. If you would rather not do that, grant the binary the two capabilities it actually needs and run it as yourself:
sudo setcap cap_net_raw,cap_net_admin+eip $(which tcpdump)
Now the part that trips up almost everyone on Debian and Ubuntu. Those distributions build tcpdump to drop privileges after it opens the interface, switching to an unprivileged account called tcpdump. The official man page documents this under -Z: the user ID changes "after opening the capture device or input savefile, but before opening any savefiles for output". That ordering has a consequence. Output files are opened as the unprivileged user, so sudo tcpdump -w /root/capture.pcap fails with a permission error even though you are root, and when it does work the file is not yours:
-rw-r--r-- 1 tcpdump tcpdump 3115 Sep 14 07:18 cap.pcap
In practice: write captures somewhere the tcpdump user can reach, such as /tmp, then sudo chown $USER capture.pcap if you want to move it. Two minutes of confusion the first time, never again after that.
Before capturing anything, find out what you can capture on:
tcpdump -D
1.eth0 [Up, Running, Connected]
2.any (Pseudo-device that captures on all interfaces) [Up, Running]
3.lo [Up, Running, Loopback]
eth0 is the real network, lo is loopback where you watch a service talk to a database on the same host, and any captures on everything at once. Start with any when you do not yet know where the traffic is.
How to Use Tcpdump for Your First Capture
The general shape of every tcpdump command is the same: options, then a filter in single quotes.
sudo tcpdump -i lo -n 'tcp port 8000'
That prints a banner and then sits there until you press Ctrl+C:
tcpdump: listening on lo, link-type EN10MB (Ethernet), snapshot length 262144 bytes
^C
25 packets captured
50 packets received by filter
0 packets dropped by kernel
Three counters at the end, and the third is the one to watch. "Dropped by kernel" means packets arrived faster than tcpdump could write them and the kernel threw them away. Zero is what you want. Anything else means your capture has holes in it, and the fix is a tighter filter or -w to a file instead of printing to the terminal.
Four options carry most of the weight:
-i eth0chooses the interface. Use-i anywhen you are not sure.-nstops tcpdump resolving IP addresses to hostnames. Always use it. Without it, every new address triggers a DNS lookup, which slows the output to a crawl, fills your own capture with the lookups tcpdump just made, and announces your interest to whoever runs the DNS server. Add a second one,-nn, to leave port numbers as numbers too, so you see:8000instead of a guess at the service name.-c 100exits after 100 packets. Good for a quick look without holding Ctrl+C hostage.-w capture.pcapwrites raw packets to a file instead of printing them.
There is no -s0 in that list on purpose. Old tutorials add it so full packets get captured rather than truncated ones. The default snapshot length is now 262144 bytes, which is the whole packet on any normal network, and the banner above says so. A command that still carries -s0 is a copy of one written before 2021.
How to Read a Tcpdump Line
This is the skill everything else rests on. Here is one real line from the capture above:
07:18:27.260675 IP 127.0.0.1.56730 > 127.0.0.1.8000: Flags [S], seq 1533482769, win 65495, options [mss 65495,sackOK,TS val 12321087 ecr 0,nop,wscale 10], length 0
Left to right:
07:18:27.260675is the timestamp, down to microseconds. Timing is often the finding: a request every 60.0 seconds is a beacon, not a user.IPis the protocol of the outer layer. You will also seeIP6andARP.127.0.0.1.56730 > 127.0.0.1.8000is source then destination, and the last number after the final dot is the port. Tcpdump does not use a colon for ports, which catches everyone once.Flags [S]is the TCP flags field, and it is the most useful thing on the line.length 0is the payload size, not the packet size. A handshake packet carries no data.
The flag notation is compact and worth memorising:
[S]SYN, somebody is opening a connection[S.]SYN-ACK, and the dot always means ACK. Something is listening.[.]a plain ACK, usually an acknowledgement with nothing else to say[P.]PSH-ACK, which is the one carrying actual data[F.]FIN-ACK, a polite close[R]or[R.]RST, a refusal. Nothing is listening on that port, or a firewall rejected it.
Now read three consecutive lines from the same capture and the TCP handshake appears on its own:
07:18:27.260675 IP 127.0.0.1.56730 > 127.0.0.1.8000: Flags [S], seq 1533482769, win 65495, length 0
07:18:27.261001 IP 127.0.0.1.8000 > 127.0.0.1.56730: Flags [S.], seq 62299410, ack 1533482770, win 65483, length 0
07:18:27.261018 IP 127.0.0.1.56730 > 127.0.0.1.8000: Flags [.], ack 1, win 64, length 0
SYN, SYN-ACK, ACK. Once you can spot that pattern at a glance you can read a port scan, a failed connection and a working service straight off the terminal without thinking about it. A scan looks like hundreds of [S] packets with [R.] coming back from every closed port, which is precisely how an Nmap scan looks from the receiving end.
Notice the sequence numbers too. The first packet shows the real value, seq 1533482769, and every line after it counts from 1, because tcpdump switches to relative numbers once the handshake is done. Pass -S if you need the absolute values back.
Tcpdump Filters: The Skill Worth Learning
An unfiltered capture on a real interface is unreadable within two seconds. Filters are not an optimisation here, they are the tool.
Tcpdump uses BPF, the Berkeley Packet Filter language, documented in the pcap-filter man page. The filter is compiled and runs in the kernel, so packets you did not ask for are discarded before they are ever copied to tcpdump. That is why a good filter also fixes dropped packets.
A BPF expression is built from three kinds of word:
- Type:
host,net,port,portrange - Direction:
src,dst, or neither, which means both - Protocol:
tcp,udp,icmp,arp,ip,ip6
Combine them with and, or and not, and always wrap the whole thing in single quotes so your shell leaves the parentheses alone.
sudo tcpdump -i any -n 'host 192.0.2.10'
sudo tcpdump -i any -n 'dst port 443'
sudo tcpdump -i any -n 'net 10.0.0.0/8'
sudo tcpdump -i any -n 'icmp'
sudo tcpdump -i any -n 'src 192.0.2.10 and not port 22'
That last one is the filter you will type most often in real life. When you are working over SSH, an unfiltered capture shows you your own SSH session, which then generates more packets, which print more lines. Excluding port 22 is the difference between a readable capture and a runaway terminal.
Filters That Answer a Question
A few combinations are worth keeping because each one maps to something you actually want to know:
'tcp[tcpflags] & tcp-syn != 0 and tcp[tcpflags] & tcp-ack == 0'shows connection attempts only, with no replies and no data. This is how you see a port scan in progress, or confirm that a host really is trying to reach a service that never answers.'udp port 53'is DNS, and DNS is where a surprising amount of trouble hides.'port 80 or port 8080 or port 8000'catches cleartext HTTP on the ports people actually use.'arp'shows the local network asking who owns which address, which is how ARP spoofing becomes visible.
The SYN filter run against the sample capture returns exactly the two connection attempts that were made, out of 25 packets:
07:18:27.260675 IP 127.0.0.1.56730 > 127.0.0.1.8000: Flags [S], seq 1533482769, win 65495, length 0
07:18:27.274514 IP 127.0.0.1.56744 > 127.0.0.1.8000: Flags [S], seq 1574267851, win 65495, length 0
The confusion worth clearing up: BPF capture filters and Wireshark display filters are two different languages that look similar and are not interchangeable. host 192.0.2.10 is BPF. ip.addr == 192.0.2.10 is a Wireshark display filter. Typing the Wireshark version into tcpdump gives you a syntax error, and typing the tcpdump version into Wireshark's green bar gives you nothing. Wireshark accepts BPF as well, but only in its capture options dialog, not in the filter bar at the top.
Writing Captures to a File and Opening Them in Wireshark
Printing to the terminal is for watching. Anything you intend to analyse should go to a file.
sudo tcpdump -i eth0 -n -w /tmp/capture.pcap 'port 80 or port 443'
Nothing prints while that runs, which always feels broken the first time. Add -v and tcpdump reports a running packet count instead. The 25 packet capture used throughout this article came out at 3,115 bytes, so pcap files stay small until they do not: a busy uplink produces gigabytes an hour, and the fix is rotation.
sudo tcpdump -i eth0 -n -w /tmp/cap.pcap -C 100 -W 10
-C 100 starts a new file every 100 MB, and -W 10 keeps ten of them before overwriting the oldest. That is a capped 1 GB ring buffer you can leave running for days. Use -G 3600 instead when you want a new file every hour rather than every so many megabytes.
Read a saved file back with -r, and note that this needs no root at all:
tcpdump -r /tmp/capture.pcap -n
Filters work on read as well as on capture, and this is the habit that makes big captures manageable. Capture broadly once, then filter the file as many times as you need:
tcpdump -r capture.pcap -n 'host 192.0.2.10 and port 443'
Now the one command that makes tcpdump and Wireshark into a single tool. If the traffic you need is on a remote server with no GUI, do not capture, copy and open. Pipe it:
ssh [email protected] 'sudo tcpdump -i eth0 -U -w - not port 22' | wireshark -k -i -
-w - writes the capture to standard output, -U flushes each packet immediately rather than buffering, and wireshark -k -i - starts capturing from standard input straight away. You get Wireshark's full protocol decoding, live, on packets from a machine that has never heard of a window manager. The not port 22 is not optional: without it, your own SSH traffic feeds back into the capture.
Tcpdump in a CTF: Pulling a Flag Out of the Traffic
Forensics challenges hand you a pcap and a question. Tcpdump gets you to the answer faster than opening a GUI, provided you know two more flags.
-A prints each packet's payload as ASCII. On cleartext protocols it is close to reading the conversation:
tcpdump -r capture.pcap -nA 'tcp port 8000'
07:18:27.261121 IP 127.0.0.1.56730 > 127.0.0.1.8000: Flags [P.], seq 1:88, ack 1, win 64, length 87
E....+@.@..?...........@[g.........@.......
[email protected] /index.html HTTP/1.1
Host: 127.0.0.1:8000
User-Agent: curl/8.5.0
Accept: */*
The line of noise before the request is the IP and TCP header rendered as ASCII, which is meaningless by design. Everything after it is the HTTP request as it went over the wire.
Keep going through the same capture and a POST appears:
POST /login HTTP/1.1
Host: 127.0.0.1:8000
User-Agent: curl/8.5.0
Content-Length: 26
Content-Type: application/x-www-form-urlencoded
user=dana&password=hunter2
There it is, in the clear, because the form posted over HTTP instead of HTTPS. This is the single most common finding in beginner forensics challenges and it is still a real finding on real internal networks in 2026, usually on some management interface nobody has touched in years.
-X is the other one. It prints hex alongside ASCII, which is what you want when the payload is not text:
tcpdump -r capture.pcap -nX -c 1
0x0000: 4500 003c a829 4000 4006 9490 7f00 0001 E..<.)@.@.......
0x0010: 7f00 0001 dd9a 1f40 5b67 1711 0000 0000 .......@[g......
0x0020: a002 ffd7 fe30 0000 0204 ffd7 0402 080a .....0..........
That is where file headers hide. 4500 at offset zero is the start of an IPv4 header. Further into a payload, 504b 0304 is a ZIP file and 8950 4e47 is a PNG. Spotting a signature like that is how you know there is a file to carve out of the capture.
The workflow in a challenge is three steps. Get a shape for the traffic with tcpdump -r capture.pcap -nq, which prints one short line per packet. Filter down to the protocol the challenge is about. Then dump payloads with -A and pipe the lot through grep:
tcpdump -r capture.pcap -nA | grep -i -E 'flag|password|user='
DNS deserves its own look, because it carries data out of networks that block everything else. A normal query is unremarkable:
tcpdump -i any -n 'udp port 53'
07:20:43.478932 eth0 Out IP 192.0.2.2.43351 > 8.8.8.8.53: 24085+ AAAA? hackerdna.com. (31)
07:20:43.494090 eth0 In IP 8.8.8.8.53 > 192.0.2.2.43351: 24085 3/0/0 AAAA 2606:4700:20::ac43:4840 (115)
Tcpdump decodes DNS properly, so the query type and the name appear without any extra flags. What matters in an investigation is the shape of the names rather than any single query: long random looking subdomains, hundreds of unique names under one parent domain, queries that never repeat. Data being encoded into hostnames looks exactly like that, and once you have seen it you will not mistake it for normal traffic again. The DNS Tunneling Detective lab gives you a capture with it running.
One honest limit. Against HTTPS, -A shows encrypted bytes and nothing else. The metadata still tells you plenty: which addresses talked, when, how often, how much moved, and the server name from the TLS handshake when it is not itself encrypted. Often that answers the question. It is never enough to read the content.
Tcpdump vs Wireshark: Which One and When
This gets framed as a rivalry and it is not one. They share libpcap and they read the same file format. The right answer on most days is to use both.
| Capability | Tcpdump | Wireshark |
|---|---|---|
| Runs over SSH on a headless server | Yes | No |
| Already installed on the target | Usually | Rarely |
| Application protocol decoding | Headers only | Hundreds of protocols |
| Reassembling a whole TCP conversation | No | Follow TCP Stream |
| Extracting files from a capture | No | Export Objects |
| Long unattended captures | Ring buffer with -C and -W | Possible, heavier |
| Scriptable in a pipeline | Yes | Via tshark |
The division of labour writes itself. Capture with tcpdump, because it is on the box, it is light, and it will still be running tomorrow. Analyse in Wireshark, because reassembling streams and exporting files by hand is work nobody should be doing. Our guide to Wireshark covers the analysis half in detail.
The exception, and it is a real one: when you know what you are looking for, tcpdump plus grep beats loading a 2 GB pcap into a GUI every time. "Did this host ever talk to that address" is a one line question. Do not open Wireshark to answer it.
Legal and Ethical Considerations
Critical reminder: Always get explicit written authorization before capturing traffic on any network. Packet capture is interception. In the United States it falls under the Wiretap Act, in the United Kingdom under the Investigatory Powers Act, and across the EU under national implementations of the ePrivacy Directive. Unlike a port scan, a capture on a network you do not own can be a criminal offence even when you change nothing and touch nothing.
- Capture only on networks you own or that are named in a signed scope document
- Coffee shop and hotel Wi-Fi is somebody else's network carrying somebody else's private traffic. It is not a practice environment.
- A capture file contains credentials, session cookies, personal data and private messages. Treat it like the sensitive artefact it is: encrypt it at rest, keep it only as long as the engagement needs it, then delete it.
- Filter at capture time to what the scope actually covers. Collecting everything and promising to ignore most of it is not a defence.
- On a shared or corporate network, tell the people who run it before you start. A promiscuous interface shows up in monitoring and looks identical to an attack.
Lab captures and CTF challenges exist precisely so you can practise this without any of that hanging over you. That is where to build the reflexes.
Frequently Asked Questions
What is tcpdump used for?
Capturing and inspecting network traffic from the command line. Administrators use it to prove which side of a connection is failing, incident responders use it to see what a compromised host is talking to, penetration testers use it to find cleartext credentials and understand a network's layout, and CTF players use it to read the pcap files that forensics challenges hand them.
What is the difference between tcpdump and Wireshark?
Tcpdump is a command line capture tool that prints one line per packet. Wireshark is a graphical analyser that decodes hundreds of application protocols, reassembles TCP streams and exports files out of a capture. Both use libpcap and both read the same pcap files. The common workflow is to capture with tcpdump on a remote server and analyse the resulting file in Wireshark.
How do I write a tcpdump capture to a file?
Use -w: sudo tcpdump -i eth0 -n -w capture.pcap. Nothing prints to the terminal while it runs, which is normal. Read it back with tcpdump -r capture.pcap -n, or open it in Wireshark. On Debian and Ubuntu, write to a directory the unprivileged tcpdump user can reach, such as /tmp, or the file open fails despite sudo.
Can tcpdump see UDP traffic?
Yes. Tcpdump captures every protocol the interface sees, including UDP, ICMP and ARP. The name is a historical accident from 1988. Filter with udp, or narrow it: sudo tcpdump -i any -n 'udp port 53' shows DNS, and tcpdump decodes the queries and answers for you.
Does tcpdump need root?
Capturing does, because it needs raw socket access. Reading a saved file with -r does not. To capture without sudo, grant the binary the capabilities it needs with sudo setcap cap_net_raw,cap_net_admin+eip $(which tcpdump).
Can tcpdump read HTTPS traffic?
No. TLS encrypts the payload, so -A shows random bytes. You still get the metadata: source and destination addresses, ports, timing, volume, and often the requested hostname in the TLS handshake. That answers "who talked to what and when", never "what did they say".
Your Next Steps
Knowing how to use tcpdump comes down to a short list. -i and -n on every command, a BPF filter in single quotes so you are not reading noise, -w when the capture matters, -r to come back to it, and -A when you need to see what was actually sent. The flags take an afternoon. Reading the output fluently takes a few captures, and there is no shortcut past doing them.
So go and do one. Work through the Packet Pursuit lab and find a flag that was split across three protocols on purpose, then take the traffic interception chapter of our network penetration testing course for how captured traffic turns into an actual finding. Both run in the browser on HackerDNA's free tier, with no VM to build and no credit card. Then run tcpdump on your own machine for five minutes and watch what your laptop talks to when you think it is idle. That one is free too, and it is usually a surprise.
Part of the Penetration Testing series
Related articles: