这是心跳包的定义。
struct {
HeartbeatMessageType type;
uint16 payload_length;
opaque payload[HeartbeatMessage.payload_length];
opaque padding[padding_length];
} HeartbeatMessage;
不正确的payload_length
字段处理是导致心脏出血错误的原因。
然而,整个数据包本身被封装在另一个具有自己的有效负载长度的记录中,大致如下所示:
struct {
ContentType type;
ProtocolVersion version;
uint16 length;
opaque fragment[TLSPlaintext.length];
} TLSPlaintext;
结构 HeartbeatMessage 放置在上面的fragment
.
所以当根据这里字段的数据到达时,可以处理一个完整的TLS“数据包” length
,但是在内部Heartbeat消息中,openssl无法验证其payload_length
.
这是一个数据包捕获的屏幕截图,其中您可以看到外部长度 3 指定了“数据包”的长度,而内部(错误)有效负载长度 16384 是导致漏洞利用的原因,因为 openssl 无法验证这一点实际接收到的数据包长度。
![wireshark 心跳包截图](https://i.stack.imgur.com/JkyFa.png)
当然,在处理这个外部记录的字段时也必须注意类似的问题,在开始处理/解析数据包的内容之前length
,您确实需要确保您确实收到length
了数据。
另请注意,套接字读取和 TCP 段之间没有特定的相关性,1 个套接字读取可以读取许多段,或者只是一个段的一部分。对于应用程序来说,TCP 只是一个字节流,一个套接字读取最多只能读取一个 TLSPlaintext 数据包长度字段的一半,或者它可以读取几个完整的 TLSPlaintext 数据包。