记录基于scapy构造ClientHello报文的尝试(二)

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

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

f55ca4d5ae504e759c54a57025cd6717.png

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

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

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

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

7c0f599a8706437aac8c9302e83de533.png

运行结果:

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

附上源码

from scapy.all import *
from scapy.layers.tls.all import *
#from scapy_ssl_tls.ssl_tls import *


load_layer("tls")

srcpcap = rdpcap("https_standerd.pcapng")
tlsLayer = srcpcap[3][TLS]
#print(tlsLayer.layers)
#print(help(tlsLayer))
clientHelloPart = tlsLayer['TLS Handshake - Client Hello']
#clientHelloPart = tlsLayer[TLSClientHello]
serverNamePart = clientHelloPart['TLS Extension - Server Name']
serverLayers = serverNamePart.servernames
#serverNamePart = clientHelloPart[TLS_Ext_ServerName][ServerName]



print(f"serverName={serverLayers[0].servername}")
#print(f"serverNameLen={serverLayers[0].namelen}")
#print(f"serverNamesLen={serverNamePart.servernameslen}")


serverLayers[0].servername = b'www.sina.com'

print(f"serverName={serverLayers[0].servername}")


wrpcap("client_hello.pcap", srcpcap)

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

4aa1a90fce434768bdb22adab061d705.png

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

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

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

d5c75a6f79f448869a6ab948e0ddf2e6.png

代码

from scapy.all import *  
  
# 定义协议层次  
ssl_client_hello = (  
    IP(src="192.168.1.1", dst="192.168.1.2")/  
    TCP(dport=443, flags="S")/  
    SSL(version=0x0303, type=0x01)/  
    SSLClientHello(version=0x0303,  
                  random=0x5778f9ac4b7b8e97ac39a0f78add5d47,  
                  cipher_suites=[  
                      0x002f, 0x0035, 0x0033, 0x0032, 0x002f,  
                      0x0032, 0x0031, 0x0035, 0x002d, 0x002d,  
                      0x002f, 0x0035, 0x332e, 0x382e, 0x372e,  
                      0x362d, 0x352d, 0x332d, 0x322d, 0x2f35,  
                      0x2f36, 0x2f37, 0x2f34, 0x2f33, 0x2f32,  
                      0x2f31, 0x2f35, 0x2f37, 0x2f36, 0x2f35],  
                  compression_methods=[1],  
                  extensions=[  
                      TLSExtension(type=0x14),  
                      TLSExtension(type=0x15),  
                      TLSExtension(type=0x16),  
                      TLSExtension(type=0x17),  
                      TLSExtension(type=0x18, server_name="www.baidu.com")])  
)  
  
# 保存报文为pcap文件  
wrpcap("client_hello.pcap", ssl_client_hello)

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

f981decb94564e409bb30768eba084fc.png

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

from scapy.all import *
from scapy.layers.tls.all import *

# 创建一个IP层数据包
ip = IP(dst="www.xfyun.com")


# 创建一个TCP层数据包
tcp = TCP(dport=443, flags="S")

# 创建一个TLSClientHello报文
client_hello = TLSClientHello(version=0x0303)

# 添加扩展字段,设置servername为www.xfyun.com
ext = TLS_Ext_ServerName(servernameslen=len('www.xfyun.com'),servernames=[b"www.xfyun.com"])
client_hello /= ext

# 添加扩展字段,设置密钥共享信息
keyshare = TLS_Ext_KeyShare()
keyshare.group = 0x001d  # FFFD (X25519)
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'
client_hello /= keyshare

# 添加扩展字段,设置预共享密钥信息
psk = TLS_Ext_PreSharedKey()
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'
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'
client_hello /= psk

# 将各个层组合在一起
packet = Ether() / ip / tcp / TLS(version=0x0303, type=0x01) / client_hello
packet.show2()
# 保存报文为pcap文件  
wrpcap("client_hello.pcap", packet)

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

尝试三:ClientHello构造思路

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

TLS()

4e8cde71b040420f9887b00b77b1e049.png

TLSClientHello()

07fe279953ac4ab1bac5d1bb0777d0eb.png

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

0d1f98af5bcc48d9b1be44555500131a.png

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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
构造NA(Neighbor Advertisement)报文可以使用Scapy的IPv6和ICMPv6模块。NA报文用于告知邻居节点本机的IPv6地址和MAC地址发生了改变。构造NA报文的步骤如下: 1. 导入必要的模块: ```python from scapy.all import * ``` 2. 构造IPv6报文头: ```python ipv6 = IPv6() ipv6.dst = "ff02::1" # 目标地址为广播地址 ipv6.src = "2001:db8::1" # 源地址为本机IPv6地址 ipv6.nh = 58 # 下一跳头为ICMPv6 ``` 3. 构造ICMPv6报文头: ```python icmpv6 = ICMPv6ND_NA() icmpv6.R = 0 # Router标志位,0表示非路由器 icmpv6.S = 1 # Solicited标志位,1表示为请求的NA icmpv6.O = 1 # Override标志位,1表示覆盖原有缓存项 icmpv6.target = "2001:db8::2" # 目标地址为邻居节点的IPv6地址 icmpv6.ndopt = ICMPv6NDOptDstLLAddr(lladdr="00:11:22:33:44:55") # LLADDR选项为邻居节点的MAC地址 ``` 4. 构造完整的数据包: ```python packet = ipv6/icmpv6 ``` 5. 使用send()函数发送数据包: ```python send(packet) ``` 完整代码示例: ```python from scapy.all import * ipv6 = IPv6() ipv6.dst = "ff02::1" # 目标地址为广播地址 ipv6.src = "2001:db8::1" # 源地址为本机IPv6地址 ipv6.nh = 58 # 下一跳头为ICMPv6 icmpv6 = ICMPv6ND_NA() icmpv6.R = 0 # Router标志位,0表示非路由器 icmpv6.S = 1 # Solicited标志位,1表示为请求的NA icmpv6.O = 1 # Override标志位,1表示覆盖原有缓存项 icmpv6.target = "2001:db8::2" # 目标地址为邻居节点的IPv6地址 icmpv6.ndopt = ICMPv6NDOptDstLLAddr(lladdr="00:11:22:33:44:55") # LLADDR选项为邻居节点的MAC地址 packet = ipv6/icmpv6 send(packet) ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ftzchina

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值