tcpdump高级过滤表达式

来源:互联网 发布:centos打开端口命令 编辑:程序博客网 时间:2024/05/16 11:19

 

http://www.wains.be/pub/networking/tcpdump_advanced_filters.txt

 

tcpdump advanced filters
========================

Sebastien Wains <sebastien -the at sign- wains -dot- be>
http://www.wains.be

$Id: tcpdump_advanced_filters.txt 34 2010-08-21 13:50:49Z sw $


Notes :

I usually always specify the interface from which to listen.. that's the -i option you will always see in the examples.
Indeed, I have tested each rule on my laptop over the wireless adapter which is eth1.

Feel free to contact me for comments, suggestions or for reporting mistakes.
I know I'm usually terrible at explaining stuff, so let me know if something is not clear.

I'll try to keep this document updated with new useful rules.


Before I begin with advanced filters, let's review the basic syntax of tcpdump

Basic syntax :
==============

Filtering hosts :
-----------------

- Match any traffic involving 192.168.1.1 as destination or source
# tcpdump -i eth1 host 192.168.1.1
不区分源地址和目的地址,过滤IP
- As soure only
# tcpdump -i eth1 src host 192.168.1.1
过滤源地址
- As destination only
# tcpdump -i eth1 dst host 192.168.1.1
过滤目的地址

Filtering ports :
-----------------

- Match any traffic involving port 25 as source or destination
# tcpdump -i eth1 port 25
不区分源端口和目的端口,过滤端口
- Source
# tcpdump -i eth1 src port 25
过滤源端口
- Destination
# tcpdump -i eth1 dst port 25
过滤目的端口

Network filtering :
-------------------
过滤网络
# tcpdump -i eth1 net 192.168 
# tcpdump -i eth1 src net 192.168
# tcpdump -i eth1 dst net 192.168


Protocol filtering :
--------------------
过滤协议
# tcpdump -i eth1 arp
# tcpdump -i eth1 ip

# tcpdump -i eth1 tcp
# tcpdump -i eth1 udp
# tcpdump -i eth1 icmp


Let's combine expressions :
---------------------------

Negation    : ! or "not" (without the quotes)
Concatanate : && or "and"
Alternate   : || or "or"

- This rule will match any TCP traffic on port 80 (web) with 192.168.1.254 or 192.168.1.200 as destination host
# tcpdump -i eth1 '((tcp) and (port 80) and ((dst host 192.168.1.254) or (dst host 192.168.1.200)))'
过滤80端口的TCP协议,目的地址是254或200
- Will match any ICMP traffic involving the destination with physical/MAC address 00:01:02:03:04:05
# tcpdump -i eth1 '((icmp) and ((ether dst host 00:01:02:03:04:05)))'
过滤icmp协议,并且MAC地址为00:01:02:03:04:05
- Will match any traffic for the destination network 192.168 except destination host 192.168.1.200
# tcpdump -i eth1 '((tcp) and ((dst net 192.168) and (not dst host 192.168.1.200)))'
过滤协议为TCP,目的网络为192.168的数据,这之中除去192.168.1.200的主机的数据

Advanced header filtering :
===========================

Before we continue, we need to know how to filter out info from headers

proto[x:y] : will start filtering from byte x for y bytes. ip[2:2] would filter bytes 3 and 4 (first byte begins by 0)
proto[x:y] & z = 0 : will match bits set to 0 when applying mask z to proto[x:y]
proto[x:y] & z !=0 : some bits are set when applying mask z to proto[x:y]
proto[x:y] & z = z : every bits are set to z when applying mask z to proto[x:y]
proto[x:y] = z : p[x:y] has exactly the bits set to z


Operators : >, <, >=, <=, =, !=
高级包头过滤
============
首先了解如何从包头过滤信息
proto[x:y] : 过滤从x 字节开始的y 字节数。比如ip[2:2]过滤出3、4 字节(第一
字节从0 开始排)
proto[x:y] & z = 0 : proto[x:y]和z 的与操作为0
proto[x:y] & z !=0 : proto[x:y]和z 的与操作不为0
proto[x:y] & z = z : proto[x:y]和z 的与操作为z
proto[x:y] = z : proto[x:y]等于z
操作符: >, <, >=, <=, =, !=
IP 头
This may not be clear in the first place but you'll find examples below involving these.


Of course, it is important to know what the protocol headers look like before diving into more advanced filters.


IP header
---------

0                   1                   2                   3  
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version|  IHL  |Type of Service|          Total Length         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|         Identification        |Flags|      Fragment Offset    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Time to Live |    Protocol   |         Header Checksum       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                       Source Address                          |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Destination Address                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Options                    |    Padding    | <-- optional
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                            DATA ...                           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+



I'll consider we are only working with the IPv4 protocol suite for these examples.

In an ideal world, every field would fit inside one byte. This is not the case, of course.

Are IP options set ?
--------------------

Let's say we want to know if the IP header has options set. We can't just try to filter out the 21st byte
because if no options are set, data start at the 21st byte. We know a "normal" header is usually 20 bytes
(160 bits) long. With options set, the header is longer than that. The IP header has the header
length field which we will filter here to know if the header is longer than 20 bytes.

+-+-+-+-+-+-+-+-+
|Version|  IHL  |
+-+-+-+-+-+-+-+-+

Usually the first byte has a value of 01000101 in binary.
通常第一个字节的二进制为01000101
Anyhow, we need to divide the first byte in half...
先把第一个字节分成二半
0100 = 4 in decimal. This is the IP version.代表IP的版本
0101 = 5 in decimal. This is the number of blocks of 32 bits in the headers. 5 x 32 bits = 160 bits or 20 bytes.报头长度,160个小b(bit)或是20个大B(字节)

The second half of the first byte would be bigger than 5 if the header had IP options set.
如果报头有IP选项设置,IHL将比5大
We have two ways of dealing with that kind of filters.
我们有两种方式处理过滤器
1. Either try to match a value bigger than 01000101. This would trigger matches for IPv4 traffic with IP options set,
   but ALSO any IPv6 traffic !
当是IPV6的情况时,版本信息肯定是超过01000101,如果是带有IP选项设置的IPV4也有可能在版本信息中超过01000101
In decimal 01000101 equals 69.
01000101十进制为69
Let's recap how to calculate in decimal.
让我们来复习下在十进制中如何计算
0 : 0 \
1 : 2^6 = 64 \ First field (IP version)
0 : 0 /
0 : 0 /
-
0 : 0 \
1 : 2^2 = 4 \ Second field (Header length)
0 : 0 /
1 : 2^0 = 1 /

64 + 4 + 1 = 69

The first field in the IP header would usually have a decimal value of 69.
If we had IP options set, we would probably have 01000110 (IPv4 = 4 + header = 6), which in decimal equals 70.
如果进行IP选项设置,二进制有可能是01000110,十进制为70
This rule should do the job :这个规则应该这样设置
# tcpdump -i eth1 'ip[0] > 69'

Somehow, the proper way is to mask the first half/field of the first byte, because as mentionned earlier,
this filter would match any IPv6 traffic.
不管怎么样,这个方法来过滤第一字节的一半/全部,正像以前提到的那样,肯定可以适用于匹配IPV6的情况
2. The proper way : masking the first half of the byte
适合的方法:过滤一个字节的前面一半
0100 0101 : 1st byte originally 第一字节原来的样子
0000 1111 : mask (0x0f in hex or 15 in decimal). 0 will mask the values while 1 will keep the values intact.   0用过滤,1用来保留
=========
0000 0101 : final result   与操作以后的结果

The correct filter :正确的过滤表达式

# tcpdump -i eth1 'ip[0] & 15 > 5'

or

# tcpdump -i eth1 'ip[0] & 0x0f > 5'


DF bit (don't fragment) set ?
-----------------------------

DF:Don't Fragment
IP协议的首部“标志”中标志(flag) 占 3 位,目前只有前两位有意义。标志字段的最低位是 MF (More Fragment)。MF =1 表示后面“还有分片”。MF  0 表示最后一个分片。标志字段中间的一位是 DF (Don't Fragment) 只有当 DF =0 时才允许分片。

Let's now trying to know if we have fragmentation occuring, which is not desirable. Fragmentation occurs
when a the MTU of the sender is bigger than the path MTU on the path to destination.
现在看下如何让我们知道是否有分片发生,当发送设备的MTU大于沿途设备的MTU时,就要分片
Fragmentation info can be found in the 7th and 8th byte of the IP header.
分片标志可以在IP头的第七和第八字节找到
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Flags|      Fragment Offset    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
标志    IP数据分割偏移
Bit 0: reserved, must be zero  保留,置0
Bit 1: (DF) 0 = May Fragment, 1 = Don't Fragment.      0为可片,1为不可片
Bit 2: (MF) 0 = Last Fragment, 1 = More Fragments.   0为最后一片,1为后面还有

The fragment offset field is only used when fragmentation occurs.
只有需要分片时分片标志才会设置
If we want to match the DF bit (don't fragment bit, to avoid IP fragmentation) :
如果我们想匹配DF位(避免IP分片)
The 7th byte would have a value of :
01000000 or 64 in decimal
二进制01000000或十进制64
# tcpdump -i eth1 'ip[6] = 64'
过滤DF位为1的IP包

Matching fragmentation ?
------------------------
匹配分片
- Matching MF (more fragment set) ? This would match the fragmented datagrams but wouldn't match the last

  fragment (which has the 2nd bit set to 0).

匹配MF标志(还有后续分片设置)?这个设置是用来匹配不是最后一个分片的数据报

# tcpdump -i eth1 'ip[6] = 32'
过滤匹配MF标志的IP包,用以过滤第一个分片
The last fragment have the first 3 bits set to 0... but has data in the fragment offset field.
最后一个分片中,第六个字节的第3比特位设置为0,除非有分片偏移字段的数据(不是很明白)
- Matching the fragments and the last fragments

匹配分片和最后一片

# tcpdump -i eth1 '((ip[6:2] > 0) and (not ip[6] = 64))'

从第6个字节开始往后数2个字节大于0,并且第6个字节的十进制不等于64,这意味不是最后一个分片
A bit of explanations :一个比特位的解解释
"ip[6:2] > 0" would return anything with a value of at least 1 希望返回值至少是个1
We don't want datagrams with the DF bit set though.. the reason of the "not ip[6] = 64" 我们不希望要DF位设置的数据包

If you want to test fragmentation use something like :如果你想测试下分片
ping -M want -s 3000 192.168.1.1


Matching datagrams with low TTL 匹配低TTL
-------------------------------

The TTL field is located in the 9th byte and fits perfectly into 1 byte.   TTL字段在第9个字节,均是1
The maximum decimal value of the TTL field is thus 255 (11111111 in binary). 最大值为255

This can be verified :
$ ping -M want -s 3000 -t 256 192.168.1.200
ping: ttl 256 out of range

+-+-+-+-+-+-+-+-+
|  Time to Live |
+-+-+-+-+-+-+-+-+

We can try to find if someone on our network is using traceroute by using something like this on the gateway :

在网关上,我们可以发现是否有人用traceroute这种类似的命令进行测试,设置一个比较小的TTL值进行发包

# tcpdump -i eth1 'ip[8] < 5'


Matching packets longer than X bytes
------------------------------------
匹配大于某个长度字节的IP包
Where X is 600 bytes
比如是600个字节
# tcpdump -i eth1 'ip[2:2] > 600'
第三、第四个字节大于600

More IP filtering
-----------------
更多的IP过滤
We could imagine filtering source and destination addresses directly in decimal addressing.
We could also match the protocol by filtering the 10th byte.

我们可以想像用十进制源和目的地址来进行过滤

我们也可以通过匹配第十个字节来过滤指定协议

It would be pointless anyhow, because tcpdump makes it already easy to filter out that kind of info.
TCPDUMP可以简单完成这个匹配协议的工作

TCP header
----------

0                   1                   2                   3  
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          Source Port          |       Destination Port        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                        Sequence Number                        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Acknowledgment Number                      |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|  Data |       |C|E|U|A|P|R|S|F|                               |
| Offset|  Res. |W|C|R|C|S|S|Y|I|            Window             |
|       |       |R|E|G|K|H|T|N|N|                               |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           Checksum            |         Urgent Pointer        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                    Options                    |    Padding    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                             data                              |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+



- Matching any TCP traffic with a source port > 1024   过滤TCP协议源端口超过1024的数据
# tcpdump -i eth1 'tcp[0:2] > 1024'

- Matching TCP traffic with particular flag combinations
匹配TCP特定标志组合
The flags are defined in the 14th byte of the TCP header.
这些标志在TCP头的第十四个字节
+-+-+-+-+-+-+-+-+
|C|E|U|A|P|R|S|F|
|W|C|R|C|S|S|Y|I|
|R|E|G|K|H|T|N|N|
+-+-+-+-+-+-+-+-+

In the TCP 3-way handshakes, the exchange between hosts goes like this :
TCP的三次握手过程
1. Source sends SYN 发起方发SYN
2. Destination answers with SYN, ACK  目的方回答SYN+ACK
3. Source sends ACK 发起方发ACK

- If we want to match packets with only the SYN flag set, the 14th byte would have a binary

  value of 00000010 which equals 2 in decimal.

当我们只想过滤仅有SYN标志的包时,第14个字节的二进制是00000010,十进制是2

# tcpdump -i eth1 'tcp[13] = 2'

- Matching SYN, ACK (00010010 or 18 in decimal)匹配SYN+ACK包时(二进制是00010010或是十进制18)
# tcpdump -i eth1 'tcp[13] = 18'

- Matching either SYN only or SYN-ACK datagrams匹配SYN或是SYN+ACK的数据时
# tcpdump -i eth1 'tcp[13] & 2 = 2'

We used a mask here. It will returns anything with the ACK bit set (thus the SYN-ACK combination as well)
我们这种与的方式,也可用在过滤ACK或SYN+ACK中
Let's assume the following examples (SYN-ACK)
假设要过滤SYN-ACK
00010010 : SYN-ACK packet
00000010 : mask (2 in decimal)
--------
00000010 : result (2 in decimal)

Every bits of the mask match !
这个去运算应该是用过滤包含SYN标志的数据报
- Matching PSH-ACK packets
# tcpdump -i eth1 'tcp[13] = 24'
过滤PSH+ACK标志
- Matching any combination containing FIN (FIN usually always comes with an ACK so we either
  need to use a mask or match the combination ACK-FIN)
# tcpdump -i eth1 'tcp[13] & 1 = 1'

- Matching RST flag
# tcpdump -i eth1 'tcp[13] & 4 = 4'


By looking at the TCP state machine diagram (http://www.wains.be/pub/networking/tcp_state_machine.jpg)
we can find the different flag combinations we may want to analyze.
我们可以分析不同的标组合
Ideally, a socket in ACK_WAIT mode should not have to send a RST. It means the 3 way handshake has not completed.
We may want to analyze that kind of traffic.
一般情况,一个sokcet在ACK_WAIT模式下不应该发送RST标志,这意味着三次握手没有完成,我们可以分析这个类型的流程

Matching SMTP data :
--------------------

I will make a filter that will match any packet containing the "MAIL" command from SMTP exchanges.

I use something like http://www.easycalculation.com/ascii-hex.php to convert values from ASCII to hexadecimal.

"MAIL" in hex is 0x4d41494c
M=4d    A=41   I=49   L=4c
The rule would be :

# tcpdump -i eth1 '((port 25) and (tcp[20:4] = 0x4d41494c))'

It will check the bytes 21 to 24. "MAIL" is 4 bytes/32 bits long..
检查21到24字节,"MAIL"是4个字节,32个比特
This rule would not match packets with IP options set.
这个规则不用匹配IP选项设置
This is an example of packet (a spam, of course) :
一个例子,是个垃圾邮件
# tshark -V -i eth0 '((port 25) and (tcp[20:4] = 0x4d41494c))'
Capturing on eth0
Frame 1 (92 bytes on wire, 92 bytes captured)
    Arrival Time: Sep 25, 2007 00:06:10.875424000
    [Time delta from previous packet: 0.000000000 seconds]
    [Time since reference or first frame: 0.000000000 seconds]
    Frame Number: 1
    Packet Length: 92 bytes
    Capture Length: 92 bytes
    [Frame is marked: False]
    [Protocols in frame: eth:ip:tcp:smtp]
Ethernet II, Src: Cisco_X (00:11:5c:X), Dst: 3Com_X (00:04:75:X)
    Destination: 3Com_X (00:04:75:X)
        Address: 3Com_X (00:04:75:X)
        .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
        .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
    Source: Cisco_X (00:11:5c:X)
        Address: Cisco_X (00:11:5c:X)
        .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
        .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
    Type: IP (0x0800)
Internet Protocol, Src: 62.163.X (62.163.X), Dst: 192.168.X (192.168.X)
    Version: 4
    Header length: 20 bytes
    Differentiated Services Field: 0x00 (DSCP 0x00: Default; ECN: 0x00)
        0000 00.. = Differentiated Services Codepoint: Default (0x00)
        .... ..0. = ECN-Capable Transport (ECT): 0
        .... ...0 = ECN-CE: 0
    Total Length: 78
    Identification: 0x4078 (16504)
    Flags: 0x04 (Don't Fragment)
        0... = Reserved bit: Not set
        .1.. = Don't fragment: Set
        ..0. = More fragments: Not set
    Fragment offset: 0
    Time to live: 118
    Protocol: TCP (0x06)
    Header checksum: 0x08cb [correct]
        [Good: True]
        [Bad : False]
    Source: 62.163.X (62.163.X)
    Destination: 192.168.X (192.168.XX)
Transmission Control Protocol, Src Port: 4760 (4760), Dst Port: smtp (25), Seq: 0, Ack: 0, Len: 38
    Source port: 4760 (4760)
    Destination port: smtp (25)
    Sequence number: 0    (relative sequence number)
    [Next sequence number: 38    (relative sequence number)]
    Acknowledgement number: 0    (relative ack number)
    Header length: 20 bytes
    Flags: 0x18 (PSH, ACK)
        0... .... = Congestion Window Reduced (CWR): Not set
        .0.. .... = ECN-Echo: Not set
        ..0. .... = Urgent: Not set
        ...1 .... = Acknowledgment: Set
        .... 1... = Push: Set
        .... .0.. = Reset: Not set
        .... ..0. = Syn: Not set
        .... ...0 = Fin: Not set
    Window size: 17375
    Checksum: 0x6320 [correct]
        [Good Checksum: True]
        [Bad Checksum: False]
Simple Mail Transfer Protocol
    Command: MAIL FROM:<wguthrie_at_mysickworld--dot--com>\r\n
        Command: MAIL
        Request parameter: FROM:<wguthrie_at_mysickworld--dot--com>


Matching HTTP data :
--------------------

Let's make a filter that will find any packets containing GET requests让我们来设一过滤规则来发现含GET请包的数据
The HTTP request will begin by :
HTTP请求是这样开始的
GET / HTTP/1.1\r\n (16 bytes counting the carriage return but not the backslashes !)
16字节算回车不算反斜杠

If no IP options are set.. the GET command will use the byte 20, 21 and 22

如查没有IP选项设置,GET命令将用到20、21和22三个字节

Usually, options will take 12 bytes (12nd byte indicates the header length, which should report 32 bytes).
So we should match bytes 32, 33 and 34 (1st byte = byte 0).
通常,选项将占12个字节(第12个字节指头长度,which should report 32 bytes)
Tcpdump is only able to match data size of either 1, 2 or 4 bytes, we will take the following ASCII
character following the GET command (a space)
TCPDUMP仅仅能够匹配1个、2个或4个字节,所以是GET+空格
"GET " in hex : 47455420

# tcpdump -i eth1 'tcp[32:4] = 0x47455420'


Matching other interesting TCP things :
---------------------------------------

SSH connection (on any port) :
We will be looking for the reply given by the SSH server.
OpenSSH usually replies with something like "SSH-2.0-OpenSSH_3.6.1p2".
The first 4 bytes (SSH-) have an hex value of 0x5353482D.

# tcpdump -i eth1 'tcp[(tcp[12]>>2):4] = 0x5353482D'

If we want to find any connection made to older version of OpenSSH (version 1, which are insecure and subject to MITM attacks) :
The reply from the server would be something like "SSH-1.99.."

# tcpdump -i eth1 '(tcp[(tcp[12]>>2):4] = 0x5353482D) and (tcp[((tcp[12]>>2)+4):2] = 0x312E)'



UDP header
----------

  0      7 8     15 16    23 24    31 
+--------+--------+--------+--------+
|     Source      |   Destination   |
|      Port       |      Port       |
+--------+--------+--------+--------+
|                 |                 |
|     Length      |    Checksum     |
+--------+--------+--------+--------+
|                                   |
|              DATA ...             |
+-----------------------------------+                

Nothing really interesting here.

If we want to filter ports we would use something like :
# tcpdump -i eth1 udp dst port 53


ICMP header
-----------

See different ICMP messages :
http://img292.imageshack.us/my.php?image=icmpmm6.gif

We will usually filter the type (1 byte) and code (1 byte) of the ICMP messages.

Here are common ICMP types :

  0 Echo Reply [RFC792]
  3 Destination Unreachable [RFC792]
  4 Source Quench [RFC792]
  5 Redirect [RFC792]
  8 Echo [RFC792]
11 Time Exceeded [RFC792]

We may want to filter ICMP messages type 4, these kind of messages are sent in case of congestion of the network.
# tcpdump -i eth1 'icmp[0] = 4'


If we want to find the ICMP echo replies only, having an ID of 500. By looking at the image with all the ICMP packet description
we see the ICMP echo reply have the ID spread across the 5th and 6th byte. For some reason, we have to filter out with the value in hex.

# tcpdump -i eth0 '(icmp[0] = 0) and (icmp[4:2] = 0x1f4)'

tcpdump 高级过滤技巧
===================
Sebastien Wains <sebastien -the at sign- wains -dot- be>
http://www.wains.be
$Id: tcpdump_advanced_filters.txt 33 2008-05-07 17:40:11Z sw $
http://www.wains.be/pub/networking/tcpdump_advanced_filters.txt
注意:
例子中都用-i 参数指定了抓取的网卡为eth1,实际使用时请自行变化。
翻译此文的目的是加深记忆,可能理解有偏差,建议看原文或man 手册。
注:由于大部分是翻译的,所以只是高级技巧,并非权威指南!
基本语法
========
过滤主机
--------
- 抓取所有经过eth1,目的或源地址是192.168.1.1 的网络数据
# tcpdump -i eth1 host 192.168.1.1
- 源地址
# tcpdump -i eth1 src host 192.168.1.1
- 目的地址
# tcpdump -i eth1 dst host 192.168.1.1
过滤端口
--------
- 抓取所有经过eth1,目的或源端口是25 的网络数据
# tcpdump -i eth1 port 25
- 源端口
# tcpdump -i eth1 src port 25
- 目的端口
# tcpdump -i eth1 dst port 25
网络过滤
--------
# tcpdump -i eth1 net 192.168
# tcpdump -i eth1 src net 192.168
# tcpdump -i eth1 dst net 192.168
协议过滤
--------
# tcpdump -i eth1 arp
# tcpdump -i eth1 ip
# tcpdump -i eth1 tcp
# tcpdump -i eth1 udp
# tcpdump -i eth1 icmp
常用表达式
----------
非: ! or "not" (去掉双引号)
且: && or "and"
或: || or "or"
- 抓取所有经过eth1,目的地址是192.168.1.254 或192.168.1.200 端口是80 的TCP 数据
# tcpdump -i eth1 '((tcp) and (port 80) and ((dst host 192.168.1.254) or (dst host
192.168.1.200)))'
- 抓取所有经过eth1,目标MAC 地址是00:01:02:03:04:05 的ICMP 数据
# tcpdump -i eth1 '((icmp) and ((ether dst host 00:01:02:03:04:05)))'
- 抓取所有经过eth1,目的网络是192.168,但目的主机不是192.168.1.200 的TCP 数据
# tcpdump -i eth1 '((tcp) and ((dst net 192.168) and (not dst host 192.168.1.200)))'
高级包头过滤
============
首先了解如何从包头过滤信息
proto[x:y] : 过滤从x 字节开始的y 字节数。比如ip[2:2]过滤出3、4 字节(第一
字节从0 开始排)
proto[x:y] & z = 0 : proto[x:y]和z 的与操作为0
proto[x:y] & z !=0 : proto[x:y]和z 的与操作不为0
proto[x:y] & z = z : proto[x:y]和z 的与操作为z
proto[x:y] = z : proto[x:y]等于z
操作符: >, <, >=, <=, =, !=
IP 头
----
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version| IHL |Type of Service| Total Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identification |Flags| Fragment Offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Time to Live | Protocol | Header Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Destination Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding | <-- optional
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| DATA ... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
本文只针对IPv4。
IP 选项设置了吗?
----------------
“一般”的IP 头是20 字节,但IP 头有选项设置,不能直接从偏移21 字节处读取数据。IP

有个长度字段可以知道头长度是否大于20 字节。
+-+-+-+-+-+-+-+-+
|Version| IHL |
+-+-+-+-+-+-+-+-+
通常第一个字节的二进制值是:01000101,分成两个部分:
0100 = 4 表示IP 版本
0101 = 5 表示IP 头32 bit 的块数,5 x 32 bits = 160 bits or 20 bytes
如果第一字节第二部分的值大于5,那么表示头有IP 选项。
下面介绍两种过滤方法(第一种方法比较操蛋,可忽略):
1. 比较第一字节的值是否大于01000101,这可以判断IPv4 带IP 选项的数据和IPv6 的数
据。
01000101 十进制等于69,计算方法如下(小提示:用计算器更方便)
0 : 0 \
1 : 2^6 = 64 \ 第一部分(IP 版本)
0 : 0 /
0 : 0 /
-
0 : 0 \
1 : 2^2 = 4 \ 第二部分(头长度)
0 : 0 /
1 : 2^0 = 1 /
64 + 4 + 1 = 69
如果设置了IP 选项,那么第一自己是01000110(十进制70),过滤规则:
# tcpdump -i eth1 'ip[0] > 69'
IPv6 的数据也会匹配,看看第二种方法。
2. 位操作
0100 0101 : 第一字节的二进制
0000 1111 : 与操作
=========
0000 0101 : 结果
正确的过滤方法
# tcpdump -i eth1 'ip[0] & 15 > 5'
或者
# tcpdump -i eth1 'ip[0] & 0x0f > 5'
分片标记
--------
当发送端的MTU 大于到目的路径链路上的MTU 时就会被分片,这段话有点拗口,权威的
请参考《TCP/IP 详解》。唉,32 借我的书没还,只能凑合写,大家记得看书啊。
分片信息在IP 头的第七和第八字节:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Flags| Fragment Offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Bit 0: 保留,必须是0
Bit 1: (DF) 0 = 可能分片, 1 = 不分片.
Bit 2: (MF) 0 = 最后的分片, 1 = 还有分片.
Fragment Offset 字段只有在分片的时候才使用。
要抓带DF 位标记的不分片的包,第七字节的值应该是:
01000000 = 64
# tcpdump -i eth1 'ip[6] = 64'
抓分片包
--------
- 匹配MF,分片包
# tcpdump -i eth1 'ip[6] = 32'
最后分片包的开始3 位是0,但是有Fragment Offset 字段。
- 匹配分片和最后分片
# tcpdump -i eth1 '((ip[6:2] > 0) and (not ip[6] = 64))'
测试分片可以用下面的命令:
ping -M want -s 3000 192.168.1.1
匹配小TTL
---------
TTL 字段在第九字节,并且正好是完整的一个字节,TTL 最大值是255,二进制为11111111。
可以用下面的命令验证一下:
$ ping -M want -s 3000 -t 256 192.168.1.200
ping: ttl 256 out of range
+-+-+-+-+-+-+-+-+
| Time to Live |
+-+-+-+-+-+-+-+-+
- 在网关可以用下面的命令看看网络中谁在使用traceroute
# tcpdump -i eth1 'ip[8] < 5'
抓大于X 字节的包
---------------
- 大于600 字节
# tcpdump -i eth1 'ip[2:2] > 600'
更多的IP 过滤
------------
首先还是需要知道TCP 基本结构,再次推荐《TCP/IP 详解》,卷一就够看的了,避免
走火入魔。
TCP 头
-----
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Acknowledgment Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data | |C|E|U|A|P|R|S|F| |
| Offset| Res. |W|C|R|C|S|S|Y|I| Window |
| | |R|E|G|K|H|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| data |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- 抓取源端口大于1024 的TCP 数据包
# tcpdump -i eth1 'tcp[0:2] > 1024'
- 匹配TCP 数据包的特殊标记
TCP 标记定义在TCP 头的第十四个字节
+-+-+-+-+-+-+-+-+
|C|E|U|A|P|R|S|F|
|W|C|R|C|S|S|Y|I|
|R|E|G|K|H|T|N|N|
+-+-+-+-+-+-+-+-+
重复一下TCP 三次握手,两个主机是如何勾搭的:
1. 源发送SYN
2. 目标回答SYN, ACK
3. 源发送ACK
没女朋友的童鞋要学习一下:
1. MM,你的手有空吗?-_-
2. 有空,你呢?~_~
3. 我也有空*_*
失败的loser 是酱紫的:
1. MM,这是你掉的板砖吗?(SYN)
2. 不是,找拍啊?(RST-ACK)
- 只抓SYN 包,第十四字节是二进制的00000010,也就是十进制的2
# tcpdump -i eth1 'tcp[13] = 2'
- 抓SYN, ACK (00010010 or 18)
# tcpdump -i eth1 'tcp[13] = 18'
- 抓SYN 或者SYN-ACK
# tcpdump -i eth1 'tcp[13] & 2 = 2'
用到了位操作,就是不管ACK 位是啥。
- 抓PSH-ACK
# tcpdump -i eth1 'tcp[13] = 24'
- 抓所有包含FIN 标记的包(FIN 通常和ACK 一起,表示幽会完了,回见)
# tcpdump -i eth1 'tcp[13] & 1 = 1'
- 抓RST(勾搭没成功,伟大的greatwall 对她认为有敏感信息的连接发RST 包,典型的棒
打鸳鸯)
# tcpdump -i eth1 'tcp[13] & 4 = 4'
详细描述了TCP 各种状态的标记,方便分析。
吴吖哦注
--------
tcpdump 考虑了一些数字恐惧症者的需求,提供了部分常用的字段偏移名字:
icmptype (ICMP 类型字段)
icmpcode (ICMP 符号字段)
tcpflags (TCP 标记字段)
ICMP 类型值有:
icmp-echoreply, icmp-unreach, icmp-sourcequench, icmp-redirect, icmp-echo,
icmp-routeradvert, icmp-routersolicit, icmp-timxceed, icmp-paramprob, icmp-tstamp,
icmp-tstampreply, icmp-ireq, icmp-ireqreply, icmp-maskreq, icmp-maskreply
TCP 标记值:
tcp-fin, tcp-syn, tcp-rst, tcp-push, tcp-push, tcp-ack, tcp-urg
这样上面按照TCP 标记位抓包的就可以写直观的表达式了:
- 只抓SYN 包
# tcpdump -i eth1 'tcp[tcpflags] = tcp-syn'
- 抓SYN, ACK
# tcpdump -i eth1 'tcp[tcpflags] & tcp-syn != 0 and tcp[tcpflags] & tcp-ack != 0'
抓SMTP 数据
----------
# tcpdump -i eth1 '((port 25) and (tcp[(tcp[12]>>2):4] = 0x4d41494c))'
抓取数据区开始为"MAIL"的包,"MAIL"的十六进制为0x4d41494c。
抓HTTP GET 数据
--------------
# tcpdump -i eth1 'tcp[(tcp[12]>>2):4] = 0x47455420'
"GET "的十六进制是47455420
抓SSH 返回
---------
# tcpdump -i eth1 'tcp[(tcp[12]>>2):4] = 0x5353482D'
"SSH-"的十六进制是0x5353482D
# tcpdump -i eth1 '(tcp[(tcp[12]>>2):4] = 0x5353482D) and (tcp[((tcp[12]>>2)+4):2]
= 0x312E)'
抓老版本的SSH 返回信息,如"SSH-1.99.."
吴吖哦注
--------
如果是为了查看数据内容,建议用tcpdump -s 0 -w filename 把数据包都保存下来,
然后用wireshark 的Follow TCP Stream/Follow UDP Stream 来查看整个会话的内容。
"-s 0"是抓取完整数据包,否则默认只抓68 字节。
另外,用tcpflow 也可以方便的获取TCP 会话内容,支持tcpdump 的各种表达式。
UDP 头
-----
0 7 8 15 16 23 24 31
+--------+--------+--------+--------+
| Source | Destination |
| Port | Port |
+--------+--------+--------+--------+
| | |
| Length | Checksum |
+--------+--------+--------+--------+
| |
| DATA ... |
+-----------------------------------+
- 抓DNS 请求数据
# tcpdump -i eth1 udp dst port 53
其他
----
-c 参数对于运维人员来说也比较常用,因为流量比较大的服务器,靠人工CTRL+C 还是
抓的太多,于是可以用-c 参数指定抓多少个包。
# time tcpdump -nn -i eth0 'tcp[tcpflags] = tcp-syn' -c 10000 > /dev/null
上面的命令计算抓10000 个SYN 包花费多少时间,可以判断访问量大概是多少。

原创粉丝点击