-
-
Pipe To Wireshark
-
Dumping to Files
-
Snapshot Length
-
Focusing On The Problem
-
Analyzing A Specific Type Of Traffic
-
Skip Resolving
-
Over SSH Without The SSH Traffic
-
Permissions Problems
-
-
-
VLAN Discovery
-
Checking For Passwords In The Clear
-
Analyzing Bandwidth
-
Simple Text Data
-
Finding MAC Addresses
-
This program is the workhorse for capturing network packets.
Note
|
If you need to capture traffic between two hosts that you don’t have easy ability to run software on but you have physical access, interject an old school hub between the hosts and put a 3rd host with decent Linux tools (running the capture) on that hub too. |
Note
|
tcpdump pretty much always likes you more if your UID is 0 (i.e. use sudo and run as root). If you can’t do this, see trick above. |
Useful Options
-
-U
Flush on each packet instead of the arbitrary point when the buffer fills. -
-w <file|->
Write packets to a standard pcap file instead of parsing them and printing summary information about them. Use-
for standard output. -
-r <file>|-
Read the packets from a file (maybe previously collected with-w
) instead of a network source. -
-i <interface>
Specify the interface to listen to (eth0
, etc.). -
-s <val|0>
Snapshot length is number of bytes per packet to look at. The default is 68 which may be enough to analyze the nature of traffic, but not enough to analyze the content of the packet. Set to0
to capture the whole packet. -
-tttt
Print timestamp on each line of the dump. -
-X
Include contents of the payload. Use-XX
to include every thing including header data. If you just want the ASCII part try the similar-A
. -
-n
is don’t resolve names.-nn
is don’t resolve names or ports. These are faster and involve less network clutter. -
-l
relates to line buffering. It basically flushes the output after every line. If you want the output dispatched after every packet try the-U
option. One of these options is important if you’re expecting sensible real-time activity from Unix pipelines.
BPF
Once you’ve set the options for how tcpdump will work, specifying exactly what it will do is a huge topic. The rich syntax may seem bewildering and overly complex at first, but it is part of an ancient and proven technology called BPF. This is actually a full byte-code language that gets compiled (yes, within the execution of tcpdump).
To find out a lot about the immense functionality in this syntax check
out man 7 pcap-filter
.
Decoding Output
The general format of a tcp protocol line is:
src > dst: flags data-seqno ack window urgent options
U |
URG |
Urgent |
. |
ACK |
Acknowledge (bit 11, don’t know its tcpdump code) |
P |
PUSH |
|
R |
RST |
Reset |
S |
SYN |
Synthesize (i.e. initiate) |
F |
FIN |
|
E |
ECN-Echo |
Explicit Congestion Notification (RFC3168) |
W |
ECN CWR |
Congestion Window Reduced |
For the canonical reference see RFC793 - Transmission Control Protocol.
From the man page comes this helpful explanation.
Src and dst are the source and destination IP addresses and ports.
Flags are some combination of S (SYN), F (FIN), P (PUSH), R (RST), U
(URG), W (ECN CWR), E (ECN-Echo) or .
(ACK), or none
if no flags
are set. Data-seqno describes the portion of sequence space covered by
the data in this packet (see example below). Ack is sequence number of
the next data expected the other direction on this connection. Window
is the number of bytes of receive buffer space available the other
direction on this connection. Urg indicates there is urgent
data in
the packet. Options are tcp options enclosed in angle brackets (e.g.,
<mss 1024>).
Tips
Pipe To Wireshark
By using a file name option of -w-
the pcap file will be written to
standard output. It seems that you can then pipe that to the Wireshark
executable.
Dumping to Files
By default the packets are summarized and cleaned up and sent to stdout, but you can specify a file name for the actual raw packets captured. This file can then be used by tcpdump in the place of actual interfaces to see the summarized and cleaned up output. Writing:
# tcpdump -w /thenameofthefilehere.pcap
Reading (perhaps to have a quick look at it):
# tcpdump -r /thenameofthefilehere.pcap | less
Snapshot Length
This controls the snapshot length which on Linux seems to be 90 bytes even though the man page says 68. This means that it only thinks about and writes the first 90 bytes of each packet. That’s fine if you just want to see packet headers and get a sense of what’s going on, but if you want to guarantee that a particular content is or isn’t (e.g. clear text passwords) being transmitted, you might want to capture all bytes. Set this to 0 for all bytes in the packet to be captured. Example:
# tcpdump -i eth0 -s 0
Focusing On The Problem
Let’s say you’re trying to troubleshoot some particular problem. If, for example, you want to scrutinize a web page request, you want to focus on port 80. Here’s how:
$ sudo tcpdump -i eth0 -s 0 tcp port 80
Or just look at the traffic to and from a specific host.
$ sudo tcpdump -i wlan0 host 192.168.1.243
Or more than one host.
$ sudo tcpdump -i enp3s0 'host 192.168.1.253 or host 192.168.1.4'
Sometimes there is a bunch of chatter from chattery processes and equipment (routers are filled with STP - spanning tree protocol, ARP - address resolution protocol, DTP - dynamic trunking protocol, etc). Perhaps the worst offender for traffic you do not wish to keep an eye on is the SSH traffic that you’re using to log into the machine in the first place. To specifically exclude such unwanted traffic from consideration use something like this:
tcpdump -i eth0 -s 0 not tcp port 22 and not tcp port 53 and not tcp port 123 and not arp and not stp
Breaking Up Huge Capture Files
Another way to focus on the problem involves looking for a needle in a haystack with respect to time. What if you have a giant capture file with gigabytes of packets? Maybe you want to start searching about 80% through the pcap file. You can use tcpdump itself to break up large pcap file.
This command will break up the large radar data file into smaller files of (roughly) 100 MB.
tcpdump -r radar_capture-191028-115136.pcap -w riversections.pcap -C 100
This will produce a lot of files like riversections.pcap1
etc. Note
that they don’t sort well since they’re not zero padded.
This lets me check a small file and if it’s in the wrong region, I can skip ahead a few files and zoom in on my region of interest.
Analyzing A Specific Type Of Traffic
In this example I’m trying to capture all of the packets associated with a secure LDAP connection. By capturing all of the data that was passed back and forth to the LDAP server, I can search through it and check to see if any passwords went over in the clear. First to get the data use this command:
sudo tcpdump -i eth0 -s 0 -w ldapcapture.pcap tcp port 636
Then run wireshark ldapcapture.pcap
to start up the graphical
analysis program Wireshark. Go to Edit->Find Packet
(Ctrl-F) and do
a string search for the password you’re looking for (or hoping you
won’t find).
Skip Resolving
To prevent hostname lookups use -n
. What I find really annoying,
however, are the often incorrect port/service lookups. To prevent this
use -nn
. This means that if you want hosts you get services too as
far as
I
can tell.
Over SSH Without The SSH Traffic
Often you’ll need to monitor something on another computer. Obviously you monitoring is traffic and that is not interesting. Furthermore, it will become a feedback loop - the more traffic you monitor, the more traffic there is. To get around this problem you need to filter yourself out of what is being watched.
sudo /usr/sbin/tcpdump -i eth0 port not 22
Or if you want to watch the SSH traffic of other processes, you can try something like this.
sudo /usr/sbin/tcpdump -i eth0 port not 22 and host 192.168.0.88
Permissions Problems
It can be very frustrating and annoying to need sudo
for every
packet capture. For most modern Linux applications this is not a
security risk (or it shouldn’t be!). There are rumors of Wireshark
having an install mode where normal users can capture packets.
Here
is a guy who has explicitly figured out how to change Linux
capabilities and permissions to accomplish this.
When you install Wireshark in Debian it asks if you want normal users
to be able to capture packets. I just tried that and answered yes and — guess what? — still can’t capture packets. I even added my user to
the wireshark
group which was created during the install.
gpasswd -a xed wireshark
Useful Examples
VLAN Discovery
Before jumping into tcpdump
, it can be helpful to check if the link
is even properly up.
sudo ethtool eth0
Once the link is known to be active, one might wonder if the correct VLAN is active on the network.
sudo tcpdump -nn -v -i eth0 -s 1500 -c 1 'ether[20:2] == 0x2000'
Checking For Passwords In The Clear
Are you at some login page and HTTPS is not active and you are wondering if your plain text password can be sniffed off the wire? Well, here’s how you sniff it to check.
:-<[dev-desktop][~]$ sudo tcpdump -s 0 -A -n -l | egrep -i "os_password"
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on enp3s0, link-type EN10MB (Ethernet), capture size 262144 bytes
os_username=testing&os_password=THISPASSWORDSENTINTHECLEAR&login=Log+in&os_destination=%2Findex.action
In this case I used os_password
because tests showed that’s what it
was. But if you’re not sure, grep out something like this
"POST /|pwd=|passwd=|password=|Host:"
.
Analyzing Bandwidth
Let’s say you want to watch a connection and see what activities cause a big spike in network traffic. Here’s what I used to do that.
# tcpdump -U -s 0 -i eth0 -w - host example.xed.ch | ./bytecounter
The bytecounter program is a simple C program that spits out the current byte count as it is piped in:
#include <stdio.h> int main(int argc, char * argv[]) { int c, n=0; while ((c= getchar()) != EOF) { n++; if (n%100==0) { printf("\r<%d>",n); fflush(stdout); } } }
Simple Text Data
To analyze the communication between bots and the simulation in the Simulated Car Racing competition, I needed to eavesdrop on simple data transmitted locally over UDP. Here’s what worked well:
sudo tcpdump -A -nn -i lo -s 0 udp port 3010 # All traffic
sudo tcpdump -A -nn -i lo -s 0 udp dst port 3010 # Driver Inputs
sudo tcpdump -A -nn -i lo -s 0 udp src port 3010 # Car Feedback
Finding MAC Addresses
This technique is helpful when you’re dealing with devices who only reveal their MAC addresses to the network. An example is a Sony PlayStation3. If you have MAC address filtering on your router, this is how you can find out what that MAC address is.
Another good case for this technique is if you just installed a new cluster and you plugged everything in. You’d like to give the machines a DHCP lease based on MAC address but you don’t know the MAC address. You could power up each machine with a monitor plugged in and write it down as it POSTs. But that’s lame. Better to just power it up fresh and let its natural factory-set desire to get it’s OS with PXE do the work. Basically you’ll want to use another working machine on that network and watch as you power up each node while tcpdump records the nodes' futile attempts to find out who it is.
# tcpdump -tttt -i eth1 port bootps or port bootpc | tee MACs.dump
The -tttt is needed to timestamp packets so you can match it with when you power on the machines. If you power on the machines quicker than its PXE cycle then there will be confusion unless precautions are taken. Turn them on at 15 second intervals using a watch for accuracy and look for that first packet at that interval.
Programming With libpcap
tcpdump is a brilliant program that does everything you could ever want, but still, you might get into a situation where you only need a very specific thing. To write your own special purpose program that can analyze network traffic you should use the same thing tcpdump uses, libpcap.
Here is a nice practical guide to libpcap.
Make sure you have Debian packages libpcap-dev
and/or maybe
libpcap0.8-dev
. Also package pcaputils
will contain pcapdump
.
And make sure you don’t forget to include the gcc -lpcap
option.
Here is a sample program based on the documentation found at http://www.tcpdump.org/pcap.html .
/* Chris X Edwards - 2018-11-18 */ /* Compile: gcc -lpcap -o pcap_sample pcap_sample.c*/ #include <pcap.h> #include <string.h> #include <stdlib.h> #include <ctype.h> #define MAXBYTES2CAPTURE 2048 /* Callback specifying what to do for each packet captured. */ void processPacket(u_char *userarg, const struct pcap_pkthdr* pkthdr, const u_char * packet){ int i= 0, *counter= (int *)userarg; printf("Packet Count: %d\n", ++(*counter)); printf("Received Packet Size: %d\n", pkthdr->len); printf("Payload:\n"); for (i=0;i<pkthdr->len;i++) { if (isprint(packet[i])) /* If it's printable... */ printf("%c",packet[i]); /* ...print it. */ else printf("."); /* Dots if not printable. */ if ( (i%64 == 0 && i !=0) || i == pkthdr->len-1) printf("\n"); } return; } int main(){ int count=0; pcap_t *pkthandle= NULL; char errbuf[PCAP_ERRBUF_SIZE], *device=NULL; memset(errbuf,0,PCAP_ERRBUF_SIZE); struct bpf_program myfilter; char filter_text[]= "host 192.168.1.1"; bpf_u_int32 netmask; /* The netmask of our sniffing device */ /* Get the name of the first device suitable for capture. */ device= pcap_lookupdev(errbuf); printf("Opening device %s\n", device); /* Open device in promiscuous mode. */ pkthandle= pcap_open_live(device, MAXBYTES2CAPTURE, 1, 512, errbuf); /* Warnings and non-sudo errors, etc. */ if (strlen(errbuf)) {printf("%s\n",errbuf);exit(1);} if (pcap_compile(pkthandle, &myfilter, filter_text, 0, netmask) == -1) { fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_text, pcap_geterr(pkthandle)); return(2); } if (pcap_setfilter(pkthandle, &myfilter) == -1) { fprintf(stderr, "Couldn't install filter %s: %s\n", filter_text, pcap_geterr(pkthandle)); return(2); } /* Loop forever (cnt=-1) & call processPacket() for every received packet. */ pcap_loop(pkthandle, -1, processPacket, (u_char *) &count); return 0; }
This program will look for the first sniffable network and then start
looking for packets that pass the filter. The filter is defined in
filter_text
and just needs to match traffic involving the host
192.168.1.1. Once it finds such a packet, it passes it to the
processPacket()
callback where it is printed.
Using Packet Capture Files
You’re playing with some cool expensive toy that spits out network traffic but you can’t hog this device while you spend days debugging your software. Or you’re trying to prepare a response to a network traffic event that happens only very rarely. The trick is to record some of this traffic and later use these recordings offline during testing and development.
The libpcap is really good about making this easy. This worked for me.
#define FROM_PCAP_FILE #ifdef FROM_PCAP_FILE char* filename= "/tmp/pcap/device_in_office_testing.pcap"; pkthandle= pcap_open_offline(filename, errbuf); #else /* Get the name of the first device suitable for capture. */ device= pcap_lookupdev(errbuf); printf("Opening device %s\n", device); /* Open device in promiscuous mode (3rd arg). */ pkthandle= pcap_open_live(device, MAXBYTES2CAPTURE, 1, 512, errbuf); #endif
When you’re ready to try out your code on real live data from the
device you’re working on, just deactivate the #define
.