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

通过Scapy结合专属私钥解密TLS1.3 HTTPS流量的技术问询

问题说明
  • 需求:在自有服务器上使用Scapy解密归属自有域名的HTTPS流量,已持有该域名正规签发的TLS1.3证书及对应私钥。
  • 已验证无效方案:scapy-ssl_tls、Scapy官方TLS解析示例notebook、TSHARK、各类MITM方案、SSLDUMP,以上方案运行无报错、无崩溃,但无法完成解密。
  • 现有报错:自行编写的测试代码运行抛出ValueError: ciphertext length must be equal to key size错误,调试后未定位根因与修复方案,测试代码如下:
import os, sys
import ssl
from scapy import *
from scapy.all import *
from scapy.layers import *
from scapy.layers.tls import *
from scapy.layers import inet
from scapy.layers.inet import *
import socket, select
import binascii
import io
from io import StringIO

load_layer("tls")
c = Cert("SSL/STAR_mydomain_com.crt")
k=PrivKey("SSL/private.key")

########### Unit-Test Encrypt/Decrypt Run OK ########### 
#M = bytes("message to be encrypted".encode())
#enc = c.encrypt(M, t='oaep')
#print(enc)
#dec = k.decrypt(enc, t='oaep')
#print(dec)

while True:
    s = sniff(filter="port 443", count=10)
    ch_list = [p for p in s]
    if len(ch_list)>0:
        for pkt in ch_list:
            p_layer = pkt.getlayer('IP')
            src = p_layer.src
            dst = p_layer.dst
            if (src=='my-server-ip') or (dst=='my-server-ip'):
                if ('TLSEncryptedContent' in str(type(pkt['TCP'].payload))):
                    
                    ########### any 3 below commands go in same error ############## 
                    ########### and i was try 'pss' instead of 'oaep' but same error 
                    
                    dec2 = k.decrypt(pkt['TCP'].payload, t='oaep')
                    #dec2 = k.decrypt(bytes(pkt['TCP'].payload), t='oaep')
                    #dec2 = k.decrypt(bytes(pkt['TCP'].payload).decode('UTF8', 'replace'), t='oaep')
                    
                    print(dec2)
                
    else:
        print('...passed')

注:不需要TLS1.3解密原理性解释,已知该能力可实现(如Palo Alto PAN-OS已支持TLS1.3流量解密),仅需可落地的代码片段或参考实现。

错误原因

原有代码逻辑错误:直接使用RSA私钥解密TLSEncryptedContent应用层载荷。TLS1.3应用数据由握手阶段派生的对称会话密钥加密,RSA私钥仅用于握手阶段的签名验证(TLS1.3默认ECDHE密钥交换场景)或解密预主密钥(仅旧版RSA密钥交换场景使用,TLS1.3已废弃),无法直接解密应用层加密内容,因此触发密文长度与密钥长度不匹配错误。

可落地实现代码

前置依赖

  • 安装Scapy版本 >= 2.5.0,旧版本TLS1.3解密逻辑存在缺陷
  • 抓包动作必须早于TLS连接建立时间,需捕获完整的握手流程(Client Hello到Server Finished全量报文),缺失握手报文无法派生会话密钥
from scapy.all import *
from scapy.layers.tls import TLS, TLSApplicationData

load_layer("tls")

# 配置参数
SERVER_IP = "替换为你的服务器公网IP"
CERT_PATH = "SSL/STAR_mydomain_com.crt"
PRIV_KEY_PATH = "SSL/private.key"
LISTEN_FILTER = f"tcp port 443 and host {SERVER_IP}"

# 加载服务端证书与私钥
server_cert = Cert(CERT_PATH)
server_privkey = PrivKey(PRIV_KEY_PATH)

def parse_tls_pkt(pkt):
    if IP not in pkt or TCP not in pkt:
        return
    # 过滤非本机收发的流量
    if pkt[IP].src != SERVER_IP and pkt[IP].dst != SERVER_IP:
        return
    try:
        # 传入服务端密钥材料,由Scapy自动完成握手解析、会话密钥派生、流量解密
        decrypted_tls = pkt[TLS](server_key=server_privkey, server_cert=server_cert)
        # 输出解密后的应用层明文
        if TLSApplicationData in decrypted_tls:
            src_info = f"{pkt[IP].src}:{pkt[TCP].sport}"
            dst_info = f"{pkt[IP].dst}:{pkt[TCP].dport}"
            print(f"[{src_info} -> {dst_info}] 解密明文:")
            print(decrypted_tls[TLSApplicationData].data)
            print("-" * 60)
    except Exception:
        # 自动跳过重传包、分片包、不完整TLS包
        pass

if __name__ == "__main__":
    print("开始监听443端口TLS流量,捕获完整握手后将自动输出解密明文...")
    sniff(
        filter=LISTEN_FILTER,
        prn=parse_tls_pkt,
        session=TLSSession  # 启用TLS会话跟踪,自动维护跨包的会话状态
    )
运行说明
  • 代码默认支持TLS1.3 1-RTT模式流量解密,若服务端开启0-RTT,需在TLS初始化参数中补充0-RTT密钥配置
  • TLS1.3默认使用ECDHE密钥交换,代码会自动通过私钥验证握手签名,结合客户端/服务器随机数、ECDHE公钥材料派生对称会话密钥,无需额外配置
  • 若解密失败,优先确认是否捕获了完整握手流程,其次确认证书与私钥匹配、Scapy版本符合要求。

内容的提问来源于stack exchange,提问作者Eyni Kave

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.17 16:16:01