Edited at

Heartbleedバグのコードを解説

More than 5 years have passed since last update.

今回バグってたのはheartbeat extension という機能の実装。

RFCはこちら

https://tools.ietf.org/html/rfc6520

Heartbleedバグに対する修正コミット

http://git.openssl.org/gitweb/?p=openssl.git;a=commit;h=96db9023b881d7cd9f379b0c154650d6c108e9a3


バグ解説


rfc6520


4. Heartbeat Request and Response Messages

The Heartbeat protocol messages consist of their type and an
arbitrary payload and padding.

struct {
HeartbeatMessageType type;
uint16 payload_length;
opaque payload[HeartbeatMessage.payload_length];
opaque padding[padding_length];
} HeartbeatMessage;


Request,Response共にこのHeartbeatMessageを送る。


rfc6520

   When a HeartbeatRequest message is received and sending a

HeartbeatResponse is not prohibited as described elsewhere in this
document, the receiver MUST send a corresponding HeartbeatResponse
message carrying an exact copy of the payload of the received
HeartbeatRequest.

とあるので、HeartbeatResponseを返す側は送られてきたHeartbeatRequestのペイロードをコピーして返す必要がある。

今回問題となったコードはこのペイロードコピー部分。


t1_lib.c

2591         /* Read type and payload length first */

2592 hbtype = *p++;
2593 n2s(p, payload);
2594 pl = p;
(中略)
2616 memcpy(bp, pl, payload);

HeartbeatRequestからペイロード長(コードではpayload)を取得して、HeartbeatResponseにペイロードをコピーするためにmemcpyしているが、ペイロード長について境界チェックを行っていないため、HeartbeatRequestに記載されたペイロード長が実際のペイロード長よりも長い場合 隣接するメモリの内容までmemcpy してHeartbeatResponseとして送り返してしまう。

そのため攻撃者は意図的に長いペイロード長を指定することで、1回のHeartbeatにつきメモリの内容を最大約64KB覗き見ることが可能。


修正


rfc6520

   If the payload_length of a received HeartbeatMessage is too large,

the received HeartbeatMessage MUST be discarded silently.

ペイロード長が長すぎる場合は破棄とあり、そのように修正されている。


t1_lib.c

2596         /* Read type and payload length first */

2597 if (1 + 2 + 16 > s->s3->rrec.length)
2598 return 0; /* silently discard */
2599 hbtype = *p++;
2600 n2s(p, payload);
2601 if (1 + 2 + payload + 16 > s->s3->rrec.length)
2602 return 0; /* silently discard per RFC 6520 sec. 4 */
2603 pl = p;