[转载]聊聊tcpdump与Wireshark抓包分析

1 tcpdump与Wireshark介绍#

在解决网络问题时,经常需要通过监控网络流量和分析协议数据,进行定位问题。tcpdump是linux下一款抓包工具,wireshark是一款抓包和数据包分析工具。两者通常结合使用,tcdump抓取的数据包保存为可分析文件,然后在windows系统下通过wireshark进行分析。tcpdump命令需要使用-w保存文件。

如果要使用tcpdump抓取其他主机MAC地址的数据包,必须开启网卡混杂模式,所谓混杂模式,用最简单的语言就是让网卡抓取任何经过它的数据包,不管这个数据包是不是发给它或者是它发出的。一般而言,Unix不会让普通用户设置混杂模式,因为这样可以看到别人的信息,比如telnet的用户名和密码,这样会引起一些安全上的问题,所以只有root用户可以开启混杂模式,开启混杂模式的命令是:ifconfig en0 promisc, en0是你要打开混杂模式的网卡

通常电脑主机端的抓包通过wireshark直接抓取,嵌入式设备内部的流量(不经过主机端)通过tcpdump来抓取,比如设备跟手机APP之间的通信只能在tcpdump抓取数据包。

2 tcpdump使用#

2.1 语法##

tcpdump [ -AdDefIKlLnNOpqRStuUvxX ] [ -B buffer_size ] [ -c count ]
        [ -C file_size ] [ -G rotate_seconds ] [ -F file ]
        [ -i interface ] [ -m module ] [ -M secret ]
        [ -r file ] [ -s snaplen ] [ -T type ] [ -w file ]
        [ -W filecount ]
        [ -E spi@ipaddr algo:secret,...  ]
        [ -y datalinktype ] [ -z postrotate-command ] [ -Z user ]
        [ expression ]
  1. 类型的关键字

host(缺省类型): 指明一台主机,如:host 210.27.48.2

net: 指明一个网络地址,如:net 202.0.0.0

port: 指明端口号,如:port 23

  1. 确定方向的关键字

src: src 210.27.48.2, IP包源地址是210.27.48.2

dst: dst net 202.0.0.0, 目标网络地址是202.0.0.0

dst or src(缺省值)

dst and src

  1. 协议的关键字:缺省值是监听所有协议的信息包

fddi

ip

arp

rarp

tcp

udp

  1. 其他关键字

gateway

broadcast

less

greater

  1. 常用表达式:多条件时可以用括号,但是要用\转义

非 : ! or "not" (去掉双引号)

且 : && or "and"

或 : || or "or"

2.2 选项##

 

-A:以ASCII编码打印每个报文(不包括链路层的头),这对分析网页来说很方便;
-a:将网络地址和广播地址转变成名字; 
-c<数据包数目>:在收到指定的包的数目后,tcpdump就会停止;
-C:用于判断用 -w 选项将报文写入的文件的大小是否超过这个值,如果超过了就新建文件(文件名后缀是1、2、3依次增加);
-d:将匹配信息包的代码以人们能够理解的汇编格式给出; 
-dd:将匹配信息包的代码以c语言程序段的格式给出; 
-ddd:将匹配信息包的代码以十进制的形式给出;
-D:列出当前主机的所有网卡编号和名称,可以用于选项 -i;
-e:在输出行打印出数据链路层的头部信息; 
-f:将外部的Internet地址以数字的形式打印出来; 
-F<表达文件>:从指定的文件中读取表达式,忽略其它的表达式; 
-i<网络界面>:监听主机的该网卡上的数据流,如果没有指定,就会使用最小网卡编号的网卡(在选项-D可知道,但是不包括环路接口),linux 2.2 内核及之后的版本支持 any 网卡,用于指代任意网卡; 
-l:如果没有使用 -w 选项,就可以将报文打印到 标准输出终端(此时这是默认); 
-n:显示ip,而不是主机名; 
-N:不列出域名; 
-O:不将数据包编码最佳化; 
-p:不让网络界面进入混杂模式; 
-q:快速输出,仅列出少数的传输协议信息; 
-r<数据包文件>:从指定的文件中读取包(这些包一般通过-w选项产生); 
-s<数据包大小>:指定抓包显示一行的宽度,-s0表示可按包长显示完整的包,经常和-A一起用,默认截取长度为60个字节,但一般ethernet MTU都是1500字节。所以,要抓取大于60字节的包时,使用默认参数就会导致包数据丢失; 
-S:用绝对而非相对数值列出TCP关联数; 
-t:在输出的每一行不打印时间戳; 
-tt:在输出的每一行显示未经格式化的时间戳记; 
-T<数据包类型>:将监听到的包直接解释为指定的类型的报文,常见的类型有rpc (远程过程调用)和snmp(简单网络管理协议); 
-v:输出一个稍微详细的信息,例如在ip包中可以包括ttl和服务类型的信息; 
-vv:输出详细的报文信息; 
-x/-xx/-X/-XX:以十六进制显示包内容,几个选项只有细微的差别,详见man手册; 
-w<数据包文件>:直接将包写入文件中,并不分析和打印出来;
expression:用于筛选的逻辑表达式;

2.3 命令实践##

接启动tcpdump,将抓取所有经过第一个网络接口上的数据包

tcpdump

 

抓取所有经过指定网络接口上的数据包

tcpdump -i en0

如果不指定网卡,默认tcpdump只会监视第一个网络接口,一般是eth0,下面的例子都没有指定网络接口。

 

抓取所有经过 en0,目的或源地址是 10.37.63.255 的网络数据:

tcpdump -i en0 host 10.37.63.255

 

抓取主机10.37.63.255和主机10.37.63.61或10.37.63.95的通信:

tcpdump host 10.37.63.255 and \(10.37.63.61 or 10.37.63.95 \)

 

抓取主机192.168.13.210除了和主机10.37.63.61之外所有主机通信的数据包:

tcpdump -n host 10.37.63.255 and ! 10.37.63.61

 

抓取主机10.37.63.255除了和主机10.37.63.61之外所有主机通信的ip包

tcpdump ip -n host 10.37.63.255 and ! 10.37.63.61

 

抓取主机10.37.63.3发送的所有数据:

tcpdump -i en0 src host 10.37.63.3 (注意数据流向)

 

抓取主机10.37.63.3接收的所有数据:

tcpdump -i en0 dst host 10.37.63.3 (注意数据流向) 

 

抓取主机10.37.63.3所有在TCP 80端口的数据包:

tcpdump -i en0 host 10.37.63.3 and tcp port 80

 

抓取HTTP主机10.37.63.3在80端口接收到的数据包:

tcpdump -i en0 host 10.37.63.3 and dst port 80

 

抓取所有经过 en0,目的或源端口是 25 的网络数据

tcpdump -i en0 port 25

# 源端口
tcpdump -i en0 src port 25
# 目的端口
tcpdump -i en0 dst port 25网络过滤

 

抓取所有经过 en0,网络是 192.168上的数据包

tcpdump -i en0 net 192.168
tcpdump -i en0 src net 192.168
tcpdump -i en0 dst net 192.168
tcpdump -i en0 net 192.168.1
tcpdump -i en0 net 192.168.1.0/24

协议过滤

tcpdump -i en0 arp
tcpdump -i en0 ip
tcpdump -i en0 tcp
tcpdump -i en0 udp
tcpdump -i en0 icmp

抓取所有经过 en0,目的地址是 192.168.1.254 或 192.168.1.200 端口是 80 的 TCP 数据

tcpdump -i en0 '((tcp) and (port 80) and ((dst host 192.168.1.254) or (dst host 192.168.1.200)))'

抓取所有经过 en0,目标 MAC 地址是 00:01:02:03:04:05 的 ICMP 数据

tcpdump -i eth1 '((icmp) and ((ether dst host 00:01:02:03:04:05)))'

抓取所有经过 en0,目的网络是 192.168,但目的主机不是 192.168.1.200 的 TCP 数据

tcpdump -i en0 '((tcp) and ((dst net 192.168) and (not dst host 192.168.1.200)))'

只抓 SYN 包

tcpdump -i en0 'tcp[tcpflags] = tcp-syn'

抓 SYN, ACK

tcpdump -i en0 'tcp[tcpflags] & tcp-syn != 0 and tcp[tcpflags] & tcp-ack != 0'

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

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

抓 HTTP GET 数据,"GET "的十六进制是 0x47455420

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

# 0x4745 为"GET"前两个字母"GE",0x4854 为"HTTP"前两个字母"HT"
tcpdump  -XvvennSs 0 -i en0 tcp[20:2]=0x4745 or tcp[20:2]=0x4854

抓 SSH 返回,"SSH-"的十六进制是 0x5353482D

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

# 抓老版本的 SSH 返回信息,如"SSH-1.99.."
tcpdump -i en0 '(tcp[(tcp[12]>>2):4] = 0x5353482D) and (tcp[((tcp[12]>>2)+4):2] = 0x312E)' 

高级包头过滤

如前两个的包头过滤,首先了解如何从包头过滤信息:

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

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

抓取端口大于1024的TCP数据包:

tcpdump -i en0 'tcp[0:2] > 1024'

抓 DNS 请求数据

tcpdump -i en0 udp dst port 53

其他

-c 参数对于运维人员来说也比较常用,因为流量比较大的服务器,靠人工 CTRL+C 还是抓的太多,于是可以用-c 参数指定抓多少个包。

time tcpdump -nn -i en0 'tcp[tcpflags] = tcp-syn' -c 10000 > /dev/null

上面的命令计算抓 10000 个 SYN 包花费多少时间,可以判断访问量大概是多少。

实时抓取端口号8000的GET包,然后写入GET.log

tcpdump -i en0 '((port 8000) and (tcp[(tcp[12]>>2):4]=0x47455420))' -nnAl -w /tmp/GET.log

2.4 抓个网站练练##

想抓取访问某个网站时的网络数据。比如网站 http://www.baidu.com/ 怎么做?

通过tcpdump截获主机www.baidu.com发送与接收所有的数据包

tcpdump -i en0 host www.baidu.com

 

想要看到详细的http报文。怎么做?

tcpdump -A -i en0 host www.baidu.com

将抓取的结果存到文件,比如文件 file1

tcpdump -A -i en0 -w file1 host www.baidu.com

如何读取这个文件的基本信息

tcpdump -r file1

想要了解更多,比如上面的http报文

tcpdump -A -r file1

也同时想要将确认序列号ack打印成绝对值

tcpdump -AS -r file1

注:

无参数的选项比如 -A, -S, -e, 等。均可以共用一个减号

'src host www.baidu.cn' 属于 expression ,如果太长,可以用单引号括起来:

tcpdump -i en0 'src host www.baidu.com'

 

3 tcpdump抓取TCP包分析#

TCP传输控制协议是面向连接的可靠的传输层协议,在进行数据传输之前,需要在传输数据的两端(客户端和服务器端)创建一个连接,这个连接由一对插口地址唯一标识,即是在IP报文首部的源IP地址、目的IP地址,以及TCP数据报首部的源端口地址和目的端口地址。TCP首部结构如下:

输入图片说明

输入图片说明

注意:通常情况下,一个正常的TCP连接,都会有三个阶段:1、TCP三次握手;2、数据传送;3、TCP四次挥手

其中在TCP连接和断开连接过程中的关键部分如下:

  1. 源端口号:即发送方的端口号,在TCP连接过程中,对于客户端,端口号往往由内核分配,无需进程指定;

  2. 目的端口号:即发送目的的端口号;

  3. 序号:即为发送的数据段首个字节的序号;

  4. 确认序号:在收到对方发来的数据报,发送确认时期待对方下一次发送的数据序号;

  5. SYN:同步序列编号,Synchronize Sequence Numbers;

  6. ACK:确认编号,Acknowledgement Number;

  7. FIN:结束标志,FINish;

3.1 TCP三次握手##

三次握手的过程如下:

输入图片说明

输入图片说明

step1. 由客户端向服务器端发起TCP连接请求。Client发送:同步序列编号SYN置为1,发送序号Seq为一个随机数,这里假设为X,确认序号ACK置为0

step2. 服务器端接收到连接请求。Server响应:同步序列编号SYN置为1,并将确认序号ACK置为X+1,然后生成一个随机数Y作为发送序号Seq(因为所确认的数据报的确认序号未初始化)

step3. 客户端对接收到的确认进行确认。Client发送:将确认序号ACK置为Y+1,然后将发送序号Seq置为X+1(即为接收到的数据报的确认序号)

  1. 为什么是三次握手而不是两次

对于step3的作用,假设一种情况,客户端A向服务器B发送一个连接请求数据报,然后这个数据报在网络中滞留导致其迟到了,虽然迟到了,但是服务器仍然会接收并发回一个确认数据报。但是A却因为久久收不到B的确认而将发送的请求连接置为失效,等到一段时间后,接到B发送过来的确认,A认为自己现在没有发送连接,而B却一直以为连接成功了,于是一直在等待A的动作,而A将不会有任何的动作了。这会导致服务器资源白白浪费掉了,因此,两次握手是不行的,因此需要再加上一次,对B发过来的确认再进行一次确认,即确认这次连接是有效的,从而建立连接

  1. 对于双方,发送序号的初始化为何值

有的系统中是显式的初始化序号是0,但是这种已知的初始化值是非常危险的,因为这会使得一些黑客钻漏洞,发送一些数据报来破坏连接。因此,初始化序号因为取随机数会更好一些,并且是越随机越安全。

tcpdump抓TCP三次握手抓包分析:

sudo tcpdump -n -S -i lo0 host 10.37.63.3 and tcp port 8080

# 接着再运行:
curl http://10.37.63.3:8080/atbg/doc

 

3.2 TCP四次挥手##

连接双方在完成数据传输之后就需要断开连接。由于TCP连接是属于全双工的,即连接双方可以在一条TCP连接上互相传输数据,因此在断开时存在一个半关闭状态,即有有一方失去发送数据的能力,却还能接收数据。因此,断开连接需要分为四次。主要过程如下:

输入图片说明

输入图片说明

step1. 主机A向主机B发起断开连接请求,之后主机A进入FIN-WAIT-1状态;

step2. 主机B收到主机A的请求后,向主机A发回确认,然后进入CLOSE-WAIT状态;

step3. 主机A收到B的确认之后,进入FIN-WAIT-2状态,此时便是半关闭状态,即主机A失去发送能力,但是主机B却还能向A发送数据,并且A可以接收数据。此时主机B占主导位置了,如果需要继续关闭则需要主机B来操作了;

step4. 主机B向A发出断开连接请求,然后进入LAST-ACK状态;

step5. 主机A接收到请求后发送确认,进入TIME-WAIT状态,等待2MSL之后进入CLOSED状态,而主机B则在接受到确认后进入CLOSED状态;

  1. 为何主机A在发送了最后的确认后没有进入CLOSED状态,反而进入了一个等待2MSL的TIME-WAIT

主要作用有两个:

第一,确保主机A最后发送的确认能够到达主机B。如果处于LAST-ACK状态的主机B一直收不到来自主机A的确认,它会重传断开连接请求,然后主机A就可以有足够的时间去再次发送确认。但是这也只能尽最大力量来确保能够正常断开,如果主机A的确认总是在网络中滞留失效,从而超过了2MSL,最后也无法正常断开;

第二,如果主机A在发送了确认之后立即进入CLOSED状态。假设之后主机A再次向主机B发送一条连接请求,而这条连接请求比之前的确认报文更早地到达主机B,则会使得主机B以为这条连接请求是在旧的连接中A发出的报文,并不看成是一条新的连接请求了,即使得这个连接请求失效了,增加2MSL的时间可以使得这个失效的连接请求报文作废,这样才不影响下次新的连接请求中出现失效的连接请求。

  1. 为什么断开连接请求报文只有三个,而不是四个

因为在TCP连接过程中,确认的发送有一个延时(即经受延时的确认),一端在发送确认的时候将等待一段时间,如果自己在这段事件内也有数据要发送,就跟确认一起发送,如果没有,则确认单独发送。而我们的抓包实验中,由服务器端先断开连接,之后客户端在确认的延迟时间内,也有请求断开连接需要发送,于是就与上次确认一起发送,因此就只有三个数据报了。

4 Wireshark分析tcpdump抓包结果#

  1. 启动8080端口,tcpdump抓包命令如下:
tcpdump -i lo0 -s 0 -n -S host 10.37.63.3 and port 8080 -w ./Desktop/tcpdump_10.37.63.3_8080_20160525.cap

# 然后再执行curl
curl http://10.37.63.3:8080/atbg/doc
  1. 使用Wireshark打开tcpdump_10.37.63.3_8080_20160525.cap文件

输入图片说明

输入图片说明

No. 1-4 行:TCP三次握手环节;

No. 5-8 行:TCP传输数据环节;

No. 9-13 行:TCP四次挥手环节;

  1. 顺便说一个查看 http 请求和响应的方法:

输入图片说明

输入图片说明

弹窗如下图所示,上面红色部分为请求信息,下面蓝色部分为响应信息:

输入图片说明

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值