This is not a flaw in TLS; it is a simple memory safety bug in OpenSSL.
The best explanations I've run across so far are the blog posts Diagnosis of the OpenSSL Heartbleed Bug by Sean Cassidy and Attack of the week: OpenSSL Heartbleed by Matthew Green.
In short, Heartbeat allows one endpoint to go "I'm sending you some data, echo it back to me". You send both a length figure and the data itself. The length figure can be up to 64 KiB. Unfortunately, if you use the length figure to claim "I'm sending 64 KiB of data" (for example) and then only really send, say, one byte, OpenSSL would send you back your one byte -- and 64 KiB (minus one) of other data from RAM.
Whoops!
This allows the other endpoint to get random portions of memory from the process using OpenSSL. An attacker cannot choose which memory, but if they try enough times, their request's data structure is likely to wind up next to something interesting, such as your private keys, or users' cookies or passwords.
None of this activity will be logged anywhere, unless you record, like, all your raw TLS connection data.
Not good.
The above xkcd comic does a nice job illustrating the issue.
Edit: I wrote in a comment below that the heartbeat messages are encrypted. This is not always true. You can send a heartbeat early in the TLS handshake, before encryption has been turned on (though you're not supposed to). In this case, both the request and response will be unencrypted. In normal usage, heartbeats ought to always be sent later, encrypted, but most exploit tools will probably not bother to complete the handshake and wait for encryption. (Thanks, RedBaron.)