说明

tcpdump在Linux系统中,由于它需要将网络界面设置为混杂模式,普通用户不能正常执行,但具备root权限的用户可以直接执行它来获取网络上的信息。 tcpdump可以将网络中传送的数据包的“头”完全截获下来提供分析。它支持针对网络层、协议、主机、网络或端口的过滤,并提供and、or、not等逻辑语句来去掉无用的信息。

不带参数的tcpdump会收集网络中所有的信息包头,数据量巨大,必须过滤。

常用选项:

-i 指定监听的网络接口 -nn IP和端口均以数字形式显示 -c 在收到指定的数量的分组后,tcpdump停止,如果没有这个参数,tcpdump会持续不断的监听直到用户输入 [ctrl]-c 为止 -e 输出数据链路层的头部信息(显示MAC地址相关信息)。 -t 在输出的每一行不打印时间戳 -q 只输出较少的协议信息(仅输出协议名称,如TCP;而不输出封包标记信息,如F、P等标记)

-w FILE直接将分组写入文件中,而不是到stdout -r FILE从后面接的文件将数据包数据读出来。那个「文件」是已经存在的文件,并且这个「文件」是由 -w 所制作出来的 -s 设置tcpdump的数据包抓取长度为len,如果不设置默认将会是65535字节。对于要抓取的数据包较大时,长度设置不够可能会产生包截断,若出现包截断,输出行中会出现"[|proto]"的标志(proto实际会显示为协议名)。但是抓取len越长,包的处理时间越长,并且会减少tcpdump可缓存的数据包的数量,从而会导致数据包的丢失,所以在能抓取我们想要的包的前提下,抓取长度越小越好(-s 0 使用默认长度65535)。 -D 列出可用于抓包的接口。将会列出接口的数值编号和接口名,它们都可以用于"-i"后 -L 列出网络接口的已知数据链路。 -F 从文件中读取抓包的过滤表达式。若使用该选项,则命令行中给定的其他表达式都将失效。

-A 数据包的内容以 ASCII 显示,通常用来捉取WWW的网页数据包资料 -X 数据包内容以十六进制 (hex)和ASCII显示,对于监听数据包内容很有用 -XX 比-X输出更详细

如果不使用-i选项明确要监听的接口,直接启动tcpdump将监视第一个网接口上所有流过的数据包

示例:

每行数据的说明:第一个分组为例 每行数据的说明:第一个分组为例 22:49:58 时间 464690 ID IP 表明是IP分组 10.0.0.61.22 分组发出源头的主机IP地址

或< 代表封包流动方向 10.0.0.1 分组目的地的主机IP地址 62659 目的地主机端口 Flags [P.] 标记(PUSH表示传输数据) seq 1389539161:1389539401 tcp的序列号范围(第一个包显示的是绝对值,后续的包显示的是相对值,如果也想显示绝对值,使用-T选项) ack 718462004 表明对序列号是718462004的包进行响应 win 325 表明发送窗口的大小是325 options [nop,nop,TS val 110216407 ecr 185503372] #一些选项值 length 240 封包长度

报文过滤表达式

表达式是一个正则表达式,tcpdump利用它作为过滤报文的条件,如果一个报文满足表达式的条件,则这个报文将会被捕获。如果没有给出任何条件,则网络上所有的信息包将会被截获,每条报文显示的信息过多难以分析,使用表达式经过滤出我们需要的信息 第一种是关于类型的关键字:主要包括host(默认),net,port,portrange host和net可搭配第2类的传输方向关键字 port可搭配第3类的各种协议关键字 例: host 210.27.48.2 #指明 210.27.48.2是一台主机, net 202.0.0.0 #指明202.0.0.0是一个网络地址, port 23 #指明端口号是23 portrange 6000-6008" #默认的type为host。 如果没有指定类型,缺省的类型是host 第二种是确定传输方向的关键字:主要包括src,dst,dst or src(默认),dst and src,这些关键字指明了传输的方向。可组合第一类关键字中的host,net,port,portrange 例: src host 210.27.48.2 #指明ip包中源地址是210.27.48.2 dst net 202.0.0.0 #指明目的网络地址是202.0.0.0 如果没有指明方向关键字,则缺省是src or dst关键字 第三种是协议类关键字:主要包括ip,tcp,udp,icmp,arp,rarp,fddi等类型 只能组合第一类关键字中的port 如果没有指定任何协议,则tcpdump将会监听所有协议的信息包。 其他重要的关键字:gateway,broadcast,less,greater。

三种逻辑运算可用于组合上述的关键字: 取非运算是 ‘not’,‘!’ 与运算是’and’,’&&’ 或运算是’or’ ,’||’ 这3个关键字可以任意组合 示例1: 在一个终端机窗口输入“tcpdump -nn -i lo” 再开一个终端,使用ssh 127.0.0.1登入,抓包,查看TCP的3次握手,和4次挥手过程

上述是TCP的3次握手 从标记P开始是传送数据 然后断开ssh连接 下面是TCP的4次挥手

示例2:测试-X选项的作用 一个窗口开始监听,另一个窗口进行ssh登录操作 可以看出使用-X选项,会将监听的数据同时以16进制及ASCII码形式显示(如果传输数据明文方式,如是有密码,将会被监听到) 示例3: 在10.0.0.61上监听,从10.0.0.8主机上ssh连接 由于使用了src port源端口过滤,因此三次握手仅监听到1次 示例4: 使用-w选项将,监听的数据输出到文件中,而不是stdout 其它示例: 1、获取所有10.0.0.61 的主机收到的和发出的所有的数据包 会有很多数据被输出 2、获取主机10.0.0.61和主机10.0.0.8 或10.0.0.7的通信,使用命令: 在命令行中使用括号时,一定要使用反斜线\转义

3、获取主机10.0.0.61除了和主机10.0.0.7之外所有主机通信的ip包,使用命令:

注意:!和IP地址之间至少有1个空格 4、获取主机10.0.0.7接收或发出的ssh(TCP)包 5、监听来自主机名为hostname主机的发送的数据包,主机名可以是本地主机,也可以是网络上的任何一台计算机 前提条件是:必须能够解析主机名 6、监听所有发送到主机hostname的数据包

tcpdump对截获的数据并没有进行彻底解码(-X选项显示),数据包内的大部分内容是使用十六进制的形式直接打印输出的。显然这不利于分析网络故障,通常的解决办法是先使用带-w参数的tcpdump 截获数据并保存到文件中,然后再使用其他程序进行解码分析。

除了过滤语句,还有一个很重要的参数,若设置不正确,会导致包数据的丢失! 它就是-s 参数,snaplen,也就是数据包的截取长度,默认截取长度为60个字节,但一般ethernet MTU都是1500字节。所以,要抓取大于60字节的包时,使用默认参数就会导致包数据丢失!只要使用-s 0就可以按包长,截取数据!

捕获带有特殊标记位的TCP包(SYN-ACK, URG-ACK等)

TCP协议头中有8个标记位: CWR | ECE | URG | ACK | PSH | RST | SYN | FIN 假设我们想要观察用于建立TCP连接的数据包。 回想一下,TCP在初始化一个新的连接时使用3次握手协议; 关于TCP控制位的连接顺序是: 1.客户端发送SYN 2.服务端回应SYN和ACK 3.客户端发送ACK 现在我们对捕获仅包含SYN位的数据包感兴趣(步骤1)。 请注意,我们不希望步骤2(SYN-ACK)的数据包,只是一个普通的初始SYN。 TCP头的结构: TCP头包含20个字节固定长度的数据(上图中的前4行),而控制位位于第13个字节(字节计算从0开始) 只看我们感兴趣的控制位:

这些是我们感兴趣的TCP控制位。我们对这个八位组中的位进行了编号,从0到7,从右到左,所以PSH位是位编号3,而URG位是编号5 回想一下,我们想要捕获只有SYN集的数据包。 让我们来看看如果一个TCP数据报到达并且在其头部设置了SYN位,会发生什么情况? 可以看到控制位部分只有位1(SYN位)被设置。 假定八位字节编号13(及第4个字节)是网络字节顺序中的8位无符号整数,则该八位字节的二进制值是 00000010 其十进制计算如下: 02 + 02 + 02 + 02 + 02 + 02 + 1*2 + 0*2 = 2 我们已经差不多完成了,因为现在我们知道如果只设置了SYN,TCP头中的第13个八位字节的值在网络字节顺序中解释为8位无符号整数时,必须恰好为2。 这种关系可以表示为: tcp[13] == 2 我们可以使用这个表达式作为tcpdump的过滤器,以便观察只有SYN集合的数据包: tcpdump -i xl0 tcp[13] == 2 表达式表示“让TCP数据报的第13个八位字节具有十进制值2”,这正是我们想要的。

现在,我们假设我们需要捕获SYN数据包,但我们并不在乎ACK或任何其他TCP控制位是否同时被设置。 看看带有SYN-ACK的TCP数据包是怎样的?

可以看到在第13个八位字节中只有第一位和第四位被设置。其二进制值是00010010 转换成十进制: 02 + 02 + 02 + 12 + 02 + 02 + 12 + 02 = 18 不能只用'tcp[13] == 18'作为tcpdump的过滤表达式, 因为这将导致只选择含有SYN-ACK标志的数据包, 其他的都被丢弃(只有SYN标志的包也会被丢弃). 而我们想要的是只要包的SYN标志被设置就将其过滤出来 为了实现我们的目标,我们需要将八位组13的二进制值与其他值进行逻辑与,以保留SYN位(只要其他包的也包含了SYN标记,进行与运算得到的结果就是1)。 我们知道我们希望在任何情况下都设置SYN,所以我们将第13个字节中的值与SYN的二进制值进行逻辑与:

我们看到,无论是否设置了ACK或另一个TCP控制位,此AND操作都会提供相同的结果。 AND值的十进制表示以及此操作的结果是2(二进制00000010),所以我们知道对于设置了SYN的数据包,以下关系必须为真:
( ( value of octet 13 ) AND ( 2 ) ) == ( 2 ) 第13个字节上其他位设置不管如何 与 SYN(2)进行与操作

使用tcpdump过滤表达式如下: tcpdump -i xl0 ’tcp[13] & 2 == 2’

其他示例: 1、打印涉及非本地主机的每个TCP会话的开始和结束数据包(SYN和FIN数据包)

tcpdump ’tcp[tcpflags] & (tcp-syn|tcp-fin) != 0 and not src and dst net localnet’

2、打印所有来自端口80的IPv4 HTTP数据包,即仅打印包含数据的数据包,而不打印例如SYN和FIN数据包以及仅ACK数据包。 tcpdump ’tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)’

3、打印通过网关snup发送的长度超过576字节的IP数据包:

tcpdump ’gateway snup and ip[2:2] > 576’

4、要打印未通过以太网广播或多播发送的IP广播或多播数据包:

tcpdump ’ether[0] & 1 = 0 and ip[16] >= 224’

5、要打印所有不是回显请求/回复的ICMP数据包(即不是ping数据包):

tcpdump ’icmp[icmptype] != icmp-echo and icmp[icmptype] != icmp-echoreply’