tcpdump is your network forensics Swiss Army knife, but if you’re only seeing packet summaries, you’re missing half the story. The -A and -X flags are your ticket to seeing the actual data inside those packets, presented in both human-readable ASCII and raw hexadecimal.
Let’s see it in action. Imagine you’re debugging a simple HTTP request. You’d run tcpdump like this:
sudo tcpdump -i eth0 -A 'port 80'
This captures traffic on eth0 destined for port 80 and prints the payload of each packet as ASCII. You’d see output like this:
15:30:01.123456 IP client.54321 > server.80: Flags [P.], seq 1:100, ack 1, win 1024, length 99
E.. ....@.@.......
GET /index.html HTTP/1.1
Host: example.com
User-Agent: curl/7.68.0
Accept: */*
15:30:01.123500 IP server.80 > client.54321: Flags [P.], seq 1:500, ack 100, win 2048, length 499
E.. ....@.@.......
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 400
<!DOCTYPE html>
<html>
<head>
<title>Example Page</title>
</head>
<body>
<h1>Hello, World!</h1>
</body>
</html>
Notice how the actual HTTP request and response are clearly visible. The -A flag automatically decodes packet payloads as ASCII.
Now, what if the payload isn’t plain text? What if it’s binary data, or you need to see exactly what’s being sent, including control characters or non-printable bytes? That’s where -X comes in.
sudo tcpdump -i eth0 -X 'port 80'
This command gives you a hex and ASCII dump of the packet payload. The output for the same HTTP request would look like this:
15:30:01.123456 IP client.54321 > server.80: Flags [P.], seq 1:100, ack 1, win 1024, length 99
0x0000: 4745 5420 2f69 6e64 6578 2e68 746d 6c20 GET /index.html
0x0010: 4854 5450 2f31 2e31 0d0a 486f 7374 3a HTTP/1.1..Host:
0x0020: 2065 7861 6d70 6c65 2e63 6f6d 0d0a 55 example.com..U
0x0030: 7365 722d 41 67 65 6e 74 3a 20 63 75 72 ser-Agent: cur
0x0040: 6c 2f 37 2e 36 38 2e 30 0d 0a 41 63 63 l/7.68.0..Acc
0x0050: 65 70 74 3a 20 2a 2f 2a 0d 0a 0d 0a ept: */*...
15:30:01.123500 IP server.80 > client.54321: Flags [P.], seq 1:500, ack 100, win 2048, length 499
0x0000: 4854 5450 2f31 2e31 2032 3030 204f HTTP/1.1 200 O
0x0010: 4b 0d 0a 43 6f 6e 74 65 6e 74 2d 54 K..Content-T
0x0020: 79 70 65 3a 20 74 65 78 74 2f 68 74 ype: text/ht
0x0030: 6d 6c 0d 0a 43 6f 6e 74 65 6e 74 2d ml..Content-
0x0040: 4c 65 6e 67 74 68 3a 20 34 30 30 0d Length: 400.
0x0050: 0a 0d 0a 3c 21 44 4f 43 54 59 50 45 ..<DOCTYPE
0x0060: 20 68 74 6d 6c 3e 0a 3c 68 74 6d 6c html><html
0x0070: 3e 0a 3c 68 65 61 64 3e 0a 3c 74 69 ><head><ti
0x0080: 74 6c 65 3e 45 78 61 6d 70 6c 65 20 tle>Example
0x0090: 50 61 67 65 3c 2f 74 69 74 6c 65 3e Page</title>
0x00a0: 0a 3c 2f 68 65 61 64 3e 0a 3c 62 6f ></head><bo
0x00b0: 64 79 3e 0a 3c 68 31 3e 48 65 6c 6c dy><h1>Hell
0x00c0: 6f 2c 20 57 6f 72 6c 64 21 3c 2f 68 o, World!</h1>
0x00d0: 31 3e 0a 3c 2f 62 6f 64 79 3e 0a 3c </body></bo
0x00e0: 2f 68 74 6d 6c 3e 0a /html>.
The left side shows the hexadecimal representation of each byte, and the right side shows its ASCII equivalent. Non-printable characters are typically represented by a dot (.). This is invaluable for dissecting custom protocols, encrypted data (where you’ll see random-looking hex), or any situation where you need to see the raw bit-for-bit content.
You can combine these flags too. tcpdump -i eth0 -AX 'port 80' will show you both the ASCII interpretation and the hex dump for each packet payload. This offers the best of both worlds: quick readability for text-based protocols and detailed raw data when you need it.
The real power of -A and -X emerges when you start filtering. For instance, to see only the ASCII payload of HTTP POST requests:
sudo tcpdump -i eth0 -A 'tcp port 80 and tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x504f5354'
This command first filters for traffic on port 80. Then, it uses a more advanced BPF filter:
tcp[12:1]gets the TCP header length byte.& 0xf0masks out the lower 4 bits, leaving only the header length in 32-bit words.>> 2converts it to bytes. This expression((tcp[12:1] & 0xf0) >> 2)calculates the offset to the TCP payload.[...] = 0x504f5354checks if the first four bytes of the payload match the ASCII representation of "POST".
When you need to see the raw bytes of a specific field in a protocol, or if you suspect non-printable characters are causing issues, the -X flag is your go-to. It gives you an unadulterated view of the data, byte by byte.
The most surprising thing about these flags is how often they reveal subtle issues that aren’t apparent from summary lines. A packet might look like it’s going to the right place with the right flags, but the payload could contain a malformed command, a missing newline, or incorrect data that breaks the application. Seeing the payload directly is the definitive way to confirm what’s actually being sent and received.
When you’re done with -A and -X, you’ll likely want to start looking at how to reconstruct entire conversations from tcpdump output.