You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Scapy发送SYN后无法接收SYN+ACK,但telnet可正常工作

解决Scapy TCP三次握手脚本本地回环失效的问题

嘿,我帮你梳理下这个Scapy三次握手脚本的问题,毕竟我踩过不少类似的坑😉。你遇到的情况很典型:本地nc监听正常,curl/telnet能连,但Scapy脚本就是跑不通,还输出奇怪的终端路径内容,大概率是这几个原因导致的:

1. Scapy默认没适配本地回环接口

本地回环(127.0.0.1)的数据包走的是内核内部路径,Scapy默认的socket可能没正确捕获或发送这些包。解决办法很简单:

  • 在脚本开头添加配置,强制Scapy使用正确的三层socket:
    from scapy.all import conf
    conf.L3socket = conf.L3socket6 if conf.ipv6_enabled else conf.L3socket
    
  • 发送/接收包时明确指定回环接口iface="lo",避免Scapy选错网卡。

2. TCP序列号/确认号没同步

很多旧的Scapy脚本会硬编码序列号,或者没正确计算ACK包的确认号。服务器的SYN-ACK包携带的序列号是随机的,你必须用这个序列号+1作为ACK包的确认号,同时用SYN-ACK里的确认号作为ACK包的序列号。比如:

# 发送SYN包
syn = IP(dst="127.0.0.1")/TCP(dport=5555, flags="S")
syn_ack = sr1(syn, iface="lo", timeout=2, verbose=0)  # verbose=0关闭冗余输出
if syn_ack:
    # 正确计算ACK包的seq和ack
    ack = IP(dst="127.0.0.1")/TCP(dport=5555, flags="A", seq=syn_ack.ack, ack=syn_ack.seq + 1)
    send(ack, iface="lo", verbose=0)

3. 系统内核发送RST包干扰握手

当Scapy发起SYN包后,系统内核发现这个连接不是自己创建的,会自动发送RST包终止连接,直接打断握手流程。你可以用iptables临时拦截回环的RST包:

sudo iptables -A OUTPUT -o lo -p tcp --tcp-flags RST RST -d 127.0.0.1 -j DROP

测试完成后记得删掉这条规则,避免影响其他本地连接:

sudo iptables -D OUTPUT -o lo -p tcp --tcp-flags RST RST -d 127.0.0.1 -j DROP

4. 脚本冗余输出导致混淆

你提到脚本输出显示ubunt@ubunt-MS-7A94:~/Desk...,这应该是Scapy默认的sr/sr1函数输出了调试信息,或者脚本里的打印逻辑有问题。只要在调用sr1和send时加上verbose=0,就能关掉这些杂乱的输出,只保留你自己的日志。

完整测试脚本

这里给你一个修改后的可直接运行的版本,你可以替换原来的脚本试试:

from scapy.all import IP, TCP, sr1, send, conf

# 适配本地回环的socket配置
conf.L3socket = conf.L3socket6 if conf.ipv6_enabled else conf.L3socket

# 目标参数
TARGET_IP = "127.0.0.1"
TARGET_PORT = 5555

# 发送SYN包
print(f"发起SYN请求到 {TARGET_IP}:{TARGET_PORT}")
syn_pkt = IP(dst=TARGET_IP)/TCP(dport=TARGET_PORT, flags="S", seq=1000)
syn_ack_pkt = sr1(syn_pkt, iface="lo", timeout=3, verbose=0)

if syn_ack_pkt:
    print(f"收到SYN-ACK:seq={syn_ack_pkt.seq}, ack={syn_ack_pkt.ack}")
    # 构造并发送ACK包完成握手
    ack_pkt = IP(dst=TARGET_IP)/TCP(dport=TARGET_PORT, flags="A", seq=syn_ack_pkt.ack, ack=syn_ack_pkt.seq + 1)
    send(ack_pkt, iface="lo", verbose=0)
    print("✅ TCP三次握手完成!")
else:
    print("❌ 未收到SYN-ACK,握手失败")

测试时先启动nc -l 5555,再运行这个脚本,同时可以用tcpdump -i lo port 5555抓包验证握手流程是否正常。

内容的提问来源于stack exchange,提问作者Mindaugas Bernatavičius

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 08:26:23