This recipe explains the basic use of Tshark and theoretical concepts of operation and dependence with other tools.
Like any other program written in C, Tshark is susceptible to vulnerabilities. Sending certain type of malformed traffic or opening a malicious pcap file could be enough to get a shell on a vulnerable computer. See, for example, CVE-2011-1591
for Wireshark versions before 1.4.4, which is susceptible to a buffer overflow in the DECT dissector. This vulnerability could be exploited to execute certain payload (for example, a reverse shell) on a computer running Wireshark by sending a single malicious packet.
It is, therefore, highly recommended to run Tshark with the least privileges required for data collection. Thus, if an exploit could run code on our host, it would be limited to the permissions of the user who launched the Tshark process. One possible solution to limit such permissions is to implement filesystem capabilities, available from kernel 2.2. These capabilities allow splitting the actions reserved for root in small privileges, which can be individually enabled or disabled for a certain process. In our case, only two of these capabilities, CAP_NET_RAW
and CAP_NET_ADMIN
, will be necessary to enable data capture. Let's see how to do this. At first we will create a group called tshark
. Then, we will add a normal user to that group (bmerino
), and finally we will add capabilities to Dumpcap so that that group could run Tshark with only the necessary permissions to capture from the network device. Take into account that this differs from setting the UID bit to Dumpcap since in that case it would be run as root:
root@Mordor:~# groupadd tshark root@Mordor:~# usermod -a -G tshark bmerino root@Mordor:~# chgrp tshark /usr/bin/dumpcap root@Mordor:~# chmod 750 /usr/bin/dumpcap root@Mordor:~# setcap cap_net_raw,cap_net_admin=eip /usr/bin/dumpcap root@Mordor:~# getcap /usr/bin/dumpcap /usr/bin/dumpcap = cap_net_admin,cap_net_raw+eip
To verify that we have permission to really capture traffic, we will launch Tshark specifying the listener interface (wlan1
in our case):
root@Mordor:~# su bmerino bmerino@Mordor:/$ tshark -i wlan1 -c 1 -q
This should generate the following output:
Capturing on wlan1 1 packet captured
The easiest way to capture traffic on your local network is to run Tshark without any parameters, in which case it will use the first interface (non-loop) it finds. Tshark, like Wireshark, relies on Dumpcap for data collection. Since Dumpcap only implements basic functionality for packet capture, it is much safer to grant root permissions to this tool instead of Tshark or Wireshark, which present a much more complex logic and therefore are more susceptible to vulnerabilities. Dumpcap, alongside a number of other utilities, is located within the wireshark-common
package, which will be included in the default installation of Tshark.
Look at the following screenshot to see how Tshark creates a child process with Dumpcap for data capture:
The following steps describe how to capture data using Tshark:
To list the network interfaces available on your computer, you can use
–D
, whereas with the-i
parameter you can specify the listening interface in which we want to capture traffic. Tshark will display a default line summary for each packet received.This line corresponds to the same information as shown in the top panel of Wireshark. We can use the
-c
option to tell Tshark the number of packets we want to get:bmerino@Mordor:/$ tshark –D && tshark –i wlan1 –c 2 1. eth0 2. wlan0 3. any (Pseudo-device that captures on all interfaces) 4. lo
You will see the following output:
Capturing on wlan1
The figure that follows shows a generic operation of Tshark and its dependencies with other operating system components for data capture. When a packet arrives at the network card, the MAC destination address is checked to see if it matches yours, in which case an interrupt service routine will be generated and handled by the network driver.
Subsequently, the received data is copied to a memory block defined in the kernel and from there it will be processed by the corresponding protocol stack to be delivered to the appropriate application in user space. Parallel to this process, when Tshark is capturing traffic, the network driver sends a copy of the packets to a kernel subsystem called Packet Filter, which will filter and store in a buffer the desired packets. These packets will be received by Dumpcap (in user space) whose main goal will be to write them into a libpcap
file format to be subsequently read by Tshark. As new packets arrive, Dumpcap will add them to the same capture file and it will notify Tshark about their arrival so that they can be processed.
It is important to understand that when the kernel receives packets it has to copy them from kernel space to user space. Such a context switch involves CPU time, so capturing all the data flow passing through our network card would be a loss of performance for the entire system. Here is where capture filters come into play since they will allow us to discard, from the kernel space, those packets we are not interested in and allow the rest, with the gain in performance that this entails. In this way, we would generate fewer context switches and would eliminate unnecessary processing from the user space.
From Tshark we can define capture filters in a user-friendly way that will be compiled into a language understood by the filtering architecture implemented in the kernel and applied to each packet received by our network card; all in runtime and transparently to the user. All this work is done by libpcap
, which provides support for BPF
or "BSD Packet Filter
", the filter capture system that underlies much of the current operating systems. The syntax for these filters is the same as that used by tcpdump
or any other program that uses libpcap
. To define this kind of filter you should use the –f
parameter. For example, if we are interested in only capturing DNS traffic, we can define a capture filter to get only UDP packets whose port is 53
.
bmerino@Mordor:/$ tshark -f "udp port 53" -i eth0
This should generate the following output:
Capturing on eth0 0.000000 192.168.1.129 -> 87.216.1.65 DNS 82 Standard query 0x7cf4 A www.securityartwork.es
It is important, however, not to confuse these filters with the display or read filters, which represent the cornerstone of Tshark. These filters follow the nomenclature of the application itself and are used to filter packets that have been captured previously. Display filters let you make the most of the potential offered by the dissectors, which are in charge of decoding and interpreting each of the fields of each protocol. Take a look at this nice cheat sheet from PacketLife
to see a summary of the most common display filters at http://packetlife.net/media/library/13/Wireshark_Display_Filters.pdf.
This is what really makes a difference from any other type of protocol analysis tool since these filters allow us to select packets in a more accurate and comfortable way than that provided by the capture filters. To define this type of filter we will use the –R
option. For example if we want to see only CDP packets from the router with a device ID of R1
, we would use the following filter:
bmerino@Mordor:~$ tshark -R "cdp.deviceid == R1" -i eth0
This would generate the following output:
Capturing on eth0 1 0.000000 00:e0:1e:aa:bb:cc -> 01:00:0c:aa:bb:dd CDP 300 Device ID: R1 Port ID: Ethernet0
It is likely that capture filters do not provide us the accuracy needed to capture the packets we are interested in, so sometimes the joint use of both filters (capture and display) will provide us with the perfect combination for our needs. In the following example we will capture the community strings of SNMP requests using both filters. We will use a capture filter to just capture traffic destined to port 162, and a display filter to select precisely the community string of those packets. The -x
option will tell Tshark to dump the content of the packets matched in an ASCII and hexadecimal way. The following screenshot is similar to that shown in the lower window of Wireshark.
Since there are hundreds of protocols available on Tshark, it would be impossible for us to remember each of their fields. So, if you need to create a display filter and you don't remember the fields of certain protocols, you can use the –G
parameter. This option will dump the contents of the registration database of Tshark to stdout
. From this information we can extract each of the fields of the protocol we need. So, for instance, if we want to know the fields available for the EIGRP routing protocol, we could type:
bmerino@Mordor:~$ tshark -G | cut -f3 | grep "^eigrp\."
This would generate the following output:
eigrp.opcode eigrp.as eigrp.tlv