It starts with this piece of good-intention paving for the current https:// roads to hell:
So we’re introducing a heartbeat, a transmission which seeks to keep the established (secure) lines of communication open (otherwise they get shut down if you’re “quiet” for too long and don’t transmit anything… which means back to square one with all the security handshakes the next time you get in touch).
Seems like a good idea, and becomes an extension on the Open SSL libraries… that workhorse for https and other secure applications. We know it’s an extension because, as it turns out (according to OpenSSL) you can (thankfully) yank out this functionality out altogether by recompiling the source code with a switch aptly named DOPENSSL_NO_HEARTBEATS.
As it happens, ideas expressed in IETF docs and their implementations are two different things. In this case, the implementation of rfc 6520 in Open SSL created a security flaw that frolicked happily out in the wild for about 2 years before headlines found it. It’s name is Heartbleed. And Oh! It was due to a such a classic programming 101 misstep that it really is quite amazing that it got past hoops/reviews and got checked in. Witness:
There are 2 main issues here.
The cardinal rule of NEVER TRUST YOUR INPUTS was temporarily forgotten. In short, the attacker sends a heartbeat request and *SAYS* that the payload in their request is N bytes long.
The programmer trusts what the attacker said… without checking the actual length of the payload in question, and then proceeds to copy N bytes of worth of payload from the request straight into the response that they are busily cobbling together. The received request object is presumably lying around in the same working memory where all the security goodies like usernames, passwords, session keys/encryption keys etc are milling about, for the Server’s eyes only. So if that payload isn’t N bytes long as promised, but waaaay shorter, this bit of C++ code kicks its programmer in the balls by letting them read way past the “end” of the actual payload in memory… eventually reading lots of sensitive stuff lying around nearby… and copying that stuff into the response and sending it right back to the attacker!!
C/C++’s swift ninja-kicks to the proverbials are well known. This is why one of the first things C projects wrap themselves in are soft cushiony layers of abstraction from such low-level utilities as memcpy and it’s evil twin malloc. C and C++ memory functions are not to be trifled with… especially in conjuction with pointers. Looking at the code, it plays fast and loose with both things. True, it’s not much point having language features and not using them, but still…
I’m not even sure why we’re writing straight to memory in this case… It’s hard to believe such a high profile open source project doesn’t have in its libraries something that models heartbeat message types and related message entities, with the appropriate handlers / setters / getters. Ultimately, this contributor had to basically roll his own code for doing such low-level stuff. Bad, bad, bad…
Interestingly, I don’t think I saw this type of security flaw (overruns) discussed in either of the IETF’s rfc5246 (for TLS) or rfc4347-bis-06 (related to DTLS)…