Designing capture filters for Ethereal/Wireshark requires some basic knowledge of tcpdump syntax.
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.
| 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 |
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 |
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 |
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.
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.
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 |
| 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)