Heartbleedバグのコードを解説

  • 160
    Like
  • 0
    Comment
More than 1 year has 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;