Head First系列计划用于记录一些工具的简单使用方法以及有意思的概念。尽量做到由表及里,层层深入。
后面如果未加说明,参考的 Linux 内核源码版本均为 4.10.10。
1. 介绍
man tcpdump
首先要说的是,不要死记硬背固定的命令。在理解了基本的参数后,可以根据具体情况自己灵活组合出有效的命令来。
为什么要用 tcpdump?
一方面,大部分 *nix 服务器没有图形界面,\
也没有预装 Wireshark,却几乎都预装了 tcpdump;
另一方面,tcpdump 的包过滤功能太强大。
下面是我根据网上资料重新组织出的讲解思路,如有错误请指教。
使用tcpdump
需要用到root
权限。
简单来说,一个tcpdump
命令串可以是下面这个形式:
# tcpdump [options] [filter expressions]
options
以-
打头,filter expressions
则不是。为了避免歧义,作为一个好习惯,最好用单引号把你的表达式包起来(对于简单的语句也可以不用),后面讲到逻辑运算时,还会用到小括号。
2. 选项
-i INTERFACE
如-i eth0
,-i any
表示监听所有网络接口。
-s SIZE
对一个包抓取前多少字节。默认是 68 字节,-s 0
表示抓取包的所有内容。
-A
数据以 ASCII 形式显示。
-X
数据以 Hex 形式显示(这个倒是很有用)。
-w FILENAME
将抓取数据写入文件。
-r FILENAME
从文件中读取数据并展示。
-n
不对 IP 做域名解析。
-nn
既不对 IP 解析,也不对 port 做服务解析。
-tttt
使用人类易读的时间形式(有用倒是有用,但这个选项怎么长这样)。
-c NUMBER
抓取 NUMBER 个符合所有条件的包后停止。
-D
显示当前有哪些可用的 INTERFACE。
-S
使用 absolute sequence number。
选项就介绍这么多,足够大多数情况使用了。
3. 过滤表达式
过滤表达式就非常有趣了,和正则表达式一样,甚至和各种编程语言一样。我们能够利用基本的 gadgets 创造出解决问题的工具。
3.1 组合
首先,有几组不同类型的组合标示符:
上面三列之间是可以组合的(事实上有些组合是非法的,如tcp net
,另外顺序有时也是有要求的)!对某一列缺少指定则表示这一列的所有包都符合条件。
一些例子如下:
tcpdump -i eth0 host 192.168.137.128 -r file.pcap
tcpdump -i eth0 tcp dst port 22
tcpdump -i any src net 192.168.137.0/24
对于host
,你在某些包过滤中还可以指定mac
地址:
tcpdump -i eth0 ether dst host 00:01:02:03:04:05
对于port
,你也可以使用dst portrange 21-23
这种形式来限定端口范围。
3.2 包大小限定
less
/greater
:
tcpdump less 128
tcpdump greater 28
3.3 逻辑运算
上面的各种组合已经很厉害了,这里的逻辑运算能够帮你生成更强大的筛选条件。
and or not
&& || !
使用上下哪一种形式都可以。
例如:
tcpdump -i eth0 '(dst port 80) && (tcp) && (less 128)'
tcpdump -i eth0 '(dst port 80) && (tcp) && (greater 128)'
注意括号的使用。对有过编程经验的朋友来说,括号的意义和重要性不必再说。
3.4 高级玩家技能
下面进入更厉害的环节。核心目的是缩小筛选粒度。方法是定位到具体包的特定位置。
以tcp
为例:
如果我们想筛选带ACK
和FIN
标志的数据包该怎么做呢?从上图可以看出,标志位占 6 个比特,偏移量为 13 字节。所以所有符合要求的包头,它们的偏移 13 字节处的那个字节必定为XXX11XXX
形式,其值至少为 16 + 8 = 24
。我们可以这样限制:
tcpdump '(tcp[13] & 16 != 0) && (tcp[13] & 8 != 0)'
对于IP
/ICMP
等协议,也都可以采用类似方式指定对应位的信息。
另外,还有其他一些更方便的表达方式,下面仅仅举出例子:
带syn
标志:
tcpdump 'tcp[tcpflags] == tcp-syn'
片段选择:
tcpdump 'tcp[32:4] = 0x47455420'
4. 惯用法
大家可以根据上面学到的内容推理一下它们的功能。
语句
time tcpdump -nn -i eth0 'tcp[tcpflags] = tcp-syn' -c 10000 > /dev/null
tcpdump -ttttnnvvS
tcpdump -nnvXSs 0 -c1 icmp
tcpdump -nnvvS src 10.5.2.3 and dst port 3389
tcpdump -nvX src net 192.168.0.0/16 and dst net 10.0.0.0/8 or 172.16.0.0/16
tcpdump 'src 10.0.2.4 and (dst port 3389 or 22)'