[关闭]
@AlexWuYh 2021-03-03T09:19:22.000000Z 字数 7039 阅读 95

tcpdump 高级过滤方式

Linux tcpdump



首先了解如何从包头过滤信息

  1. proto[x:y] : 过滤从x字节开始的y字节数。比如ip[2:2]过滤出34字节(第一字节从0开始排)
  2. proto[x:y] & z = 0 : proto[x:y]和z的与操作为0
  3. proto[x:y] & z !=0 : proto[x:y]和z的与操作不为0
  4. proto[x:y] & z = z : proto[x:y]和z的与操作为z
  5. proto[x:y] = z : proto[x:y]等于z

操作符 : >, <, >=, <=, =, !=

IP头(IPV4)

  1. 0 1 2 3
  2. 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
  3. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  4. |Version| IHL |Type of Service| Total Length |
  5. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  6. | Identification |Flags| Fragment Offset |
  7. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  8. | Time to Live | Protocol | Header Checksum |
  9. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  10. | Source Address |
  11. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  12. | Destination Address |
  13. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  14. | Options | Padding | <-- optional
  15. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  16. | DATA ... |
  17. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

中文:

268981-20180530231811755-859452716.jpg-24.1kB

  1. /*IP头定义,共20个字节*/
  2. typedef struct _IP_HEADER
  3. {
  4. char m_cVersionAndHeaderLen;   //版本信息(前4位),头长度(后4位)
  5. char m_cTypeOfService;       // 服务类型8位
  6. short m_sTotalLenOfPacket;     //数据包长度
  7. short m_sPacketID;         //数据包标识
  8. short m_sSliceinfo;         //分片使用
  9. char m_cTTL;           //存活时间
  10. char m_cTypeOfProtocol;       //协议类型
  11. short m_sCheckSum;        //校验和
  12. unsigned int m_uiSourIp;      //源ip
  13. unsigned int m_uiDestIp;      //目的ip
  14. } __attribute__((packed))IP_HEADER, *PIP_HEADER ;

IP选项

一般的IP头是20字节,但IP头有选项设置,不能直接从偏移21字节处读取数据。IP头有个长度字段可以知道头长度是否大于20字节。

通常第一个字节的二进制值是:01000101,

分成两个部分:

0100 = 4 表示IP版本

0101 = 5 表示IP头32 bit的块数,

5 x 32 bits = 160 bits or 20 bytes

如果第一字节第二部分的值大于5,那么表示头有IP选项。

下面介绍有过滤方法

0100 0101 **: 第一字节的二进制
**0000 1111
: 与操作
<=========
0000 0101 : 结果

正确的过滤方法:

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

或者

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

分片标记

当发送端的MTU大于到目的路径链路上的MTU时就会被分片,分片信息在IP头的第七和第八字节:

  1. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  2. |Flags| Fragment Offset |
  3. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Bit 0: 保留,必须是0
Bit 1: (DF) 0 = 可能分片, 1 = 不分片
Bit 2: (MF) 0 = 最后的分片, 1 = 还有分片

Fragment Offset字段只有在分片的时候才使用。

要抓带DF位标记的不分片的包,第七字节的值应该是:

01000000 = 64

  1. tcpdump -i eth1 'ip[6] = 64'

抓分片包

  1. tcpdump -i eth1 'ip[6] = 32'

最后分片包的开始3位是0,但是有Fragment Offset字段。

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

测试分片可以用下面的命令:

  1. ping -M want -s 3000 192.168.1.1

匹配小TTL

TTL字段在第九字节,并且正好是完整的一个字节,TTL最大值是255,二进制为11111111。

可以用下面的命令验证一下:

  1. $ ping -M want -s 3000 -t 256 192.168.1.200
  2. ping: ttl 256 out of range
  1. +-+-+-+-+-+-+-+-+
  2. | Time to Live |
  3. +-+-+-+-+-+-+-+-+
  1. tcpdump -i eth1 'ip[8] < 5'

抓大于X字节的包

  1. tcpdump -i eth1 'ip[2:2] > 600'

更多的过滤方式

首先还是需要知道TCP基本结构

  1. 0 1 2 3
  2. 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
  3. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  4. | Source Port | Destination Port |
  5. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  6. | Sequence Number |
  7. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  8. | Acknowledgment Number |
  9. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  10. | Data | |C|E|U|A|P|R|S|F| |
  11. | Offset| Res. |W|C|R|C|S|S|Y|I| Window |
  12. | | |R|E|G|K|H|T|N|N| |
  13. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  14. | Checksum | Urgent Pointer |
  15. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  16. | Options | Padding |
  17. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  18. | data |
  19. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

  268981-20180530234728337-1534993130.jpg-60.1kB

  1. /*TCP头定义,共20个字节*/
  2. typedef struct _TCP_HEADER
  3. {
  4. short m_sSourPort;       //源端口号16bit
  5. short m_sDestPort;        //目的端口号16bit
  6. unsigned int m_uiSequNum;   //序列号32bit
  7. unsigned int m_uiAcknowledgeNum; //确认号32bit
  8. short m_sHeaderLenAndFlag;   //前4位:TCP头长度;中6位:保留;后6位:标志位
  9. short m_sWindowSize;      //窗口大小16bit
  10. short m_sCheckSum;       //检验和16bit
  11. short m_surgentPointer;      //紧急数据偏移量16bit
  12. }__attribute__((packed))TCP_HEADER, *PTCP_HEADER;
  13. /*TCP头中的选项定义
  14. kind(8bit)+Length(8bit,整个选项的长度,包含前两部分)+内容(如果有的话)
  15. KIND =
  16. 1表示 无操作NOP,无后面的部分
  17. 2表示 maximum segment 后面的LENGTH就是maximum segment选项的长度(以byte为单位,1+1+内容部分长度)
  18. 3表示 windows scale 后面的LENGTH就是 windows scale选项的长度(以byte为单位,1+1+内容部分长度)
  19. 4表示 SACK permitted LENGTH为2,没有内容部分
  20. 5表示这是一个SACK包 LENGTH为2,没有内容部分
  21. 8表示时间戳,LENGTH为10,含8个字节的时间戳
  22. */

16位源端口号和16位目的端口号。

32位序号

​ 一次TCP通信过程中某一个传输方向上的字节流的每个字节的编号,通过这个来确认发送的数据有序,比如现在序列号为1000,发送了1000,下一个序列号就是2000。

32位确认号

​ 用来响应TCP报文段,给收到的TCP报文段的序号加1,三握时还要携带自己的序号。

4位头部长度

​ 标识该TCP头部有多少个4字节,共表示最长15*4=60字节。同IP头部。

6位保留

​ 6位标志。URG(紧急指针是否有效)ACK(表示确认号是否有效)PSH(提示接收端应用程序应该立即从TCP接收缓冲区读走数据)RST(表示要求对方重新建立连接)SYN(表示请求建立一个连接)FIN(表示通知对方本端要关闭连接)

16位窗口大小

​ TCP流量控制的一个手段,用来告诉对端TCP缓冲区还能容纳多少字节。

16位校验和

​ 由发送端填充,接收端对报文段执行CRC算法以检验TCP报文段在传输中是否损坏。

16位紧急指针

​ 一个正的偏移量,它和序号段的值相加表示最后一个紧急数据的下一字节的序号。

标志位字段(U、A、P、R、S、F)

占6比特。各比特的含义如下:

  1. tcpdump -i eth1 'tcp[0:2] > 1024'

TCP标记定义在TCP头的第十四个字节

  1. +-+-+-+-+-+-+-+-+
  2. |C|E|U|A|P|R|S|F|
  3. |W|C|R|C|S|S|Y|I|
  4. |R|E|G|K|H|T|N|N|
  5. +-+-+-+-+-+-+-+-+
  1. tcpdump -i eth1 'tcp[13] = 2'
  1. tcpdump -i eth1 'tcp[13] = 18'
  1. tcpdump -i eth1 'tcp[13] & 2 = 2'
  1. tcpdump -i eth1 'tcp[13] = 24'
  1. tcpdump -i eth1 'tcp[13] & 1 = 1'
  1. tcpdump -i eth1 'tcp[13] & 4 = 4'

常用的字段偏移名字

tcpdump考虑了一些数字恐惧症者的需求,提供了部分常用的字段偏移名字:

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标记位抓包的就可以写直观的表达式了:

  1. tcpdump -i eth1 'tcp[tcpflags] = tcp-syn'
  1. tcpdump -i eth1 'tcp[tcpflags] & tcp-syn != 0 and tcp[tcpflags] & tcp-ack != 0'

抓SMTP数据

  1. tcpdump -i eth1 '((port 25) and (tcp[(tcp[12]>>2):4] = 0x4d41494c))'

抓取数据区开始为"MAIL"的包,"MAIL"的十六进制为0x4d41494c。

抓HTTP GET数据

  1. tcpdump -i eth1 'tcp[(tcp[12]>>2):4] = 0x47455420'

"GET "的十六进制是47455420

抓SSH返回

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

 "SSH-"的十六进制是0x5353482D

  1. tcpdump -i eth1 '(tcp[(tcp[12]>>2):4] = 0x5353482D) and (tcp[((tcp[12]>>2)+4):2] = 0x312E)'
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注