Designing Capture Filters for Ethereal/Wireshark

Mike Horn

Next: Building a basic filter set



This is a primer for designing capture filters for Ethereal/Wireshark. Designing capture filters for Ethereal/Wireshark requires some basic knowledge of tcpdump syntax. The tcpdump man page is your source for complete information regarding syntax and supported primitives. Tcpdump syntax will be the first section covered in this primer. We will use what is covered in this first section to build our basic filter set. Finally, we will enter our filter strings into Ethereal/Wireshark. If you do not want to cover Tcpdump syntax, you might want to skip to the basic filter set. Or, you might just need to know how to enter the filter strings into Ethereal/Wireshark.

 

Designing the Filters Using Tcpdump Syntax

 

Tcpdump provides several primitives for easy filter design. Think of a primitive as a macro or keyword for a predefined filter.

Outline of this section:

The syntax for host filtering:

Syntax

Description

host host

host is either the ip address or host name

src host host

Capture all packets where host is the source

dst host host

Capture all packets where host is the destination

Examples:

host 10.10.10.10

Capture all packets to and from 10.10.10.10

src host 10.10.10.10

Capture all packets where 10.10.10.10 is the source

dst host 10.10.10.10

Capture all packets where 10.10.10.10 is the destination

Port filtering:

Syntax

Description

port port

Capture all packets where port is either the source or destination

src port port

Capture all packets where port is the source port

dst port port

Capture all packets where port is the destination port

Examples:

port 80

Capture all packets where 80 is either the source or destination port

src port 80

Capture all packets where 80 is the source port

dst port 80

Capture all packets where 80 is the destination port

Network filtering:

Syntax

Description

net net

Capture all packets to/from net

src net net

Capture all packets where net is the source

dst net net

Capture all packets where net is the destination

Examples:

net 192.168

Capture all packets where the network is 192.168.0.0

src net 192.168

Capture all packets where the 192.168.0.0 network is the source

dst net 192.168

Capture all packets where the 192.168.0.0 network is the destination

Protocol Based Filters

Ethernet Based:

Syntax

Description

ether proto \[primitive name]

Examples:

ether proto \ip or just ip

Capture all ip packets

ether proto \arp or just arp

Capture all address resolution protocol packets

ether proto \rarp or just rarp

Capture all reverse arp packets

IP Based:

Syntax

Description

ip proto \[primitive name]

Examples:

ip proto \tcp or just tcp

Capture all TCP segments (packets)

ip proto \udp or just udp

Capture all UDP packets

ip proto \icmp or just icmp

Capture all ICMP packets

Combining Primitive Expressions
You can combine primitive expressions using the following:
Negation:! or not
Concatenation:&& or and
Alternation:|| or or

Examples:

host 10.10.10.10 && !net 192.168

Capture all packets to/from 10.10.10.10 that are not to/from 192.168.0.0

host 10.10.10.10 && port 80

Capture all packets to/from 10.10.10.10 and are sourced/destined on 80

 

You can build very sophisticated capture filters by combining primitive expressions.
You can also build filters that will not work. Ethereal/Wireshark will error on some really obvious filter errors.
Consider this filter for example:
host 192.168.1.10 && !host 192.168.1.10   /* Capture all packets to/from 192.168.1.10 and not to/from 192.168.1.10
Ethereal/Wireshark will error on this filter stating that the expression will reject all packets */

However Ethereal/Wireshark will parse this filter even though it will not capture any packets:
host 192.168.1.10 && not net 192.168   /* Capture all packets to/from 192.168.1.10 and not to/from the 192.168 network */
The point being sanity check your filters!

 

Byte Offset Notation:
Filters based on byte offset notation are the most powerful but confusing filters to design. However, once you understand it you will be designing filters to capture ANY kind of packet. Filters based on this notation can capture packets based on any value in any location within the packet. Any of the preceeding filters can be designed with byte offset notation by locating its offset in the appropriate header.

The syntax is: proto [Offset in bytes from the start of the header:Number of bytes to check]

Examples:

ip[8]

Go to byte 8 of the ip header and check one byte (TTL field)

tcp[0:2]

Go to the start of the tcp header and check 2 bytes (source port)

Now that we know how to find a value within a packet, we have to do something with the value like compare it to another value. Tcpdump provides the usual comparison operators (>, <, >=, <=, =, !=).

Examples:

ip[8] = 1

Capture all IP packets where the TTL is 1

tcp[0:2] = 80

Capture all tcp segments (packets) where 80 is the source port.
This is equivalent to the filter: src port 80

 

Tips to help you with byte offset notation:
1.  Remember that the headers start with byte zero.
2.  Always keep a layout of the headers of interest handy when designing filters with byte offset notation (for example: ip,udp,tcp and icmp).
3.  If you don't specify the number of bytes to check, one byte will be checked. You can specify 1,2 or 4 bytes to be checked.
4.  Review the RFCs for IP , TCP , UDP and ICMP

Note: Ethereal/Wireshark defaults to decimal notation. You specify hexadecimal notation by adding 0x to your hex value. There are several times when hex is easier to use (like masking then comparing). As long as you know the offset in the packet and its length, you will be able to design a filter to capture it. I have compiled a table of some common packet offsets with filters.

You can isolate bits within a packet by using bit masking. If you don't understand masking please refer to Masking the Easy Way.

To check the ip header length field:
ip[0] & 0x0f  /* This instructs Ethereal/Wireshark to look at the first byte of the ip header and mask the low order nibble (header length field). */

Let's look at this in detail: The first byte of the ip header contains the ip version in the high-order nibble and the ip header length in the low-order nibble. Because we are bringing in a byte, we need to be able to isolate the nibble of interest.

0100 0101 Value of byte 0 in the packet
0000 1111 Our mask
0000 0101 Result
0101b = 5 This tells us that there are 5 32-bit words in the header.
If we wanted to find a packet that had ip options, we could design a filter like:
ip[0] & 0x0f > 5 /* Capture all packets where the ip header length is greater than 5 */

Why would you want to capture this?
RFC 791 requires support of ip options. However, most garden variety ip packets do not have ip options. If a packet does have options, it is generally considered suspicious.

TCP flags:
Building filters based on tcp flag values can alert you to all sorts of bad or odd traffic. Certain combinations of flags are known to crash some systems. Some recon probes employ illegal/unconventional flag combinations to assist in tcp stack fingerprinting.

The base filter for TCP flags is tcp[13].
The flags (from MSB to LSB) are:
Reserved Reserved Urgent Ack Push Reset Syn Fin
A normal syn packet would have a value of 0000 0010b or 0x02.
If you just wanted to capture only syn packets the filter would be:
tcp[13] = 2   /* Capture packets where only the syn bit is set */
A filter for all syn packets would then be:
tcp[13] & 0x02 = 2   /* This will capture all packets where the syn bit is set. This includes syn, syn-ack, etc. As long as a syn bit is set, this filter will capture it. */

Payload matching filters:
This section covers filters designed to match tcp payload. Be careful as libpcap can not guarantee that you are offsetting into the payload of the segment. If tcp options are present in the segment, the offset into the payload will also be off. One thing you can do is add an expression like "or tcp[12] & 0xf0 > 0x50" to the filter. This will bring in tcp segments that have options. It is a trade-off but you will still not have to go through as many packets. The SMTP filter from the basic filter set page looks for commands and response codes. This filter is designed to look at the standard offset into the tcp header (tcp[20]) and match the payload with your filter string. You will need to know the hex equivalent of the ascii characters.
Example:
Command:
HELO

Char/String

Hex

H

0x48

E

0x45

L

0x4C

O

0x4F

HELO

0x48454C4F

MAIL

Char/String

Hex

M

0x4D

A

0x41

I

0x49

L

0x4C

MAIL

0x4D41494C

The rest of the SMTP commands to be converted are:
RCPT = 0x52435054
DATA = 0x44415441
RSET = 0x52534554
SEND = 0x53454E44
SOML = 0x534F4D4C
SAML = 0x53414D4C
VRFY = 0x56524659
EXPN = 0x4558504E
NOOP = 0x4E4F4F50
QUIT = 0x51554954
TURN = 0x5455524E

Putting all of this together (including packets with tcp options) in a filter string:
port 25 and (tcp[12] & 0xf0>0x50 or tcp[20:4] = 0x48454C4F or tcp[20:4] = 0x4D41494C or tcp[20:4] = 0x52435054 or tcp[20:4] = 0x44415441 or tcp[20:4] = 0x52534554 or tcp[20:4] = 0x53454E44 or tcp[20:4] = 0x534F4D4C or tcp[20:4] = 0x53414D4C or tcp[20:4] = 0x56524659 or tcp[20:4] = 0x4558504E or tcp[20:4] = 0x4E4F4F50 or tcp[20:4] = 0x51554954 or tcp [20:4] = 0x5455524E)

Now the reply/response codes:

221 0x32323120
214 0x32313420
220 0x32323020
221 0x32323420
250 0x32353020
251 0x32353120
354 0x33353420
421 0x34323120
450 0x34353020
451 0x34353120
452 0x34353220
500 0x35303020
501 0x35303120
502 0x35303220
503 0x35303320
504 0x35303420
550 0x35353020
551 0x35353120
552 0x35353220
553 0x35353320
554 0x35353420

SMTP reply filter string (with tcp options):
port 25 and (tcp[12] & 0xf0> 0x50 or tcp[20:4] = 0x32323120 or tcp[20:4] = 0x32323420 or tcp[20:4] = 0x32353020 or tcp[20:4] = 0x32353120 or tcp[20:4] = 0x33353420 or tcp[20:4] = 0x34323120 or tcp[20:4] = 0x34353020 or tcp[20:4] = 0x34353120 or tcp[20:4] = 0x34353220 or tcp[20:4] = 0x35303020 or tcp[20:4] = 0x35303120 or tcp[20:4] = 0x35303220 or tcp[20:4] = 0x35303320 or tcp[20:4] = 0x35303420 or tcp[20:4] = 0x35353020 or tcp[20:4] = 0x35353120 or tcp[20:4] = 0x35353220 or tcp[20:4] = 0x35353320 or tcp[20:4] = 0x35353420)

By combining the two filter strings above, you will be able to capture SMTP conversations without pulling in the message data. You may also want to capture connection initiation and tear down. This is easy enough by adding an expression for tcp flags to the above strings.
tcp[13] & 0x02 = 0x02 any with the syn flag set
tcp[13] & 0x01 = 0x01 any with the fin flag set
tcp[13] & 0x04 = 0x04 any with the reset flag set
A more efficient alternative to the three flag filters above is to mask-in the three least significant bits and pull in anything not equal to 0.
This is expressed as:
(tcp[13] & 0x07 != 0)

NOTE: Tcpdump does have tcp flag primitives for all but reserved flag bits. I prefer to use the strings above but you could have written the above flag filters using the flag primitives.

Putting all of this together to form a big filter string:
port 25 and (tcp[12] & 0xf0>0x50 or tcp[13] & 0x07 != 0 or tcp[20:4] = 0x48454C4F or tcp[20:4] = 0x4D41494C or tcp[20:4] = 0x52435054 or tcp[20:4] = 0x44415441 or tcp[20:4] = 0x52534554 or tcp[20:4] = 0x53454E44 or tcp[20:4] = 0x534F4D4C or tcp[20:4] = 0x53414D4C or tcp[20:4] = 0x56524659 or tcp[20:4] = 0x4558504E or tcp[20:4] = 0x4E4F4F50 or tcp[20:4] = 0x51554954 or tcp [20:4] = 0x5455524E or tcp[20:4] = 0x32323120 or tcp[20:4] = 0x32323420 or tcp[20:4] = 0x32353020 or tcp[20:4] = 0x32353120 or tcp[20:4] = 0x33353420 or tcp[20:4] = 0x34323120 or tcp[20:4] = 0x34353020 or tcp[20:4] = 0x34353120 or tcp[20:4] = 0x34353220 or tcp[20:4] = 0x35303020 or tcp[20:4] = 0x35303120 or tcp[20:4] = 0x35303220 or tcp[20:4] = 0x35303320 or tcp[20:4] = 0x35303420 or tcp[20:4] = 0x35353020 or tcp[20:4] = 0x35353120 or tcp[20:4] = 0x35353220 or tcp[20:4] = 0x35353320 or tcp[20:4] = 0x35353420)

Building a Basic Filter Set

This section will assist you with building your basic filter set.
The basic filter set should include filters to capture packets on well known service ports.
The table below should get you started.

Filter Name

Filter String

 

 

HTTP_80

port 80

DNS_53

port 53

SMTP_25

port 25

FTP_CMD_21

port 21

TELNET_23

port 23

POP3_110

port 110

SNMP_161_162

port 161 or port 162

IMAP_143

port 143

NNTP_119

port 119

LDAP_389

port 389

NCP_524

port 524

Netbios_SMB_137_138_139

port 137 or port 138 or port 139

 

 

Host based filtering

host Enter the ip address or hostname after host

Port based filtering

port Enter the port number after port

IP Fragmentation

ip[6:2] & 0x2000 = 0x2000 or ip[6:2] & 0x1fff !=0x0000

 

 

IP_All

ip

TCP_All

tcp

UDP_All

udp

ARP_Ether

arp

 

 

ICMP_ALL

icmp

ICMP_ping

icmp[0]= 0 or icmp[0]= 8

ICMP_noPing

icmp[0]!= 0 and icmp[0]!= 8

 

 

IGMP

ip[9] = 2

EGP

ip[9] = 8

Multicast

net 224.0.0

Multicast (another variation)

ip multicast

Multicast

ether multicast

 

 

You can use the common packet offsets table as a shortcut to help build other filters.


Advanced Filters:
SMTP

SMTP Commands - HELO, MAIL,RCPT,DATA,RSET,SEND,SOML,SAML,VRFY,EXPN,NOOP,QUIT AND TURN:
port 25 and (tcp[12] & 0xf0 > 0x50 or tcp[20:4] = 0x48454C4F or tcp[20:4] = 0x4D41494C or tcp[20:4] = 0x52435054 or tcp[20:4] = 0x44415441 or tcp[20:4] = 0x52534554 or tcp[20:4] = 0x53454E44 or tcp[20:4] = 0x534F4D4C or tcp[20:4] = 0x53414D4C or tcp[20:4] = 0x56524659 or tcp[20:4] = 0x4558504E or tcp[20:4] = 0x4E4F4F50 or tcp[20:4] = 0x51554954 or tcp [20:4] = 0x5455524E)

SMTP Reply/response codes - 221,214,220,221,250,251,354,421,450,451,452,500,501,502,503,504,550,551,552,553 and 554:
port 25 and (tcp[12] & 0xf0 > 0x50 or tcp[20:4] = 0x32323120 or tcp[20:4] = 0x32323420 or tcp[20:4] = 0x32353020 or tcp[20:4] = 0x32353120 or tcp[20:4] = 0x33353420 or tcp[20:4] = 0x34323120 or tcp[20:4] = 0x34353020 or tcp[20:4] = 0x34353120 or tcp[20:4] = 0x34353220 or tcp[20:4] = 0x35303020 or tcp[20:4] = 0x35303120 or tcp[20:4] = 0x35303220 or tcp[20:4] = 0x35303320 or tcp[20:4] = 0x35303420 or tcp[20:4] = 0x35353020 or tcp[20:4] = 0x35353120 or tcp[20:4] = 0x35353220 or tcp[20:4] = 0x35353320 or tcp[20:4] = 0x35353420)

SMTP Commands and reply (combination of the two above with tcp options, syn, fin, or reset flag set)
port 25 and (tcp[12] & 0xf0 > 0x50 or tcp[13] & 0x07 != 0 or tcp[20:4] = 0x48454C4F or tcp[20:4] = 0x4D41494C or tcp[20:4] = 0x52435054 or tcp[20:4] = 0x44415441 or tcp[20:4] = 0x52534554 or tcp[20:4] = 0x53454E44 or tcp[20:4] = 0x534F4D4C or tcp[20:4] = 0x53414D4C or tcp[20:4] = 0x56524659 or tcp[20:4] = 0x4558504E or tcp[20:4] = 0x4E4F4F50 or tcp[20:4] = 0x51554954 or tcp [20:4] = 0x5455524E or tcp[20:4] = 0x32323120 or tcp[20:4] = 0x32323420 or tcp[20:4] = 0x32353020 or tcp[20:4] = 0x32353120 or tcp[20:4] = 0x33353420 or tcp[20:4] = 0x34323120 or tcp[20:4] = 0x34353020 or tcp[20:4] = 0x34353120 or tcp[20:4] = 0x34353220 or tcp[20:4] = 0x35303020 or tcp[20:4] = 0x35303120 or tcp[20:4] = 0x35303220 or tcp[20:4] = 0x35303320 or tcp[20:4] = 0x35303420 or tcp[20:4] = 0x35353020 or tcp[20:4] = 0x35353120 or tcp[20:4] = 0x35353220 or tcp[20:4] = 0x35353320 or tcp[20:4] = 0x35353420)
NOTE: These SMTP filters will also capture any packets to/from port 25 with tcp options.
If you want to see how to build these filters, please refer to payload filtering.