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)
我的小经验: 我在项目中遇到过,目标服务器配置了防火墙,直接发SYN包会被丢弃。这时候,你可以试试用 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)
避坑指南: 我曾经在测试一个金融系统时,直接用默认的Python-Requests User-Agent发请求,结果被WAF直接拦截了。从那以后,我每次写爬虫或渗透脚本,第一件事就是伪造User-Agent。另外,注意请求频率,加个 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("[!] 无响应,可能被过滤")
核心要点: Scapy的 / 操作符是用来叠加协议层的。你可以像搭积木一样,把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
我的小技巧: 日志级别要分清楚。INFO记录正常流程,WARNING记录预期内的异常(比如端口关闭),ERROR记录真正的错误。这样你回头分析日志时,一眼就能看出问题在哪。我曾经靠日志里的一个WARNING,发现目标服务器在特定端口上返回了奇怪的banner,顺藤摸瓜找到了一个隐藏服务。

最后,记住一个原则:永远不要相信输入,永远不要假设网络是可靠的。写异常处理时,把最具体的异常写在前面,最通用的 Exception 写在最后。这样你才能精确地捕获和处理不同类型的错误。

好了,这一章的内容就到这里。Socket是地基,Requests是伪装,Scapy是武器,异常处理和日志是护甲。把这四样东西练熟了,你就能写出真正能用的渗透测试工具了。