2

まず、私は C プログラマーではなく、OpenSSL コードベースは巨大です。そのため、コードを掘り下げる時間とスキルがあれば、おそらく答えを見つけることができる質問をすることを許してください。

私が知る限り、TLS は TCP 上で実行されます。TCP はストリーム指向であるため、メッセージがいつ配信されたかを知る方法はありません。着信メッセージの長さを事前に把握するか、スキャンする区切り文字を指定する必要があります。

それを念頭に置いて、完全なペイロードを受信する前に、OpenSSL がハートビート リクエストを処理するにはどうすればよいでしょうか?

OpenSSL がペイロードの長さを受信した後、TCP ソケットから読み取った最初のデータ チャンクの処理を開始した場合、OpenSSL は安全でないだけでなく、通常の操作では壊れているように見えます。TCP の最大セグメント サイズは 536 バイトであるため、それより大きいペイロードは複数の TCP セグメントにまたがり、複数のソケット読み取りにまたがる可能性があります。

問題は、OpenSSL がまだ配信されていないメッセージの処理をどのように/なぜ開始できるのかということです。

4

2 に答える 2

5

これがハートビート パケットの定義です。

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

したがって、ここのフィールドに応じたデータが到着すると、1 つの TLS「パケット」全体を処理できますlengthが、内部のハートビート メッセージでは、openssl はそのpayload_length.

これはパケット キャプチャのスクリーンショットです。外側の長さ 3 が「パケット」の長さを指定し、内側の (間違った) ペイロード長 16384 がエクスプロイトの原因であることがわかります。openssl はこれを検証できなかったためです。実際に受信したパケットの長さ。

ハートビート パケットの Wireshark スクリーンショット

もちろん、この外部レコードのフィールドを処理するときも同様の注意を払う必要があります。パケットのコンテンツの処理/解析を開始する前にlength、実際にデータを受信したことを確認する必要があります。length

また、ソケットの読み取りと TCP セグメントの間に特定の相関関係がないことにも注意してください。1 つのソケットの読み取りで、多くのセグメントを読み取ることも、セグメントの一部のみを読み取ることもできます。アプリケーションにとって、TCP は単なるバイト ストリームであり、1 つのソケット読み取りで 1 つの TLSPlaintext パケットの長さフィールドの半分までしか読み取ることができないか、複数の TLSPlaintext パケット全体を読み取ることができます。

于 2014-04-18T19:13:25.943 に答える