• 记录基于scapy构造ClientHello报文的尝试


            最近有个需求就是用scapy构造https的client hello报文,由用户指定servername构造对应的报文。网上对于此的资料甚少,有的也是怎么去解析https报文,但是对于如果构造基本上没有找到相关的资料。

            一直觉得最好的老师就是Python的help功能和dir功能,对于这种资料比较少的最好也是去看看源码,我们可以先看看scapy对于TLS的支持能力

     有handshake,extensions等,说明基础的能力肯定是具备的,在上一篇文章中

    基于Python3的scapy解析SSL报文-CSDN博客

    我们可以看到scapy可以去解析https报文,那我想着能解析应该也具备构造的能力,所以自己先是尝试是不是和构造HTTPS差不多,在原有的报文上去修改servername。

    尝试一:在原ClientHello报文上做修改

    运行结果:

    1. serverName=b'www.baidu.com'
    2. serverName=b'www.sina.com'

    附上源码

    1. from scapy.all import *
    2. from scapy.layers.tls.all import *
    3. #from scapy_ssl_tls.ssl_tls import *
    4. load_layer("tls")
    5. srcpcap = rdpcap("https_standerd.pcapng")
    6. tlsLayer = srcpcap[3][TLS]
    7. #print(tlsLayer.layers)
    8. #print(help(tlsLayer))
    9. clientHelloPart = tlsLayer['TLS Handshake - Client Hello']
    10. #clientHelloPart = tlsLayer[TLSClientHello]
    11. serverNamePart = clientHelloPart['TLS Extension - Server Name']
    12. serverLayers = serverNamePart.servernames
    13. #serverNamePart = clientHelloPart[TLS_Ext_ServerName][ServerName]
    14. print(f"serverName={serverLayers[0].servername}")
    15. #print(f"serverNameLen={serverLayers[0].namelen}")
    16. #print(f"serverNamesLen={serverNamePart.servernameslen}")
    17. serverLayers[0].servername = b'www.sina.com'
    18. print(f"serverName={serverLayers[0].servername}")
    19. wrpcap("client_hello.pcap", srcpcap)

    来看看保存的报文能不能修改成功

     可以看到修改成功了,但是光修改这个还是不够的,因为改了servername,那整个报文的长度都要重新计算赋值。但是可以看到这样是有效的

    尝试二:从零开始构造ClientHello报文

            从零开始构造需要对scapy关于ClientHello相关的函数非常熟悉,我也尝试去读了源码,发现太复杂了,需要非常熟悉ssl的各个字段。既然网上没有相关资料,那就从chatgpt开始吧,由于墙的原因,咱就用一下国内的大模型,主要尝试了两个,一是百度家的,二是讯飞家的。

    代码

    1. from scapy.all import *
    2. # 定义协议层次
    3. ssl_client_hello = (
    4. IP(src="192.168.1.1", dst="192.168.1.2")/
    5. TCP(dport=443, flags="S")/
    6. SSL(version=0x0303, type=0x01)/
    7. SSLClientHello(version=0x0303,
    8. random=0x5778f9ac4b7b8e97ac39a0f78add5d47,
    9. cipher_suites=[
    10. 0x002f, 0x0035, 0x0033, 0x0032, 0x002f,
    11. 0x0032, 0x0031, 0x0035, 0x002d, 0x002d,
    12. 0x002f, 0x0035, 0x332e, 0x382e, 0x372e,
    13. 0x362d, 0x352d, 0x332d, 0x322d, 0x2f35,
    14. 0x2f36, 0x2f37, 0x2f34, 0x2f33, 0x2f32,
    15. 0x2f31, 0x2f35, 0x2f37, 0x2f36, 0x2f35],
    16. compression_methods=[1],
    17. extensions=[
    18. TLSExtension(type=0x14),
    19. TLSExtension(type=0x15),
    20. TLSExtension(type=0x16),
    21. TLSExtension(type=0x17),
    22. TLSExtension(type=0x18, server_name="www.baidu.com")])
    23. )
    24. # 保存报文为pcap文件
    25. wrpcap("client_hello.pcap", ssl_client_hello)

    直接运行报错,调试了版本也不好使,放弃,接着下一家

    直接运行也会报错,需要修改调试

    1. from scapy.all import *
    2. from scapy.layers.tls.all import *
    3. # 创建一个IP层数据包
    4. ip = IP(dst="www.xfyun.com")
    5. # 创建一个TCP层数据包
    6. tcp = TCP(dport=443, flags="S")
    7. # 创建一个TLSClientHello报文
    8. client_hello = TLSClientHello(version=0x0303)
    9. # 添加扩展字段,设置servername为www.xfyun.com
    10. ext = TLS_Ext_ServerName(servernameslen=len('www.xfyun.com'),servernames=[b"www.xfyun.com"])
    11. client_hello /= ext
    12. # 添加扩展字段,设置密钥共享信息
    13. keyshare = TLS_Ext_KeyShare()
    14. keyshare.group = 0x001d # FFFD (X25519)
    15. keyshare.key_exchange = b'\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
    16. client_hello /= keyshare
    17. # 添加扩展字段,设置预共享密钥信息
    18. psk = TLS_Ext_PreSharedKey()
    19. psk.identity = b'\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
    20. psk.secret = b'\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
    21. client_hello /= psk
    22. # 将各个层组合在一起
    23. packet = Ether() / ip / tcp / TLS(version=0x0303, type=0x01) / client_hello
    24. packet.show2()
    25. # 保存报文为pcap文件
    26. wrpcap("client_hello.pcap", packet)

     用wireshark打开生成的报文并不能识别成ClientHello。

    尝试三:ClientHello构造思路

    说实话在调试两个大模型的代码过程中,花费了我几乎一下午的时间,在这个过程中也熟悉了一下构造的几个函数

    TLS()

    TLSClientHello()

     大模型提供了构造的思路,但是仅仅只是填入servername,其他参数不填的话,构造出来的报文也是残缺的,那其他我们不关注的参数说实话我们也很难去构造,那我们能不能从已有的一个报文中去提取这些参数然后填入呢

    当然这只是一个思路,等后面有时间打算实践一下,目前记录一下 

  • 相关阅读:
    深入理解MySQL——配置半同步复制
    离线强化学习论文学习 Critic Regularized Regression
    使用docker简单编译k20pro内核
    MySql逗号分割的字段数据分解为多行
    vue --version无法显示,只弹出vs窗口
    pyplot设置字体格式大小、坐标轴刻度在图内
    iOS打包 rebuild from bitcode对ipa大小的影响
    uniapp使用request下载图片,并且显示出来
    聊聊 C# 和 C++ 中的 泛型模板 底层玩法
    Spring Data @Repository 的分页查询
  • 原文地址:https://blog.csdn.net/qq_27071221/article/details/134492887