互联网安全建设从0到1
上QQ阅读APP看书,第一时间看更新

1.1 网络流量的收集

如果想识别网络中黑客的攻击,需要先了解网络流量,以及如何对网络流量进行收集、分析。本节将介绍针对网络流量的收集,为后续的攻击识别进行铺垫。

流量镜像(SPAN)也叫端口镜像,一般是指在交换机上将一个或多个源端口(或VLAN)的数据流量转发到某一个指定端口,目的是方便对一个或多个网络接口的流量进行监听和分析(通过IDS产品、网络分析仪等)。可以通过配置交换机实现流量镜像,如图1-1所示。

图1-1 流量镜像

WebServer1和WebServer2接在核心交换机上,通过防火墙映射至公网,提供Web服务,可以通过流量镜像的方式将两台WebServer的流量镜像至MonitorServer,这样MonitorServer即可对访问WebServer的所有流量进行分析。相关命令如下(Cisco):


monitor session 1 source interface Fa0/13-14 both

其中,Fa0/13-14为WebServer接口,both参数表示收集双向流量,也可以指定rx、tx参数,设置只收集入方向流量或出方向流量。


monitor session 1 destination interface Fa0/15

其中,Fa0/15为MonitorServer接口。

当然,也有可能出现被收集流量服务器不在同一台交换机的情况,这时就要使用远端镜像(RSPAN)技术,不过建议还是在规划的时候尽量将被监控服务器放在同一台交换机,毕竟流量穿过一台或者多台交换机对带宽及交换机性能还是会造成一定的损耗。

获取到镜像流量之后,将流量接入服务器接口,便可以在服务器网卡上抓到流量包。下面介绍几种流量收集方式。

1.1.1 最传统的抓包方式libpcap

提起抓包工具,在Linux环境下大家最先想到的是tcpdump,Windows环境下常用的是Wireshark。而这两个最流行的抓包软件底层使用的是libpcap(Packet Capture Library)。

libpcap是UNIX/Linux系统下最流行的抓包C库。libpcap提供了链路层数据包抓取、链路层数据包发送、包过滤规则。

1.下载安装

官方网站(http://www.tcpdump.org)最新的libpcap版本为1.9.0。下载安装即可:


wget http://www.tcpdump.org/release/libpcap-<version>.tar.gz
tar xvf http://www.tcpdump.org/release/libpcap-<version>.tar.gz
./configure
make
sudo make install

2.libpcap抓包流程

libpcap典型的抓包流程如图1-2所示。

图1-2 libpcap抓包流程图

首先调用pcap_open_live打开一个网卡设备[1],pcap_open_live函数原型如下:


pcap_t * pcap_open_live(const char * device, int snaplen, int promisc,
int to_ms, char * errbuf)
# device 设备名称
# snaplen每一帧最大长度,即tcpdump -s选项,过大会浪费性能,过小会丢失数据,默认为65535
# promisc 是否开启混杂模式,1表示开启,0表示不开启
# to_ms
# errbuf字符串缓冲区,用来存放错误信息
# 成功返回pcap实例,失败返回NULL,并将错误信息填充到errbuf中

在默认情况下,网卡只接收目标MAC为本机MAC或者为广播的数据,所以抓取镜像流量时总是需要开启混杂模式,抓取本机流量时则可以不必开启此选项。在Linux下也可以手动开启混杂模式,命令为:


ifconfig <eth> promisc

3.pcap_loop、pcap_dispatch、pcap_next函数

在接收网卡数据包时,有三个函数可选:pcap_loop、pcap_dispatch、pcap_next。其中,pcap_next是调用pcap_dispatch来实现轮询调用,每次调用返回一个数据包,pcap_loop使用回调的方式来获取数据包,pcap_loop的定义如下:


int pcap_loop(pcap_t*p, int cnt, pcap_handler callback, unchar * user);

需要设置一个回调函数:


typedef void (*pcap_handler)(u_char *arg, const struct pcap_pkthdr *hdr,
const u_char *pkt);
# arg为用户自定义参数,来自pcap_loop函数的最后一个参数,这是C语言为回调函数提供上下文
  和配置的惯用方式,可以指向一个全局的结构体
# hdr抓包头
# pkt抓到的以太网帧数据

pcap_loop中第二个参数cnt指定pcap_loop最多收取多少个帧数据后返回,显然在抓取流量镜像时应当设置为–1。

pcap_dispatch和pcap_next每次调用处理一次以太网数据帧,pcap_dispatch可以传递与pcap_loop兼容的pcap_handler函数,而pcap_next则直接返回数据,需要用户主动调用pcap_next程序。

三个函数都可以达到目的,笔者比较喜欢用pcap_loop。

4.pcap_close函数

在代码逻辑退出时,务必使用pcap_close函数关闭pcap句柄。一个常见的编程技巧是,在处理退出信号时关闭句柄。

5.BFP过滤器

BFP过滤器语法同tcpdump,使用过滤器减少程序接收到的无用数据,此处不详细介绍,感兴趣的读者可查阅相关资料。

6.wincap和npcap

我们在Windows上用得最多的抓包软件是Wireshark。Wireshark抓包软件底层也是用的libpcap,在Windows系统下使用的wincap是一个libpcap兼容的Windows移植版。wincap接口的大部分用法同libpcap,只是wincap不支持本地回环网口抓取。在Windows XP系统以上的Windows系统中,可以使用npcap这一抓包SDK。npcap是由Nmap开发的一款libpcap兼容的抓包SDK。也就是说,可以使用npcap作为Wireshark的底层。

[1] 打开设备时传入NULL或者any,可以打开当前系统下的所有网卡设备。libpcap也可以通过pcap_open_offline打开离线的pcap文件来获取流量。

1.1.2 scapy

libpcap是用C语言实现的,调用libpcap对于大多数非专业C程序员来说有一定的难度。然而大多数开发者都可以写一些Python脚本。本节介绍一下Python的便捷抓包程序scapy。

libpcap抓包得到是一个链路层的以太网数据帧,后续的包解析、流还原均需要自己编程或者调用其他代码库来实现,当然,libpcap也提供了包(以太网帧)发送的能力。而scapy不仅仅是一个抓包库,同时也提供了发送、构造、解码、协议解析的能力。

scapy官方网站为https://scapy.net,去官方网站安装pip install scapy[1]。在安装完scapy之后,在命令行输入scapy就进入了scapy的REPL(Read Eval Print Loop,交互式解释器)模式。RPEL模式表示一个计算机环境,类似Windows系统的终端或UNIX/Linux shell,Python命令本身就是一个REPL。

注意:在Windows下安装scapy需要用到wincap或者npcap,关于wincap和npcap的使用请参考后续内容,事实上scapy底层也依赖于libpcap。

在RPEL模式下输入ls(),可以列出scapy支持的协议格式,如下所示:

scapy抓包很简单,只需要2行代码。我们来看一个例子:

其中,第一行导入scapy包,第二行使用sniff函数抓取100个数据包,然后返回一个dpkt的list对象,这样就获取了连续的100个数据包。

如何持续抓数据包呢?sniff函数同样支持给定一个回调函数来持续获取数据,关于回调函数,我们在1.1.1节中已经做了介绍:


sniff(filter=filterstr,prn=pack_callback, iface='<eth>', count=0)

scapy的sniff函数相当于C语言调用几个libpcap函数。简单、易用、有丰富的解码库,这些都是scapy的优点,不足之处主要是受制于Python解释器低下的解释执行效率。关于抓包性能的提升我们会在1.1.4节介绍。

[1] scapy支持Python 2.7.x和Python 1.4以上的版本,Python 3环境下应使用pip3。

1.1.3 gopacket

体验到了scapy的便捷与强大,又苦于Python较低的性能,那么此时gopacket也许是一个折中的选择。gopacket起源于gopcap项目,gopcap最初是由Andreas Krennmair利用cgo实现的一个使用Go语言调用libpcap的封装,后来Google在此基础上发展出功能强大、性能优异的抓包库。关于gopacket的更多信息,可参考如下网站:

·gopacket代码:https://github.com/google/gopacket

·gopacket文档:https://godoc.org/github.com/google/gopacket

gopacket安装步骤如下:

1)安装1.5以上版本的Go语言。

2)安装gopacket:


go get github.com/google/gopacket

gopacket有几个概念:

·source:数据源,即数据来源,屏蔽了不同抓包驱动的抽象接口。

·layers:数据层,用来执行数据包解析。

·flow:一组双向通信为一个数据流。

gopacket支持PF_RING/af_packet/pcap作为抓包驱动,pcap模式用法类似于C语言。此处不再赘述,感兴趣的读者可以参考官方的例子(https://github.com/google/gopacket/tree/master/examples/pcapdump)。

1.1.4 丢包与性能提升

前面提到抓包总是和性能分不开,如何提升性能是很重要的。我们首先来看一下Linux系统接收数据包的流程,如图1-3所示。

1)数据包经过光纤或者电缆进入网口(在网络接口层),并发向下一层,即OSI模型的物理层。

2)接着进入MAC层,MAC层用于匹配目标MAC地址是否为本机MAC地址或者广播MAC地址(混杂模式下不做检测,全部接受)。

3)网卡硬件将数据填充到FIFO缓冲区中,并通过中断通知CPU驱动程序来进行接收。

图1-3 Linux系统接收数据包的流程

4)驱动程序使用DMA技术将网卡缓冲区的数据接收并发送到内核缓冲区。

5)内核将接收到的数据依次通过网络协议栈向上传递。

6)应用层通过系统调用或者socket接收网络数据。

我们使用到的libpcap是在应用层通过系统调用获取到的内核层网络缓冲区数据。

抓包性能提升的关键首先是网卡,高性能的网卡拥有更高的吞吐率和包延时。物理器件的情况也会影响抓包效率,特别是从分光器出来的流量,光衰的存在导致抓包率有所降低。

再往上层,高速的抓包驱动和缩短抓包流程也能提高效率。除了Python、Go语言上的性能情况,libpcap抓包流程漫长也是其抓包效率低下的原因。libpcap通过系统调用同内核通信,效率低下。在此背景下就有了PF_RING和DPDK技术。

1.1.5 PF_RING、DPDK与af_packet

PF_RING是由ntpop开发的抓包软件。PF_RING有vanilla模式和付费的ZC模式两种(老版本的PF_RING有三种模式)。想要实现高性能抓包,必须编译用PF_RING修改的网卡驱动。使用PF_RING时必须选择PF_RING支持的网卡型号[1]。实测vanilla模式性能并不理想。付费版ZC模式的PF_RING按照MAC来计算费用,性能可以大幅提升,原因在于PF_RING实现了一个从驱动直接到应用层的内存映射来高速传递数据包。

DPDK(Data Plane Development Kit)是由Intel官方开发并开源的抓包工具。支持大多数Intel网卡,网卡选型空间较大。在原理上用到UIO、大页内存、NUMA等技术。在驱动上使用轮询模式替代中断模式,使用CPU资源来换取高速抓包。DPDK的不足之处是开发难度较大,SDK也是用C语言调用,需要对CPU体系结构有较深的了解。DPDK在云计算等场景下已经得到大量验证,经得起生产环境的考验。

af_packet抓包工具是Linux 1.x之后提供的新抓包技术,gopacket支持使用af_packet进行抓包;实测af_packet抓包技术性能优于libpcap,且无须修改网卡驱动,仅对操作系统内核版本有要求。国内大多数互联网公司使用的是CentOS,如果需要使用af_packet,请选择CentOS 7及以上版本。

此外,使用硬件网络分流器也是一个很好的解决方案,现在服务器一般都配有多个网卡,使用硬件分流器将大流量分散到多个网口上,使用多进程进行抓包,或者使用多机多进程方案进行抓包。

[1] 当前支持e1000e/igb/ixgbe/i40e/fm10k网卡驱动,参考https://github.com/ntop/PF_RING/blob/dev/drivers/intel/README。