Wireshark - 抓包界的鲨鱼
一、 一些背景知识
说起 TCP 通讯中的三次握手,相信大家应该都不陌生。
“咳,不就是指建立一个TCP连接时,需要客户端和服务器总共发送3个包才能确立连接吗?”
那么,你知道当你在浏览器中输入网址,到浏览器最终呈现出网页,这中间到底经历了哪些过程吗?
“大概我都知道,但是具体的过程到底是怎么样的,我还真不是特别熟。如果可以有个工具能查看到这个过程就好了。”
别说,还真有这么一个工具,可以实现我们的理论实践。它就是大名鼎鼎的 Wireshark 。
二、 抓包界的狠角色 - Wireshark
Wireshark 是世界上最流行的网络分析工具。这个强大的工具可以捕捉网络中的数据,并为用户提供关于网络和上层协议的各种信息。
与很多其他网络工具一样,Wireshark 也使用 pcap network library 来进行封包捕捉。
Wireshark的优势:
- 安装方便。
- 简单易用的界面。
- 提供丰富的功能。
Wireshark 的原名是 Ethereal,新名字是 2006 年起用的。当时 Ethereal 的主要开发者决定离开他原来供职的公司,并继续开发这个软件。但由于 Ethereal 这个名称的使用权已经被原来那个公司注册,Wireshark 这个新名字也就应运而生了。
2.1 Wireshark 的安装
Wireshark 提供 Windows 和 MacOS 版本的安装包下载以及源码下载,Linux 环境可以自行下载源码进行编译,然后通过 Tshark 这个轻量级的命令行工具实现对数据的处理。
本文已 Windows 环境下的 Wireshark 为例,Windows 版本的安装非常简单,按照默认配置一路安装下来即可。
2.2 Wireshark 的界面
安装完 Wireshark 之后,打开后就可以看到开始界面了。
Wireshark 可以捕获机器上的某一块 网卡
的网络包,当机器上有多块网卡的时候,我们可以在开始页面上选择具体需要的网卡。
另外在这个页面上我们还可以提前预设好 过滤器
,使用过滤是非常重要的, Wireshark 在抓包的时候将会得到大量的冗余信息,在几千甚至几万条记录中,我们很难找到自己需要的部分。而过滤器会帮助我们在大量的数据中迅速找到我们需要的信息。我们暂时先跳过过滤器的介绍,放到第五章再讲。
双击具体的需要进行抓包的网卡,我们就进入了 Wireshark 的真正的主界面了。
从图中可以看到,Wireshark 的主界面主要有四大块功能区。
(1)显示过滤器
和开始界面中的过滤器不同,两者虽然都叫过滤器,但是过滤的范围有所不同。开始界面中的过滤器是针对网卡进行的过滤,也就是在此处设置的过滤会决定哪些符合要求的封包进入我们的封包显示区,主界面的显示过滤器是针对封包显示区中的数据进行更进一步的细致的过滤。
例如我想看 IP 地址为 115.231.97.2 的封包通讯,那么我就可以在显示过滤器中填写这么一条过滤指令:ip.addr == 115.231.97.2
, Wireshark 就会将 IP 地址为 115.231.97.2 的所有数据包展示出来。
(2) 封包显示区
封包显示区可以显示数据包的编号、时间戳、源地址、目标地址、协议、长度以及封包信息。我们可以看到不同的协议用了不同的颜色显示。
我们也可以修改这些显示颜色的规则,视图
-> 着色规则
。
(3) 封包详细信息
这个面板对我们是最重要的,用来查看协议中的每一个字段。
各行信息分别为:
- Frame: 物理层的数据帧概况
- Ethernet II: 数据链路层以太网帧头部信息
- Internet Protocol Version 4: 互联网层 IP 包头部信息
- Transmission Control Protocol: 传输层的数据段头部信息,此处是 TCP
- Hypertext Transfer Protocol: 应用层的信息,此处是 HTTP 协议
各行信息与对应的 OSI 七层模型
什么是 OSI 七层模型
OSI 七层模型是一个用于计算机或通信系统间互联的标准体系。我们知道网络通讯的物理线路并非是可靠安全的,OSI 七层模型解决的就是在此之上建立一个可靠、安全的传输渠道。
- 物理层:最下面一层,节点之间不可靠、不安全的传输就是物理层。
- 数据链路层: 首先搭了一个数据链路层,既然节点之间传输数据不安全,那么需要一个单位(数据包),通过奇偶校验或其它方法来检验包是否正确,由此完成了一个节点到另外一个节点之间数据包的传递。
- 网络层: 如果 Tom 和 Jerry 都在一个房间内,那么数据链路层足够,可是如果是其它地区、国家,这就不仅仅是两个节点之间传输,需要一个网络层。网络层有路由,Tom 会把包发给房间的路由器,路由器再传输给其它路由,辗转很多层后最后到 Jerry 所在的电脑上。这就是网络层的工作,同时为了标识在网络层中的各个节点,使用了 IP 协议,使每个节点都有 IP 地址。
- 传输层: 虽然在数据链路层可以确定包是否正确, 但不能保证是相对可靠的,此时需要重传机制在错误时可以自动重传这个包,而不需要Tom人工确认,这就需要传输层。由此产生了对应的TCP、UDP协议。TCP协议是基于连接的,在 Tom 和 Jerry 传输之间建立一个可靠的连接,在此连接上传输数据。
- 会话层:为两端通信实体建立连接(会话),中间有认证鉴权以及检查点记录(供会话意外中断的时候可以继续,类似断点续传)。
- 表示层:决定数据的展现(编码)形式,如同一部电影可以采样、量化、编码为 RMVB、AVI,一张图片能够是 JPEG、BMP、PNG 等。
- 应用层:以上过程确实可以传输可靠的数据,但是这个数据是为哪个应用服务的呢?是 HTTP 还是 STP 或者 email 协议,这就是应用层。
下图可以看到 Wireshark 捕获到的 TCP包 中的每个字段。
(4) 十六进制数据
在这里用十六进制形式表示封包内容,可以显示数据包在物理层上传输时的最终形式。
工具认识的差不多了,接下来就让我们来验证一下,传说中的 “三次握手” 究竟是怎么执行的吧。
三、 一探究竟 - 三次握手的现场
我们先来补充一些背景知识。
3.1 为何我们需要三次握手?
我们知道网络传输并非是可靠、安全的,具体体现如下:
- 不可靠性:
丢包、重复包:发送包对方并未收到或是收到重复包。
出错:传输时出错,只能通过重传来解决。
乱序:包是按照顺序发送的,对方接收时顺序打乱。
- 不安全性: 网络传输一定是一个不安全的线路,因为网络层将数据发送给另外一个节点,需要经过很多路由器,每一个路由都有可能被黑客监听。
3.2 三次握手
TCP 是主机对主机层的传输控制协议,提供可靠的连接服务,采用三次握手确认建立一个连接。
3.2.1 TCP 标志位
TCP在其协议头中使用大量的标志位或者说 1 位(bit)布尔域来控制连接状态,一个包中有可以设置多个标志位。位码即 TCP 标志位,有 6 种标示:
- SYN (synchronous): 创建连接
- ACK (acknowledgement):确认接收到的数据
- PSH (push):传送
- FIN (finish):结束连接
- RST (reset):重置
- URG (urgent):紧急
- Sequence number:(顺序码)
- Acknowledge number:(确认码)
3.2.2 握手过程
建立一个 TCP 连接时,需要客户端和服务器总共发送3个包。目的是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号和确认号并交换 TCP 窗口大小信息。
第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;
第二次握手:服务器收到 syn 包,必须确认客户的 SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即 SYN+ACK 包,此时服务器进入 SYN_RECV 状态;
第三次握手:客户端收到服务器的 SYN+ACK 包,向服务器发送确认 包ACK(ack=k+1),此包发送完毕,客户端和服务器进入 ESTABLISHED 状态,完成三次握手。完成三次握手,客户端与服务器开始传送数据。
3.3 鲨鱼出动
我们以抓包访问又拍云官网(www.upyun.com)的数据,以此分析网络模型组成及相关原理。
1 打开 WireShark,选择本机连接的网络进行捕获。
2 打开 Chrome,访问又拍云官网。
3 停止捕获,在捕获内容中搜索字符串 "upyun",第一条就是捕获到的数据,点击查看具体内容构成。
4 解析 211 号 DNS 数据包
这是一个 DNS 数据包,代表我们要访问又拍云官网,首先要通过 DNS 请求到又拍云的 IP 地址。
- Frame 211: 73 bytes on wire (584 bits), 73 bytes captured (584 bits) on interface 0
这是物理层,Frame 211 代表这是第 211 号数据包,大小为 73。
- Ethernet II, Src: AsustekC_9b:71:45 (d0:17:c2:9b:71:45), Dst: fa:16:3e:f7:0b:26 (fa:16:3e:f7:0b:26)
数据链路层的报文头,它的 Src 是 AsustekC_9b:71:45 ,这其实是我的电脑,华硕主板,Windows 系统,Dst 中的是我电脑连接的网络路由。虽然这是DNS的一个 query,但是无法访问我的路由,最终是传到外面 DNS 的路由,在数据链路层只是将包从电脑传到路由,这个包会由路由器进行转发。
- Internet Protocol Version 4, Src: 10.0.1.141, Dst: 10.0.6.30
网络层即IP层的头。很熟悉的 IPV4 协议,Src 是我连接的网络的IPV4地址,Dst 是 DNS 服务器地址。
- User Datagram Protocol, Src Port: 52526, Dst Port: 53
传输层中UDP协议的头。 这个DNS的请求是作为一个UDP包发送,不需要预先建立连接。
- Domain Name System (query)
DNS 的 query 内容。以上的 UDP 包中的内容就是 DNS 的 query 部分,由以下二进制数据表示,根据协议会规定每个字节代表什么含义,Wireshark 会翻译出每个字节的含义,例如下图中:
Questions 数量为 1,www.upyun.com 又拍云的地址。(意味着还可以有多个 Questions )
这里可以看到 Response 响应在 212 号包。
5 解析 212 号 DNS 数据包
- Ethernet II, Src: fa:16:3e:f7:0b:26 (fa:16:3e:f7:0b:26), Dst: AsustekC_9b:71:45 (d0:17:c2:9b:71:45)
src 内容是本地路由
- Internet Protocol Version 4, Src: 10.0.6.30, Dst: 10.0.1.141
src 是 DNS 服务器地址,Dst 是本机 IP,代表 DNS 将包发送到本机;
DNS 的 response 内容,DNS 返回的 Answer 有 2 个地址。最终解析到的 IP 地址是 115.231.100.108
。
6 与又拍云建立连接,进行网络协议中的三次握手
经过以上步骤后,接下来在 Wireshark 中过滤 115.231.100.108
地址的信息即可。
显示过滤器填写:ip.addr==115.231.100.108
我们看一下 213、214、215 号 TCP 包,查看其 Info 部分。
我们可以看到 TCP 对应的三次握手的标记包。
第一个包标志为 [SYN]
第二个包标志为 [SYN,ACK]
第三个包标志为 [ACK]
7 213 号 TCP 包
- 数据链路层(Ethernet II)
包是从本机发送到路由。
- 网络层(IPV4)
将包发送给又拍云。
- 传输层(TCP):
- Destination Port
目的地端口号为 80, 即试图和又拍云的 80 号端口连接,80 号端口是 HTTP 协议的端口,浏览器若要访问需要从 HTTP 获取信息。
- Sequence number
是包的编号为0。
- Acknowledgment number
0,因为目前并未收到Ack。
- Flags
设置为SYN,代表连接的请求。
- Window size value
滑动窗口的大小,大小是 64240。
- TCP Segment Len
长度为 0,因为本次请求只带了一个头部,内容为 0,所以此包的长度除去头部之外为 0。
8 214 号 TCP 包
我们继续查看第二次握手又拍云响应的包是什么,直接查看重点部分 TCP 内容如下:
- Acknowledgment number
值为 1,在 TCP 中 1 并不表示收到了包,而是说在等待、期待发送包,因为之前已经发送了第一个包,意味着包 0 已经收到,现在期待收包 1。
- Flags
值为(SYN,Ack),这代表服务器已经收到了连接请求,并且愿意进行连接。
- Window size value
又拍云的滑动窗口大小,长度为 7300。
9 215 号 TCP 包
我们继续查看第三次握手又拍云响应的包是什么,直接查看重点部分 TCP 内容如下:
- Sequence number
包的编号为 1
- Acknowledgment number
值为 1,说明我们已经收到了又拍云的 0 号包,现在期待 1 号包的来临。
- Flags
设置为(Ack),代表确认连接。
- Window size value
调整滑动窗口大小为 260。
当此包被发送出去后,3 次握手过程完成,本机和又拍云之间的消息在一个很可靠的 TCP 连接上进行。
10 成功建立连接,开始 GET 请求资源
我们可以看到现在已经开始进行 HTTP 协议通讯了。
其中,TCP Segment Len 长度不再为 0,而是 399。
Sequence number 仍然是1,值得注意的是,在 TCP 协议中并非按照 1、2、3…. 这样来标识,而是按照发送字节的大小。例如当前是 1,加上此包本身长度为 399,所以 Next sequence number 是 400。
Acknowledgment number 为 1。
HTTP 内容请求
第一个包接收完后继续接收第二个包。
Acknowledgment number 为 400 ,表示从 0~399 之间的数据已接收到,从 400 开始发送。
218 号包接收完后云通知浏览器进行 302 跳转,访问 https 站点,而后又是三次握手的过程。
四、 一探究竟 - HTTPS 安全加密
HTTPS 实际就是在 TCP 层与 HTTP 层之间加入了 TLS/SSL 来解决安全问题的。
在进行应用数据传输之前,TLS 需要通过握手过程来协商安全通信所需的相关参数。
整个通信过程中主要用到散列、对称加密、非对称加密和证书等相关技术,来解决客户端与服务器数据传输中各种安全风险问题,从而达到保证整个通信过程的安全。
我们也可以通过 Wireshark 来观察整个 TLS 握手的过程。
从上图大致可以总结出握手的基本流程:
- 1、客户端向服务器端发送一个 Client Hello;
- 2、服务器端向客户端返回一个 Server Hello;
- 3、服务器端向客户端返回一个 Certificate;
- 4、服务器端向客户端返回 Server key change,Server Hello Done;
- 5、客户端向服务器端发送 Client Key Exchange, Change Cipher Spec, Encrypted Handshake Message;
- 6、服务器端向客户端返回 Change Cipher Spec, Encrypted Handshake Message。
注:以上为 TLSv1.2 版本状态下的握手流程,TLSv1.3 改进了握手加密的步骤,使其变得更为安全与迅速,因此抓包情况会有所不同。
下面的例子以访问百度首页为例,分析一下 TLS 握手加密的过程。
抓包后可以使用 ip.addr == 115.239.211.112 && ssl
界面过滤规则来查看与百度通信的封包情况。
1 Client Hello
从这条消息开始,开始 TLS 协议的握手过程。
我们可以在 Client Hello 消息中,看到两个 Version 信息,根据 RFC5246 它们分别是:第一处表示本次通信使用的 TLS 版本为 1.0,第二处表示客户端期望使用的 TLS 版本为 1.2。
注:这里的版本协商,客户端会提供它能支持的最高的 TLS 版本,由服务端确认最终使用的 TLS 版本。)
Random(随机数)前面的四个字节是当前时间,它的格式是 Unix 时间戳。跟随其后是 28 字节的随机数,它将在后面加密过程中使用。
Session ID(会话 ID)一般是空值或者是 0。如果在几秒前连接过该服务,它就可能继续使用之前的会话,不需要重新执行整个“握手”过程。
Cipher Suites(加密套件组),它是请求发送端所支持的密码算法的一个列表。这里看到请求发起方提供了 17 个可供选择的选项。每一个 Cipher Suite 都是 4 个算法类型的组合:
- 1 个 authentication(认证)算法;
- 1 个 encryption(加密)算法;
- 1 个 message authentication code (消息认证码,简称 MAC)算法;
- 1 个 key exchange(密钥交换)算法。
一个组件算法可用于实现信息加密、完整性校验和身份验证等功能。
这个字段包含了我们请求要发往的服务器的域名信息,它作用有些类似 HTTP 协议中 “Host” 请求头。
2 Server Hello
Server Hello 中有服务端对 Client Hello 回应的一些关键信息:
同 Client Hello 类似,它返回了服务端的当前时间,以及服务端产生的一个 28 字节随机数。
服务端确认通信使用的 TLS 版本:TLS1.2
服务端选择的通信使用的加密协议套件:
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
注:这里的 Session ID 长度为 0 。如果服务器未查到客户端的 Session ID 指定的会话(可能是会话已经老化),则会重新握手,Session ID 要么重新计算(和 Client Hello 中 Client Hello 不一样),要么置成 0,这两个方式都会告诉客户端这次会话不进行会话复用。
3 Server Key Exchange
对于使用 DHE/ECDHE 非对称密钥协商算法的 TSL 握手,将发送该类型握手。
ECDHE下主要有几点重要的信息
- 1:指明自己使用的椭圆曲线算法(一般根据客户端的拓展中 supported_groups 中的选择椭圆曲线算法);
- 2:公钥。服务器本地计算一个大数(BIGNUM),乘上曲线的 Base Point,得到一个新的 Point,这个 Point 就是公钥,用 04+x+y 的格式组织起来。04表示 unconpressed point,和客户端的 ec_point_formats 有关;
- 3:签名。和 RSA 握手不同,RSA 情况下, 只要能正常协商密钥,那么必然服务器端有证书对应的私钥,也间接表明了服务器拥有该证书。DHE/ECDHE 不同,证书对应的私钥并不参与密钥协商,如果要证明服务器拥有证书,则必然有签名的操作(就像双向认证的情况下,客户端需要发送 certificate verify )。
4 Client Key Exchange&Change Cipher Spec、Encrypted Handshake Message(Finished)
- 1:Client Key Exchange,合法性验证通过之后,客户端计算产生随机数字 Pre-master,并用证书公钥加密,发送给服务器;
- 2:Change Cipher Spec,客户端通知服务器后续的通信都采用协商的通信密钥和加密算法进行加密通信;
- 3:Encrypted Handshake Message,结合之前所有通信参数的值与其它相关信息生成一段数据,采用协商密钥与算法进行加密,然后发送给服务器用于数据与握手验证。
这里需要注意的是,在 Finished 消息中包含两部分信息,finish 标识和 hash 校验信息。但是无论客户端还是服务端, 在Change Cipher Spec 之后的内容都已经通过加密方式传输了,所以 Finished 中具体内容已经无法通过 Wireshark 直接查看。
5 Server Hello Done
这是 TLS 握手过程的最后一条消息,至此,TLS通信的整个握手过程已经完成。后续就开始加密传输数据了。
五、 过犹不及 -- 过滤器
使用 Wireshark 时最常见的问题,就是我们会得到大量冗余信息,以至于很难找到自己需要的部分。
所以我们就会讲到过滤器。为什么过滤器会如此重要?就是因为它们可以帮助我们在庞杂的结果中迅速找到我们需要的信息。
Wireshark 有两种过滤器:
- 捕捉过滤器:用于决定将什么样的信息记录在捕捉结果中。需要在开始捕捉前设置。
- 显示过滤器:在捕捉结果中进行详细查找。过滤器规则可以在得到捕捉结果后随意修改。
那么我们应该使用哪一种过滤器呢?
两种过滤器的目的是不同的。捕捉过滤器是数据经过的第一层过滤器,它用于控制捕捉数据的数量,以避免产生过大的日志文件。显示过滤器是一种更为强大(复杂)的过滤器。它可以在日志文件中迅速准确地找到所需要的记录。两种过滤器使用的语法是完全不同的。
1 捕捉过滤器
在开始界面中,我们可以在界面中直接找到捕获过滤器。
捕捉过滤器的语法如下图:
- Protocol(协议)
可选的值: ether, fddi, ip, arp, rarp, decnet, lat, sca, moprc, mopdl, tcp, udp 等等。
如果没有特别指明是什么协议,则默认使用所有支持的协议。
- Direction(方向)
可选的值: src, dst, src and dst, src or dst
如果没有特别指明来源或目的地,则默认使用 "src or dst" 作为关键字。
例如,"host 10.2.2.2" 与 "src or dst host 10.2.2.2" 是一样的。
- Host
可选的值: net, port, host, portrange.
如果没有指定此值,则默认使用"host"关键字。
例如,"src 10.1.1.1" 与 "src host 10.1.1.1" 相同。
- Logical Operations(逻辑运算)
可选的值:not, and, or.
否 ("not") 具有最高的优先级。或 ("or") 和与 ("and") 具有相同的优先级,运算时从左至右进行。
例如:
"not tcp port 3128 and tcp port 23" 与 "(not tcp port 3128) and tcp port 23" 相同。
"not tcp port 3128 and tcp port 23" 与 "not (tcp port 3128 and tcp port 23)" 不同。
Wireshark 提前预设了一些过滤器规则,例如:
更多例子和语法详情可参考Wireshark 的过滤器文档。
实战:分析 ICMP 协议数据包
ping 是用来测试网络连通性的命令,一旦发出 ping 命令,主机会发出连续的测试数据包到网络中,在通常的情况下,主机会收到回应数据包,ping 采用的是 ICMP 协议。
1 为了抓取使用 ICMP 的包,我们要设置过滤条件。按照语法规则,只需要定义协议项即可。icmp
。
2 点击对应网卡开始,发现现在抓取不到任何包。
3 打开命令行窗口,执行命令:ping www.upyun.com
4 这时可以看到数据包抓取页面抓取到了 8 包,与命令行显示的已发送和已接受的包的数量是一致的。
5 我们查看抓取到的封包数据可以发现,ICMP 的报文就只有两种,请求和应答。
请求:
应答:
两个报文的 type 不一样,8 代表请求,0 代表应答;code都为 0,表示为回显应答;标示符和序列号都是一样的,表示这两个报文是配对的。
2 显示过滤器
通常经过捕捉过滤器过滤后的数据还是很复杂。相信这一点大家在上面验证三次握手的时候就已经感受到了。当捕捉结果非常繁杂的时候,我们就可以使用显示过滤器进行更加细致的查找。
它的功能比捕捉过滤器更为强大,而且我们可以根据情况随时修改规则来提供更加精准的结果显示。
捕捉过滤器的语法如下图:
- Protocol(协议)
Wireshark 支持大量协议。在显示过滤器栏的右边点击 “表达式” 按钮后,我们可以看到所有 Wireshark 支持的协议。我们可以在其中搜索自己所需的协议。
比如:IP,TCP,DNS,SSH
- String1, String2 (可选项)
协议的子类。展开相关协议,然后选择其子类即可。
- Comparison operators (比较运算符)
每个子类可使用的比较运算符可以在表达式的右上角的 关系
中找到。
- Logical expressions(逻辑运算符)
可用的逻辑运算符有以下几个:
| 普通写法 | 代码写法 |含义
| :----: | :----: | :----: |
| and | && |逻辑与
| or | || | 逻辑或
| xor | ^^ | 逻辑异或
| not | ! | 逻辑非
举个例子:tcp.dstport 80 xor tcp.dstport 1025
只有当目的 TCP 端口为 80 或者 来源于端口 1025 时,这样的封包才会被显示。
以下是一些常用的显示过滤规则。
1 snmp || dns || icmp
显示 SNMP 或 DNS 或 ICMP 封包。
2 ip.addr == 10.1.1.1
显示来源或目的 IP 地址为 10.1.1.1 的封包。
3 ip.src != 10.1.2.3 or ip.dst != 10.4.5.6
显示来源不为 10.1.2.3 或者目的不为 10.4.5.6 的封包。
4 ip.src != 10.1.2.3 and ip.dst != 10.4.5.6
显示来源不为 10.1.2.3 并且目的 IP 不为 10.4.5.6 的封包。
5 tcp.port == 25
显示来源或目的 TCP 端口号为 25 的封包。
6 tcp.dstport == 25
显示目的TCP端口号为25的封包。
7 tcp.flags
显示包含 TCP 标志的封包。
8 tcp.flags.syn == 0x02
显示包含 TCP SYN 标志的封包。
参考文章: 又拍云-热门工具
版权属于:DeepFal
本文链接:https://blog.deepfal.cn/index.php/archives/61/
转载时须注明出处及本声明
1 条评论
不错不错,我喜欢看