3、Python安全编程基础:Socket编程、Requests库高级用法、Scapy数据包构造、异常处理与日志
各位同学,咱们今天聊点硬核的。Python在渗透测试里,说白了就是一把瑞士军刀。你光会用现成的工具,那叫脚本小子。能自己写工具,才叫入门。这一章,我带你把这把刀磨快。
我个人习惯,写任何安全脚本前,先把异常处理和日志架子搭好。为什么?因为渗透测试环境太脏了。目标可能随时断连,数据包可能被截断,API可能返回一堆乱码。没有健壮的异常处理,你的脚本跑一半就崩了,那叫一个尴尬。
3.1 Socket编程:从零搭一个侦察兵
Socket,说白了就是网络通信的管道。你想想看,渗透测试里最基础的操作——端口扫描、服务识别、甚至简单的反弹Shell,底层都是Socket在干活。
我建议你从TCP客户端写起。别一上来就搞什么异步框架,先把基础打牢。
import socket
def tcp_scan(target, port):
try:
# 创建一个TCP套接字
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置超时,别让脚本卡死
s.settimeout(2)
# 尝试连接
result = s.connect_ex((target, port))
if result == 0:
print(f"[+] 端口 {port} 开放")
else:
print(f"[-] 端口 {port} 关闭")
s.close()
except socket.error as e:
print(f"[!] Socket错误: {e}")
except Exception as e:
print(f"[!] 未知错误: {e}")
# 扫描一下本地
tcp_scan('127.0.0.1', 80)
connect_ex 而不是 connect,它不会抛异常,而是返回错误码。这样你就能更优雅地处理各种网络状况。
嗯,这里要注意。写Socket服务端的时候,一定要处理粘包问题。我曾经写一个简单的后门,客户端发数据太快,服务端一次recv只读到一半,结果解析数据全乱了。解决方案很简单:要么固定报文长度,要么在报文头里标明数据长度。
def recv_exactly(sock, length):
"""精确接收指定长度的数据"""
data = b''
while len(data) < length:
chunk = sock.recv(length - len(data))
if not chunk:
raise ConnectionError("连接断开")
data += chunk
return data
3.2 Requests库高级用法:伪装的艺术
Requests库,大家都会用。但渗透测试里,你不能像个老实人一样直接发请求。你得学会伪装。
为什么?因为WAF(Web应用防火墙)会盯着你看。你发请求的User-Agent、Cookie、请求频率,任何一个不对劲,人家就把你封了。
我建议你建立一个Session对象,用它来维持会话。这样你登录后的Cookie会自动带上,不用每次都手动处理。
import requests
# 创建一个会话,保持Cookie
session = requests.Session()
# 设置一个像真实浏览器的User-Agent
session.headers.update({
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
})
# 先登录
login_data = {'username': 'admin', 'password': 'test123'}
session.post('https://target.com/login', data=login_data)
# 然后访问需要认证的页面
response = session.get('https://target.com/dashboard')
print(response.text)
time.sleep(),别把目标打挂了。
Requests库还有一个高级用法——流式下载。如果你在渗透测试中需要下载大文件(比如一个数据库备份),用 stream=True 可以避免内存爆炸。
response = requests.get('https://target.com/bigfile.zip', stream=True)
with open('bigfile.zip', 'wb') as f:
for chunk in response.iter_content(chunk_size=8192):
if chunk:
f.write(chunk)
3.3 Scapy数据包构造:网络层的瑞士军刀
Scapy,这玩意儿太强了。你可以用它构造任何你想要的网络数据包。从ARP欺骗到TCP SYN Flood,从DNS查询到ICMP隧道,全都能搞定。
我个人习惯,在写任何网络工具前,先用Scapy在本地搭个实验环境。你想想看,你写一个端口扫描器,总不能直接往生产环境上怼吧?
from scapy.all import *
# 构造一个TCP SYN包
ip = IP(dst="192.168.1.1")
tcp = TCP(sport=RandShort(), dport=80, flags="S")
packet = ip / tcp
# 发送并等待响应
response = sr1(packet, timeout=2)
if response:
if response.haslayer(TCP):
if response.getlayer(TCP).flags == 0x12: # SYN-ACK
print("[+] 端口 80 开放")
elif response.getlayer(TCP).flags == 0x14: # RST
print("[-] 端口 80 关闭")
else:
print("[!] 无响应,可能被过滤")
/ 操作符是用来叠加协议层的。你可以像搭积木一样,把IP层、TCP层、甚至应用层数据拼在一起。这种灵活性,是其他网络库比不了的。
嗯,这里要提醒你。用Scapy发原始数据包,通常需要root权限。我在Kali Linux上跑没问题,但如果你在Windows上,记得装Npcap驱动。我曾经在Windows上折腾了半天,才发现是驱动没装对。
3.4 异常处理与日志:让你的脚本活得更久
渗透测试脚本,跑在不可控的环境里。网络超时、连接重置、数据解析失败,这些都是家常便饭。没有异常处理,你的脚本就是个脆皮。
我建议你养成一个习惯:任何可能出错的代码,都用try-except包起来。但别滥用,别把整个脚本都塞进一个try里,那样你根本不知道哪里出了问题。
import logging
import sys
# 配置日志,输出到文件和控制台
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('pentest.log'),
logging.StreamHandler(sys.stdout)
]
)
def safe_scan(target, port):
try:
s = socket.socket()
s.settimeout(3)
s.connect((target, port))
logging.info(f"端口 {port} 开放")
s.close()
except socket.timeout:
logging.warning(f"端口 {port} 超时")
except ConnectionRefusedError:
logging.debug(f"端口 {port} 被拒绝")
except Exception as e:
logging.error(f"扫描端口 {port} 时出错: {e}")
finally:
# 确保资源释放
try:
s.close()
except:
pass
最后,记住一个原则:永远不要相信输入,永远不要假设网络是可靠的。写异常处理时,把最具体的异常写在前面,最通用的 Exception 写在最后。这样你才能精确地捕获和处理不同类型的错误。
好了,这一章的内容就到这里。Socket是地基,Requests是伪装,Scapy是武器,异常处理和日志是护甲。把这四样东西练熟了,你就能写出真正能用的渗透测试工具了。