解决问题思路

利用Python编程实现对wrk的泛洪攻击检测,并让程序触发调用Linux命令实现防御:

1、泛洪攻击的检测,可以考虑使用的命令,这些命令可以通过Python进行调用和分析。
(1) netstat -ant | wc -l
(2) netstat -ant | grep SYN_RECV
(3) netstat -s | grep overflowed
(4) netstat -s | grep dropped
(5)top -n 1 获取CPU的使用率
以上操作过程的命令,允许使用管道和AWK等技术提取数据,也可以直接使用Python进行数据提取。

2、防御措施可以选择以下几种:
(1)修改系统配置参数,来增加系统的TCP连接数
(2)直接结束某些消耗CPU的进程,或者停止Apache的服务
(3)开启防火墙,将目标IP地址进行封锁
(4)自行查阅资料,进行其他可行的操作

上述Python代码实现的核心就是调用系统命令,再通过Python进行分析,触发命令的执行等。建议在Linux上安装Python3.7及以上的版本。

基本步骤:
1、确保在Linux上可以正常运行Python3,而CentOs内置的是Python2.7
2、做基本的调研,明确对于DOS的入侵检测,需要使用哪些方法或命令
3、将可以使用的命令通过Python来运行,并进行调试,确保Python+命令可以正常工作

可以直接使用命令提取数据,如使用grep,awk,或sort等,也可以直接使用Python解析字符串的方式提取数据。

4、想办法找到连接数最多的攻击源IP地址,驱动Linux的防火墙进行入侵防御
5、最后进行整合,测试,再模拟攻击,来确保脚本本身可以正常检测

一、在CentOS上安装Python3

1、下载Python3.10源代码文件

下载地址:https://www.python.org/downloads/source/

1772973312765

2、运行以下命令完成安装过程

1772973162528

mkdir /usr/local/python3
tar -zxvf Python-3.12.13.tgz 
cd Python-3.12.13/
./configure --prefix=/usr/local/python3  # 指定python安装的路径
make #对源代码进行编译
make install

1772973700474

1772974028269

3、确认是否安装成功

[root@localhost python3]# /usr/local/python3/bin/python3
Python 3.12.13 (main, Mar  8 2026, 20:49:25) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import time       
>>> print(time.time())
1772974648.9474528

1772974683543

4、设置环境变量

编辑用户主目录下的~/.bash_profile文件,设置PATH环境变量

[root@localhost ~]# vi .bash_profile 
[root@localhost ~]# source ~/.bash_profile 

1772975036157
编辑完成后,运行source ~/.bash_profile使环境变量生效,然后可以在命令行直接执行python3和pip3即可

二、理解各个命令的含义

1、uptime

uptime命令用于查看主机的开机时长,用户连接数量,以及在1、5、15分钟三段时间内,CPU的负载情况。

1772336025063

2.netstat

netstat命令用来打印Linux中网络系统的状态信息,可让你得知整个Linux操作系统的网络情况。需要注意的是在Windows和Linux上的参数会略有不同。

以数字方式列出所有TCP连接情况:netstat -ant
以数字方式列出所有UDP连接情况:netstat -anu
以数字方式列出所有TCP和UDP处理监听状态的情况:netstat -anult
显示所有端口的统计信息:netstat -s
显示TCP端口的统计信息:netstat -st
显示核心路由信息:netstat -r
显示所有连接的进程信息:netstat -ap

1772345011960

以数字方式列出所有TCP和UDP处理监听状态的情况:netstat -anult

1772345094208

在kali上做DOS攻击:

1772345621000

查看攻击信息:

1772345652315

3.ss

用来显示处于活动状态的套接字信息。ss命令可以用来获取socket统计信息,它可以显示和netstat类似的内容。但ss的优势在于它能够显示更多更详细的有关TCP和连接状态的信息,而且比netstat更快速更高效。

显示监听状态下的队列情况:ss -lnt
显示非监听状态下的连接详情:ss -nt
显示socket摘要信息:ss -s

LISTEN状态:Recv-Q表示的当前等待服务端调用accept完成三次握手的listenbacklog数值,也就是说,当客户端通过connect)去连接正在listen()的服务端时,这些连接会一直处于这个queue里面直到被服务端accepto;Send-Q表示的则是最大的listenbacklog数值,这就就是上面提到的min(backlog,somaxconn)的值。

非 LISTEN状态:Recv-Q表示receive queue 中的 bytes数量;Send-Q表示send queue 中的 bytes 数值,该数值意义不大,更多关注连接的数量和状态即可。

1772346611781

1772346691312

4.firewall-cmd

关闭防火墙:systemctl stop firewalld
添加允许端口:firewall-cmd --add-port=80/tcp
列出防火墙规则:firewall-cmd --list-all
禁止IP地址访问80端口:firewall-cmd --add-rich-rule='rule family="ipv4" source address="192.168.112.148" port port="80" protocol="tcp" reject'
让配置永久生效:添加允许端口:firewall-cmd --add-port=80/tcp --permanent

5.sysctl

sysctl命令用于运行时配置内核参数,这些参数位于/proc/sys目录下。sysct配置与显示在/proc/sys目录中的内核参数,可以用sysctl来设置或重新设置联网功能,如IP转发、IP碎片去除以及源路由检查等。用户只需要编辑/etc/sysctl.conf文件,即可手工或自动执行由sysctl控制的功能。

1772345981265

1772346068735

显示所有系统参数:sysctl -a
使用cat查看指定参数:cat /proc/sys/net/ipv4/ip_forward, 除/proc/sys外,后面的路径与参数名称一致,.换成/即可
临时改变某个指定参数的值,如:sysctl -w net.ipv4.ip_forward=1,也可以:echo 1 > /proc/sys/net/ipv4/ip_forward
如果想永久保留配置,可以修改/etc/sysctl.conf文件

快速修改部分参数,优化性能:

net.ipv4.tcp_syncookies:   是否打开SYN COOKIES的功能,“1”为打开,“2”关闭。
net.ipv4.tcp_max_syn_backlog:  SYN队列的长度,加大队列长度可以容纳更多等待连接的网络连接数。
net.ipv4.tcp_synack_retries 和 net.ipv4.tcp_syn_retries: 定义SYN重试次数,默认为5,建议为2
net.ipv4.sack=0

1772346421482

1772346450951

1772346480971

三、代码获取信息

1.获取值

[root@localhost pycode]# uptime
 21:47:39 up  1:18,  2 users,  load average: 0.08, 0.22, 0.28
[root@localhost pycode]# uptime | awk -F ": " '{print $2}'
0.04, 0.19, 0.27
[root@localhost pycode]# uptime | awk -F ": " '{print $2}' | awk -F "," '{print $1}'
0.03

1772977757120

全选快捷键
vi/vim 编辑器:按Esc键确保处于正常模式,输入gg将光标移至文件开头,按下Shift + V进入行可视模式,再输入G即可选中全部内容。也可以使用命令:1,$ y复制全文,或:%y a将全文复制到寄存器a中。

# -*- coding: utf-8 -*-
import os, time


# 第一步:先采集跟DOS攻击关联度较高的数据
def get_cpu():
    # 1、采集CPU的平均负载
    uptime = os.popen('uptime').read()
    uptime = uptime.replace(": ", ",")
    cpu_load = float(uptime.split(",")[-3])

    # 利用awk命令来提取CPU负载
    cpu_load = os.popen("uptime | awk -F ': ' '{print $2}' | awk -F ',' '{print $1}'").read()
    cpu_load = float(cpu_load)
    return cpu_load

# 2、采集netstat -ant 的连接数量
def get_conn_count():
    netstat = os.popen("netstat -ant | wc -l").read()
    return int(netstat)

# 3、采集队列长度
def get_queue_size():
    sslnt = os.popen("ss -lnt | grep :80").read()
    recvq = int(sslnt.split()[1])
    sendq = int(sslnt.split()[2])
    return recvq, sendq

if __name__ == '__main__':
    while True:
        cpu = get_cpu()
        conn = get_conn_count()
        recvq, sendq = get_queue_size()
        print(f"CPU-Load:{cpu}, TCP Conn:{conn}, TCP Queue:{recvq, sendq}")

        # 对采集到的数据进行判断,并进行预警提醒
        if cpu > 50 and conn > 500 and recvq > sendq - 10 :
            print("当前系统TCP连接负载过重,存在DOS攻击的可能性。")

        time.sleep(2)

编写好代码之后,在kali实施攻击:

1772979340586

在被攻击主机上查看CPU负载情况:

1772979424426

1772981050221

采集连接数量最多的IP地址

1773062406955

完整python代码

# -*- coding: utf-8 -*-
import os, time


# 第一步:先采集跟DOS攻击关联度较高的数据
from collections import Counter


def get_cpu():
    # 1、采集CPU的平均负载
    uptime = os.popen('uptime').read()
    uptime = uptime.replace(": ", ",")
    cpu_load = float(uptime.split(",")[-3])

    # 利用awk命令来提取CPU负载
    cpu_load = os.popen("uptime | awk -F ': ' '{print $2}' | awk -F ',' '{print $1}'").read()
    cpu_load = float(cpu_load)
    return cpu_load

# 2、采集netstat -ant 的连接数量
def get_conn_count():
    netstat = os.popen("netstat -ant | wc -l").read()
    return int(netstat)

# 3、采集队列长度
def get_queue_size():
    sslnt = os.popen("ss -lnt | grep :80").read()
    recvq = int(sslnt.split()[1])
    sendq = int(sslnt.split()[2])
    return recvq, sendq

# 4、采集连接数量最多的IP地址
def get_most_ip():
    reslut = os.popen("netstat -ant | grep :80").read()
    line_list = reslut.split('\n')
    ip_list = []
    for line in line_list:
        try:
            temp_list = line.split()
            ip = temp_list[4].split(':')[0]
            ip_list.append(ip)
        except:
            pass

    dict = Counter(ip_list)
    most_ip = dict.most_common(1)
    return most_ip[0][0]

#5、调用firewall-cmd防火墙命令封锁攻击源IP地址
def firewall_ip(ip):
    result = os.popen(f"firewall-cmd --add-rich-rule='rule family=ipv4 source address={ip} port port=80 protocol=tcp reject' ")
    if 'success' in result:
        print(f'已经成功将可疑攻击源{ip}进行封锁')
    else:
        print(f'对可疑{ip}进行封锁失败,请人工处理')

if __name__ == '__main__':
    while True:
        cpu = get_cpu()
        conn = get_conn_count()
        recvq, sendq = get_queue_size()
        most_ip = get_most_ip()
        print(f"CPU-Load:{cpu}, TCP Conn:{conn}, TCP Queue:{recvq, sendq}")

        # 对采集到的数据进行判断,并进行预警提醒
        if cpu > 50 and conn > 500 and recvq > sendq - 10 :
            print(f"当前系统TCP连接负载过重,存在DOS攻击的可能性,可能的IP地址:{most_ip}")

        time.sleep(2)

注:解除ip地址的封锁

firewall-cmd --remove-rich-rule='rule family=ipv4 source address={ip} port port=80 protocol=tcp reject'

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐