简单网络预警系统设计与实现

Posted Natuki丶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了简单网络预警系统设计与实现相关的知识,希望对你有一定的参考价值。

本学渣在《入侵防御技术及应用》这门课中的课程设计,希望能帮到你的课设或是项目



一、选题内容

1.1、问题描述:

基于网络嗅探,设计并实现一个简单的网络预警系统,针对捕获的数据包实现解码/译码和特征检测。

1.2、要求:

采用文本界面或图形界面下进行交互的工作方式,完成如下功能:

1.2.1、界面方面:

可配置、可显示系统运行结果。

1.2.2、功能设计:

抓取本机在网络中的通信数据,包括协议类型、源和目的地址、端口、数据包大小等。
支持应用层协议分析,至少包括 HTTP、FTP、SMTP 三种协议。
支持 SSL/TLS。
支持基于 MAC 地址、IP 地址、协议类型、端口、应用层协议特征的特征检测。
支持实时统计分析,根据检测结果,实时报警。

二、实验环境

编程语言:本程序采用C#语言设计
操作系统:Windows10
编译器:Microsoft Visual Studio 2019

三、方案设计

3.1、总体功能流程图设计

3.2、抓包功能

通过Winpcap实现在Windows操作平台上对底层数据包的捕获以及过滤。WinPcap 是 BPF 模型和 Libpcap 函数库在 Windows 平台下网络数据包捕获和网络状态分析的一种体系结构,这个体系结构是由一个核心的包过滤驱动程序,一个底层的动态连接库 Packet.dll 和一个高层的独立于系统的函数库 Libpcap 组成。C#函数库SharpPcap以及PacketDotNet就是利用封装好的winpcap进行抓包,它提供了许多基于数据包packet的功能函数接口。

3.3、应用层协议分析

利用捕获到的传输层数据包,分析其对应的端口号。再根据特定端口号判断协议类型,通过每个应用层协议报文格式进一步分析其字段的值。通过库函数自带的封装好的数据包函数接口可以实现对相应不同应用层协议类型的数据包内容的解析。

3.4、TLS/SSL

由于Packet.Net以及SharpPcap并没有HTTPS数据包的解析,所以只能自己设计出针对TLS或SSL的数据包内容解析。HTTPS端口号默认是443,通过对端口的分析得知数据包是否是HTTPS,以及对数据字段格式的分析可以解析出HTTPS数据包的诸如内容类型、协议版本、数据长度等信息

3.5、网络攻击的特征检测

本程序根据入侵检测实验课中学习到的SYN-FLOOD攻击以及NTP反射放大攻击的特征进行了检测。在本次实验中用于测试攻击的程序中,Syn-Flood攻击后的数据包的源ip地址是随机不确定的,而Ntp反射攻击后的数据包的源ip地址是确定的,也就是ntp服务器。

3.5.1、Syn-Flood攻击的特征检测

Syn-Flood通过判断捕捉到的数据包对应的Tcp协议标志位是否是SYN以及目的地址是否是本机IP,其次在当前捕捉的数据报缓冲区数组中占比是否达到百分之七十以上来判断。
其次,由于数据包缓冲区是每隔50ms读取一次,在事先测量攻击时观察到50ms内收到攻击的数据包数量是有一定要求的,即倘若50ms内读取到的数据包内容较少则并不鉴定为攻击。
流程图设计如下:

3.5.2、Ntp放大反射攻击的特征检测

Ntp放大反射攻击是通过分析数据包中UDP协议对应的源端口号是否是123,并且数据包的源ip地址是否一致的(均为Ntp Server服务器IP地址),以及数据包的目标地址是否是本机来判断。如果当前数据包缓冲区数组中满足条件的占比达到百分之七十以上则判断主机受到了Ntp放大反射攻击。与Syn-Flood相同,倘若当前读取到的数据包数量较低则不鉴定为攻击。
流程图设计如下:

3.6、实时统计分析

通过调用WinForm中的DataGridView窗口与设计更新并读取数据包多线程的委托函数来实现,DataGridView是WinForm中自带的以表格形式显示数据的窗口控件,提供了实时显示的函数接口,通常这个函数是与线程联合使用的。在本程序中,设计了一个数据包数组缓冲区,读取数据缓冲区的线程每隔50ms更新一次,每次读取时从当前缓冲区中统计每个数据包的协议内容、个数等信息,并且通过WinForm中提供的函数接口Invoke实现将读取到的统计信息实时显示到DataGrid表格中。

四、系统实现

4.1、抓包功能

C#的SharpPcap库中提供了一个CaptureDeviceList类,该类是用来获取本地已有的网络适配器的,在实例化它的一个对象之后,调用它的一个Instance参数可以获取到网络适配器device。
在捕捉数据包之前,需要选择数据采集模式,device提供了Promiscuous和Normal两种模式,前者是混杂模式,它能够接受所有经过它的数据流,无论这个数据流的目的地址是不是它,它都会接受这个数据包,后者普通模式是只接受目的地址是它的包而不接受其他的地址的网络数据包。
定义一个类型为数据包RawPacket的缓冲区链表,在开启监听事件时,将捕获到的数据包存入数据包缓冲区中。由于该操作是异步的过程,在当前线程对数据包缓冲区执行操作时,其他线程是不能访问的,在更新完缓冲区数组后释放该线程,更新周期设置为50ms。
每个缓冲区链表中存放的数据包格式为Packet,将该Packet对象作为解析函数的参数进行调用并创建各网络层协议的对象。例如数据链路层的对象为Ethernet、网络层的对象为Ipv4、传输层对象为UDP,如果根据Packet对象创建的新的各层次的对象并非null则表明此时捕捉到的数据包就是对应层次的协议。在每次更新数据包缓冲区时,首先通过库函数中提供的链路层的函数接口实现对缓冲区中每个数据包的链路层解析,解析出其源mac地址以及目的mac地址等信息。其次根据数据包再解析其网络层的协议、IP地址、版本信息。然后再解析其传输层信息,包括分析TCP还是UDP以及端口信息。
C#WinForm窗体中提供了结点树控件,捕获到的数据包个层次信息均是通过结点数显示的,利用该控件可以实现类似于Wireshark软件里解析数据包各层次内容的效果。

4.2、应用层协议分析

从传输层的数据包区分应用层协议,首先判断其传输层的端口,例如HTTP的端口号为80、SMTP的端口号为25、FTP的端口号为21或20。在分析出属于哪一种应用层协议后,再根据捕获到的数据包的字节数组内容进行解析。通过库函数中提供的函数实现,其参数即为对应的字节数组,返回值为节点树node。最后再将解析出来的node对象作为子节点添加到窗体中的结点数父类中显示。

4.3、TLS/SSL

由于本程序中库函数并没有提供HTTPS解析的函数,所以我根据数据包的字节数组自行进行了简单的解析。在数据包的传输层对象中分析其端口号的值,倘若为443则判断是HTTPS协议,根据数据包字节数组中特定位置的字段值来解析出对应的内容。HTTPS字节数组的数据载体中第一个字节代表内容类型Content Type,这是握手层。20代表Change Cipher Spec更改加密规范协议,21代表Alert警告协议,22代表HandShake握手协议,23代表Application Data应用数据协议。数据载体中第二个和第三字节代表协议版本信息,例如0303字段代表协议版本为TLSv1.2,0301代表TLSv1.0等。数据载体中第四个字节和第五个字节代表数据段的长度,后面字段的内容是详细的封装信息,包括证书以及秘钥等。

4.4、网络攻击的特征检测

根据分析抓包过程中更新的数据包缓冲区来实现,由于该数据包缓冲区是实时更新的,因此针对缓冲区的检测也是实时的。

4.4.1、Syn-Flood攻击的特征检测

定义一个int数组,长度为当前数据包缓冲区的长度,用于存放当前数据包数组中TCP报文内容的标志为SYN的个数。再定义一个string数组,用于存放缓冲区数据包中的目的地址。如果该数据包缓冲区中满足tcp标志位为syn且目的ip地址为本机的比例达到百分之七十以上则判断受到攻击,利用WinForm中的MessageBox空间进行弹窗提示。

4.4.2、Ntp放大反射攻击的特征检测

定义一个int数组,用于存放数据包缓冲区数组中UDP对应的源端口是否为123。定义两个string数组,一个用于存放数据包目的IP地址,另一个用于存放源地址。找出源地址数组中占比最大的值,用于判断是否是Ntp服务器的地址。在上述中提到过,本程序测试的Syn攻击程序发送的数据包中的源地址是随机的,而NTP攻击程序中由于本机访问一次NTP服务器,NTP服务器变以数十倍的数量发送相应数据包,所以本测试的NTP攻击中源地址均是固定的NTP服务器的地址。通过判断数据包缓冲区中,满足发送的目的地址是本机、源地址是本次缓冲区中源地址重复次数最多的、UDP对应的端口号是123这三个条件的占比达到百分之七十以上则弹窗提示收到NTP攻击。

4.5、实时统计的实现

定义一个参数类型为数据包的委托函数,用于实时显示到DataGridView表中。在每次更新数据包缓冲区的线程运行时,通过拥有控件的基础窗口句柄用指定的数据包链表执行事先定义好的用于显示的委托函数,根据数据包和索引序列号生成相应的字符串显示到窗口列表中。C#的DataGridView中提供了ADD函数的接口,该函数的参数是用于显示到表格中每一行的数据数组,通过解析数据包后的信息打包成数组后调用DataGridView控件的ADD函数将该数据包添加到新的一行中去。

五、程序演示

5.1、抓包演示

选择网络适配器,这里选择的是无线网

选择扫描模式

SharpPcap库中提供了过滤规则的函数,通过输入规则可实现过滤

点击开始按钮后执行抓包,结果如下图,包含各个层次的信息以及数据包内容

在左下角结点树中可以展开详细的各层次的信息:

传输层UDP的内容如下:

5.2、应用层协议解析演示

5.2.1、FTP

抓取到的FTP数据包如下

5.2.2、SMTP

SMTP数据包是通过在CMD控制台中输入telnet smtp.qq.com 25可以捕捉到SMTP的数据包,因为SMTP的端口号为25,在过滤器中设置过滤规则后显示的内容解析如下:

5.2.3、HTTP

在正常访问网页后可以捕捉到Http数据包,其解析内容如下

5.3、TLS/SSL演示

5.4、网络攻击

本实验中用于测试攻击的程序是在入侵检测DOS攻击实验课中使用到的两个文件

5.4.1、Syn-Flood攻击及预警演示

在cmd控制台中使用事先准备的syn-flood攻击软件在程序中可以捕捉到Syn-Flood攻击后的数据包以及弹窗提示如下:

5.4.2、Ntp放大反射攻击及预警演示

在CMD中开始ntp攻击

捕捉到的数据包以及预警提示如下:

5.5、实时统计演示

本程序中实现了一个实时统计数据包协议类型对应数量的监控窗口,如下:

六、总结

在本实验中,一大难点在于为了实现捕捉到数据包能够实时显示,需要动用多线程调用以及委托函数的相关知识,由于事先对他们的操作并不是很熟练,导致在这个地方卡了不少时间,最后在深入理解了相关实例后才自己写出来。
其次,关于SSL以及TLS要实现的功能理解出错了,本次实验中TLS以及SSL应该是要解析其签名以及加密内容的,而我只实现了特定字段值的解析。在预警功能这一方面,我事先并没有考虑到分析端口以及标志位等信息的判断,只考虑了IP地址以及占比,导致一开始的预警系统虽然能够检测到相应的攻击但是误报率很高,具体体现在我正常浏览网页时也会提示收到攻击,在后来加上对端口号以及标志位的判断后误误报率大大降低。
对预警系统的实现只考虑到了两种攻击的情况,考虑到的方面较少,并且经过老师提醒后我才了解NTP反射的源主机IP地址是可以伪造的,所以相关函数还需要一进步改进。本程序只对Syn-Flood以及NTP放大反射攻击进行了特征检测,此外其他攻击的特征检测并没有考虑。

七、部分代码展示

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using SharpPcap;
using SharpPcap.LibPcap;//引用SharpPcap
using SharpPcap.WinPcap;
using SharpPcap.AirPcap;
using System.Net.NetworkInformation;
using PacketDotNet;
using System.Management;
using System.Net;
using System.Net.Sockets;

namespace MySniffer
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
            pktInfo = new PacketInfo(this.treeView1);
            IpAddress = GetLocalIP();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            loadDevice();//加载窗体时加载网卡
            Control.CheckForIllegalCrossThreadCalls = false;
        }
        public void DetecetSynFlood(List<RawCapture> bufferList)
        {
            try
            {
                if (StartMessageBox == false)
                {
                    if (bufferList.Count < 30)
                    {
                        return;
                    }
                    int N = bufferList.Count;
                    string[] DestPortArr = new string[N];
                   int[] SourceSYN = new int[N];
                    for (int i = 0; i < N; i++)
                    {
                            Packet pp = Packet.ParsePacket(bufferList[i].LinkLayerType,
                          bufferList[i].Data);
                            IpPacket ipp = IpPacket.GetEncapsulated(pp);
                            if(ipp!=null)
                            {
                                DestPortArr[i] = ipp.DestinationAddress.ToString();
                            }
                            TcpPacket tp = TcpPacket.GetEncapsulated(pp);
                            
                            if (tp!=null)
                            {
                                bool tempbool = tp.Syn;
                                SourceSYN[i] = (tempbool == true ? 1 : 0);
                            }                  
                    }
                    int temp2 = 0;
                    for (int i = 0; i < N; i++)
                    {
                        if ((DestPortArr[i] == IpAddress)&& SourceSYN[i]==1)
                        {
                            temp2++;
                        }
                    }
                    double y = ((double)(temp2)) / ((double)(N));
                    if (y >= 0.7)
                    {
                        DialogResult answer;
                        answer = MessageBox.Show
                            ("检测到SYN FLOOD攻击");
                        if (answer == DialogResult.OK)
                        {
                            StartMessageBox = false;
                        }
                        else
                        {
                            StartMessageBox = true;
                        }
                    }
                }

            }
            catch (Exception)
            {

            }
            
          
        }
        public void DetecetNtpReply(List<RawCapture> bufferList)
        {
            if (StartMessageBox == false)
            {
                if (bufferList.Count < 5)
                {
                    return;
                }
                int N = bufferList.Count;
                string[] DestPortArr = new string[N];
                string[] SourcePortArr = new string[N];
                int[] SourcePort = new int[N];
                for (int i = 0; i < N; i++)
                {
                    Packet pp = Packet.ParsePacket(bufferList[i].LinkLayerType,
                         bufferList[i].Data);
                    IpPacket ip = IpPacket.GetEncapsulated(pp);
                    if(ip!=null)
                    {
                        DestPortArr[i]=ip.DestinationAddress.ToString();
                    }
                    UdpPacket up = UdpPacket.GetEncapsulated(pp);
                    if (up != null)
                    {
                        string temps =up.SourcePort.ToString();
                        SourcePort[i] = (temps == "123" ? 1 : 0);
                    }
                }
                var d = from n in SourcePortArr
                        group n by n into g
                        select new { Key = g.Key, Count = g.Count() };
                //找到出现次数最多的那个次数
                var max = d.Max(a => a.Count);
                int temp2 = 0;
                //根据最大的次数 查找元素
                var maxItems = from m in d where m.Count == max select m.Key;
                string Source = maxItems.First();
                for (int i = 0; i < N; i++)
                {
                    if ((SourcePortArr[i] == Source) && (DestPortArr[i] == IpAddress)
                        &&(SourcePort[i]==1))
                    {
                        temp2++;
                    }
                }
                double y = ((double)(temp2)) / ((double)(N));

                if (y >= 0.7)
                {
                    DialogResult answer;
                    answer = MessageBox.Show
                        ("检测到NTP反射放大攻击");
                    if (answer == DialogResult.OK)
                    {
                        StartMessageBox = false;
                    }
                    else
                    {
                        StartMessageBox = true;
                    }
                }
            }


        }
        string IpAddress = "";//获取本机IP地址
        ICaptureDevice device;// 定义设备
        bool StartMessageBox = false;
        List<RawCapture> packetList = new List<RawCapture>();//捕获的数据列表
        List<RawCapture> bufferList;//缓存列表
        Thread AnalyzerThread;//分析数据的线程
        Thread MonitorThread;//监控线程
        object threadLock = new object();//线程锁定
        object MonitorLock = new object();//监控线程锁定
        bool isStartAnalyzer;//用于表示是否启动分析线程的标志
        DeviceMode devMode = DeviceMode.Promiscuous;//数据采集模式,默认为混杂模式
        int readTimeOut = 50;//设置读取的时间延迟
        delegate void DataGridRowsShowHandler(RawCapture packet);
        public static string GetLocalIP()
        {
            /* var address = NetworkInterface
            .GetAllNetworkInterfaces()
            .Where(i => i.NetworkInterfaceType == NetworkInterfaceType.Wireless80211)
            .SelectMany(i => i.GetIPProperties().UnicastAddresses)
            .Where(a => a.Address.AddressFamily == AddressFamily.InterNetwork)
            .Select(a => a.Address.ToString())
            .ToList().Last();
             return address.ToString();*/
            string AddressIP = string.Empty;
            foreach (IPAddress _IPAddress in Dns.GetHostEntry(Dns.GetHostName()).AddressList)
            {
                if (_IPAddress.AddressFamily.ToString() == "InterNetwork")
                {
                    AddressIP = _IPAddress.ToString();
                }
            }
            return AddressIP;
        }

        //定义委托函数,用于实时显示捕获到的数据包
        DataBuilder rowsBulider = new DataBuilder();
        PacketInfo pktInfo;//用于分析数据包的类
        uint packetIndex = 0;
        private MonitorForm monitorform;
        int[][] DataCache = new int[4][];
        private void loadDevice()// 获取网卡方法
        {
            comDeviceList.ComboBox.DisplayMember = "Text";
            comDeviceList.ComboBox.ValueMember = "Value";
            CaptureDeviceList deviceLst = CaptureDeviceList.Instance;
            //获取主机网卡信息
            foreach (ICaptureDevice dev in deviceLst)
            {
                // AirPcap devices cannot disable local capture
                if (dev is AirPcapDevice)
                {
                    Console.WriteLine(dev.ToString());
                }
                else if (dev is WinPcapDevice)
                {
                    ClsComboboxItem clsCbxItem = new ClsComboboxItem();
                    clsCbxItem.Text = ((WinPcapDevice)dev).Interface.FriendlyName
                        + "  " + dev.Description.Split('\\'')[1];
                    clsCbxItem.Value 基于C#和RFID的智能咖啡厅系统设计与实现

基于C#和RFID的智能咖啡厅系统设计与实现

长文预警!Spring源码之IoC容器的基本实现

网络安全的自动检测与预警

网络安全预警通报关于Apache Solr反序列化远程代码执行漏洞的预警通报

监控系统之预警