TCP/IP is the backbone on modern networks including the Internet. Understanding how information travel across a network is crucial for network and system administrators. Often, they will have to capture and analyze packets going in and out of servers to diagnose and fix network issues or even detect cyber-attacks.

With the rapid advances in malwares affecting huge networks and organization, mastering packet capturing and sniffing will give you a huge advantage and may often be the only way to detect issues on your network.

tcpdump is one of the simplest and yet powerful open-source tool for packet capturing. It can be used to analyze network protocols, reading raw packet values and filtering information per IP, port, and a bunch of other features. Let’s dive in!

Hands-on

You will need a Linux system to be able to follow this guide. If you are not on Linux, you can also simply download the latest Ubuntu image and install on a virtual machine using VirtualBox. tcpdump won’t work on WSL but it seems to be working on WSL2. I will be using a VM of Ubuntu 20.04 on VirtualBox for this tutorial, and tcpdump is already installed on the system.

If your Linux distribution doesn’t have tcpdump already installed, you can do with this command:

$ sudo apt update && sudo apt install tcpdump

Capturing Packets

Capturing packets is as simple as executing tcpdump:

$ sudo tcpdump
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
19:26:05.618248 IP localhost.37972 > localhost.domain: 12219+ [1au] A? ntp.ubuntu.com. (43)
19:26:05.618281 IP localhost.37972 > localhost.domain: 60545+ [1au] AAAA? ntp.ubuntu.com. (43)

The output may look confusing at first, but you will get used to it. The most important information here is:

  • tcpdump is listening to all network interfaces on the system, as we did not specify any. You can use -i parameter to specify the interface you want to sniff on.
  • The traffic is listed in sequential order, indicating source and destination IP / hostname with port number or service name. Here you can see that the system is trying to get the IP for domain ntp.ubuntu.com.

You can always press CTRL+C anytime to quit the capturing session.

Note: For the network interface to capture all packets, even those that are not designated for it. The card must enter Promiscuous mode. This will be done automatically when executing tcpdump as root.

Printing HEX Values

For detailed analysis, we often need to be able to read the values in hexadecimal (HEX). This can be accomplished with the switch -X.

This is also very helpful as not all values have printable characters. You will notice this in the output below where you will notice a bunch of dot characters but with different values:

$ sudo tcpdump -X
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
19:34:36.687818 IP localhost > localhost: ICMP echo request, id 3, seq 1, length 64
	0x0000:  4500 0054 0a36 4000 4001 3271 7f00 0001  [email protected]@.2q....
	0x0010:  7f00 0001 0800 6208 0003 0001 0c42 0c60  ......b......B.`
	0x0020:  0000 0000 b47e 0a00 0000 0000 1011 1213  .....~..........
	0x0030:  1415 1617 1819 1a1b 1c1d 1e1f 2021 2223  .............!"#
	0x0040:  2425 2627 2829 2a2b 2c2d 2e2f 3031 3233  $%&'()*+,-./0123
	0x0050:  3435 3637                                4567
19:34:36.687827 IP localhost > localhost: ICMP echo reply, id 3, seq 1, length 64
	0x0000:  4500 0054 0a37 0000 4001 7270 7f00 0001  [email protected]
	0x0010:  7f00 0001 0000 6a08 0003 0001 0c42 0c60  ......j......B.`
	0x0020:  0000 0000 b47e 0a00 0000 0000 1011 1213  .....~..........
	0x0030:  1415 1617 1819 1a1b 1c1d 1e1f 2021 2223  .............!"#
	0x0040:  2425 2627 2829 2a2b 2c2d 2e2f 3031 3233  $%&'()*+,-./0123
	0x0050:  3435 3637                                4567
^C
2 packets captured
4 packets received by filter
0 packets dropped by kernel

We have just captured an ICMP echo and reply, more commonly known as a ping.

Let’s push it further and hide a message in the ICMP packets. An attacker could easily write a small Python script that steal information on a host and send that information to another host hiding them in ICMP packets.

Let’s do it:

1. Converting an example text to hexadecimal with the following command:

$ echo -n "Secret password" | od -A n -t x1
 53 65 63 72 65 74 20 70 61 73 73 77 6f 72 64

2. Launching tcpdump capturing only ICMP packets:

$ sudo tcpdump -X icmp

3. Now enter those values without whitespaces in the ICMP packet with the following command:

$ ping localhost -c 1 -p 5365637265742070617373776f7264

4. The output of your tcpdump should now the display the secret text:

$ sudo tcpdump -X icmp
19:50:27.197580 IP localhost > localhost: ICMP echo request, id 6, seq 1, length 64
	0x0000:  4500 0054 59e8 4000 4001 e2be 7f00 0001  [email protected]@.......
	0x0010:  7f00 0001 0800 4992 0006 0001 c345 0c60  ......I......E.`
	0x0020:  0000 0000 ad03 0300 0000 0000 6563 7265  ............ecre
	0x0030:  7420 7061 7373 776f 7264 5365 6372 6574  t.passwordSecret
	0x0040:  2070 6173 7377 6f72 6453 6563 7265 7420  .passwordSecret.
	0x0050:  7061 7373                                pass
19:50:27.197594 IP localhost > localhost: ICMP echo reply, id 6, seq 1, length 64
	0x0000:  4500 0054 59e9 0000 4001 22be 7f00 0001  [email protected]".....
	0x0010:  7f00 0001 0000 5192 0006 0001 c345 0c60  ......Q......E.`
	0x0020:  0000 0000 ad03 0300 0000 0000 6563 7265  ............ecre
	0x0030:  7420 7061 7373 776f 7264 5365 6372 6574  t.passwordSecret
	0x0040:  2070 6173 7377 6f72 6453 6563 7265 7420  .passwordSecret.
	0x0050:  7061 7373                                pass

Filtering Packets

You can use filters in tcpdump, the below is an example of how you can filter by host:

$ sudo tcpdump -X host localhost

In this case, we’re filtering packets by the localhost host (both source and destination), if you want to filter by destination address you can use dst instead of host, the same thing on source address (src).

You can also filter by port number, this can be useful for capturing web traffic for example:

$ sudo tcpdump -X port 80
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
19:55:40.067169 IP localhost.40768 > localhost.http: Flags [S], seq 531515134, win 65495, options [mss 65495,sackOK,TS val 3984359995 ecr 0,nop,wscale 7], length 0
	0x0000:  4500 003c 43c0 4000 4006 f8f9 7f00 0001  E..<[email protected]@.......
	0x0010:  7f00 0001 9f40 0050 1fae 46fe 0000 0000  [email protected]
	0x0020:  a002 ffd7 fe30 0000 0204 ffd7 0402 080a  .....0..........
	0x0030:  ed7c 823b 0000 0000 0103 0307            .|.;........
19:55:40.067183 IP localhost.http > localhost.40768: Flags [S.], seq 2047482984, ack 531515135, win 65483, options [mss 65495,sackOK,TS val 3984359995 ecr 3984359995,nop,wscale 7], length 0
	0x0000:  4500 003c 0000 4000 4006 3cba 7f00 0001  E..<[email protected]@.<.....
	0x0010:  7f00 0001 0050 9f40 7a0a 1c68 1fae 46ff  [email protected]
	0x0020:  a012 ffcb fe30 0000 0204 ffd7 0402 080a  .....0..........
	0x0030:  ed7c 823b ed7c 823b 0103 0307            .|.;.|.;....
19:55:40.067192 IP localhost.40768 > localhost.http: Flags [.], ack 1, win 512, options [nop,nop,TS val 3984359995 ecr 3984359995], length 0
	0x0000:  4500 0034 43c1 4000 4006 f900 7f00 0001  [email protected]@.......
	0x0010:  7f00 0001 9f40 0050 1fae 46ff 7a0a 1c69  [email protected]
	0x0020:  8010 0200 fe28 0000 0101 080a ed7c 823b  .....(.......|.;
	0x0030:  ed7c 823b     

There are a lot of other filters, such as portrange, net and more, I encourage you to type man tcpdump for detailed information.

Saving Captured Packets

During interventions or problem investigation, it is often a good practice to save the captured packets. Those packets can be replayed or analyzed through other packet sniffers such as Wireshark or Scapy.

To save packets, use the follow command:

$ sudo tcpdump -w packets.pcap -X port 80

By simply adding -w parameter, you specify the output file name. You’ll also notice that the file is a binary file, meaning that the data captured is not human readable and requires a program to read it.

Reading Captured Packets

To read pcap files, you can use tcpdump with the following command:

$ sudo tcpdump -r packets.pcap 
reading from file packets.pcap, link-type EN10MB (Ethernet)
19:59:25.855559 IP localhost.40768 > localhost.http: Flags [P.], seq 531515135:531515138, ack 2047482985, win 512, options [nop,nop,TS val 3984585784 ecr 3984359995], length 3: HTTP
19:59:25.855759 IP localhost.http > localhost.40768: Flags [.], ack 3, win 512, options [nop,nop,TS val 3984585784 ecr 3984585784], length 0

Similarly, the -r parameter is the input file you want to analyze, this pcap file can be captured by any sniffing program that supports pcap format.

Conclusion

I hope you enjoyed this introductory guide to packet sniffing with tcpdump. You can type man tcpdump to see various parameters and filtering techniques.

And remember, the quickest way to master this tool as many other Linux tools is to practice. Sniff your chats, web browsing, and you may even discover secret connections initiated by some software sending information to their servers without notifying you.

Read also: How to Scan SQL Vulnerable Sites with Sqlmap

Happy network hacking!