NOOB2ROOT

CVE watch CVE-2014-0160

Heartbleed: memory disclosure in OpenSSL

A missing bounds check in the OpenSSL TLS heartbeat extension let anyone read up to 64KB of server memory per request — including private keys.

Severity
7.5
high
Vendor
OpenSSL
Disclosed
7 Apr 2014
Affected
OpenSSL 1.0.1 through 1.0.1f

CVSS breakdown

Attack vector
Network
Attack complexity
Low
Privileges required
None
User interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
None
Availability
None

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N

Analysis

Heartbleed is the vulnerability that taught a generation of defenders that patching is not the same as remediation.

TLS has a keepalive mechanism called the heartbeat extension (RFC 6520). One side sends a small payload and a number saying how long that payload is; the other side echoes it back. It exists so a session can be held open without renegotiating.

#The bug

OpenSSL took the attacker's word for the length.

The heartbeat request carries a payload_length field and the payload itself. OpenSSL read payload_length, allocated a response buffer of that size, and memcpy'd that many bytes out of the request structure — without ever checking that the request actually contained that much data.

So you send a one-byte payload and claim it is 64KB. OpenSSL copies one byte of your payload and then 65,535 bytes of whatever happened to be sitting next to it on the heap, and sends it all back to you.

The fix in 1.0.1g is the bounds check that should have been there from the start — reject the record if the claimed length exceeds what actually arrived.

#Why it was so bad

What sits next to the TLS buffers on a busy server's heap is the interesting part: session cookies, HTTP request bodies, usernames and passwords in flight, and — the reason this became a key-rotation event rather than a patching event — the server's private key.

Two properties made it worse than the CVSS 7.5 suggests. Neither integrity nor availability is affected, which caps the score, but:

  • It leaves no trace. A heartbeat is not an application-layer event. Nothing reaches the access log. There is no way to prove, after the fact, that you were not read.
  • It is repeatable. Each request returns a different 64KB slice of heap. An attacker just loops.

Because you cannot prove the key did not leak, the correct response was to assume it did.

#Detection

Retrospective detection is mostly hopeless — that is the point of the bug. What you can do:

  • Check the version. OpenSSL 1.0.1 through 1.0.1f, inclusive. 1.0.0 and earlier never had the heartbeat code and were never vulnerable.
  • At the network layer, a heartbeat response substantially larger than the request that triggered it is the signature. Most IDS signatures written in April 2014 keyed on exactly this.
  • -tlsextdebug on openssl s_client will show whether the peer advertises the heartbeat extension at all.

#Fixing it properly

The patch is step one of four, and the last three are the ones organisations skipped:

  1. Upgrade to 1.0.1g or rebuild with -DOPENSSL_NO_HEARTBEATS.
  2. Generate a new private key. Not a re-issued certificate against the old key — a new key.
  3. Revoke the old certificate. A re-issue without a revocation leaves the leaked key valid.
  4. Invalidate every active session and force credential rotation, because session cookies and passwords were in that same heap.

#What generalises

This is a length field you did not validate. The pattern shows up anywhere a protocol lets the sender describe the size of its own data — and it is the same shape of bug as CitrixBleed nine years later, which also over-read memory because a length was trusted.

The durable lesson is the incident-response one, though. When a bug leaks secrets silently, the absence of evidence of compromise is not evidence of absence. Plan for the class of vulnerability where the only safe assumption is that it worked.

References