Bloody Cert Certified
Oh, Information Disclosure vulnerabilities. Truly the Rodney Dangerfield of vulns, people never quite know what their impact is going to be. With Memory Corruption, we’ve basically accepted that a sufficiently skilled attacker always has enough degrees of freedom to at least unreliably achieve arbitrary code execution (and from there, by the way, to leak arbitrary information like private keys). With Information Disclosure, even the straight up finder of Heartbleed has his doubts:
So, can Heartbleed leak private keys in the real world or not? The best way to resolve this discussion is PoC||GTFO (Proof of Concept, or you can figure out the rest). CloudFlare threw up a challenge page to steal their key. It would appear Fedor Indutny and Illkka Mattila have successfully done just that. Now, what’s kind of neat is that because this is a crypto challenge, Fedor can actually prove he pulled this off, in a way everyone else can prove but nobody else can duplicate.
I’m not sure if key theft has already occurred, but I think this fairly conclusively establishes key theft is coming. Lets do a walk through:
First, we retrieve the certificate from http://www.cloudflarechallenge.com.
$ echo “” | openssl s_client -connect www.cloudflarechallenge.com:443 -showcerts | openssl x509 > cloudflare.pem
depth=4 C = SE, O = AddTrust AB, OU = AddTrust External TTP Network, CN = AddTrust External CA Root
verify error:num=19:self signed certificate in certificate chain
This gives us the certificate, with lots of metadata about the RSA key. We just want the key.
$ openssl x509 -pubkey -noout -in cloudflare.pem > cloudflare_pubkey.pem
Now, we take the message posted by Fedor, and Base64 decode it:
$ wget https://gist.githubusercontent.com/indutny/a11c2568533abcf8b9a1/raw/1d35c1670cb74262ee1cc0c1ae46285a91959b3f/1.bash
–2014-04-11 18:14:48– https://gist.githubusercontent.com/indutny/a11c2568533abcf8b9a1/raw/1d35c1670cb74262ee1cc0c1ae46285a91959b3f/1.bash
Resolving gist.githubusercontent.com… 18.104.22.168
Connecting to gist.githubusercontent.com|22.214.171.124|:443… connected.
HTTP request sent, awaiting response… 200 OK
Length: unspecified [text/plain]
Saving to: `1.bash’
[ <=> ] 456 –.-K/s in 0s
2014-04-11 18:14:49 (990 KB/s) – `1.bash’ saved 
$ cat 1.bash
> echo “Proof I have your key. firstname.lastname@example.org” | openssl sha1 -sign key.pem -sha1 | openssl enc -base64
$ cat 1.bash | grep -v fedor | openssl enc -d -base64 > fedor_signed_proof.bin
So, what do we have? A message, a public key, and a signature linking that specific message to that specific public key. At least, we’re supposed to. Does OpenSSL agree?
$ echo “Proof I have your key. email@example.com” | openssl dgst -verify cloudflare_pubkey.pem -signature fedor_signed_proof.bin -sha1
Ah, but what if we tried this for some other RSA public key, like the one from Google?
$ echo “” | openssl s_client -connect www.google.com:443 -showcerts | openssl x509 > google.pem
depth=2 C = US, O = GeoTrust Inc., CN = GeoTrust Global CA
verify error:num=20:unable to get local issuer certificate
$ openssl x509 -pubkey -noout -in google.pem > google_pubkey.pem
$ echo “Proof I have your key. firstname.lastname@example.org” | openssl dgst -verify google_pubkey.pem -signature fedor_signed_proof.bin -sha1
Or what if I changed things around so it looked like it was me who cracked the code?
$ echo “Proof I have your key. email@example.com” | openssl dgst -verify cloudflare_pubkey.pem -signature fedor_signed_proof.bin -sha1
Nope, it’s Fedor or bust :) Note that it’s a common mistake, when testing cryptographic systems, to not test the failure modes. Why was “Verified OK” important? Because “Verification Failure” happened when our expectations weren’t met.
There is, of course, one mode I haven’t brought up. Fedor could have used some other exploit to retrieve the key. He claims not to have, and I believe him. But that this is a failure mode is also part of the point — there have been lots of bugs that affect something that ultimately grants access to SSL private keys. The world didn’t end then and it’s not ending now.
I am satisfied that the burden of proof for Heartbleed leaking private keys has been met, and I’m sufficiently convinced that “noisy but turnkey solutions” for key extraction will be in the field in the coming weeks (it’s only been ~3 days since Neel told everyone not to panic).
Been getting emails asking for what the appropriate response to Heartbleed is. My advice is pretty exclusively for system administrators and CISOs, and is something akin to “Patch immediately, particularly the systems exposed to the outside world, and don’t just worry about HTTP. Find anything moving SSL, particularly your SSL VPNs, prioritizing on open inbound, any TCP port. Cycle your certs if you have them, you’re going to lose them, you may have already, we don’t know. But patch, even if there’s self signed certs, this is a generic Information Leakage in all sorts of apps. If there is no patch and probably won’t ever be, look at putting a TLS proxy in front of the endpoint. Pretty sure stunnel4 can do this for you.”
QUICK EDIT: One final note — the bug was written at the end of 2011, so devices that are older than that and have not been patched at all remain invulnerable (at least to Heartbleed). The guidance is really to identify systems that are exposing OpenSSL 1.01 SSL servers (and eventually clients) w/ heartbeat support, on top of any protocol, and get ‘em patched up.
Yes, I’m trying to get focus off of users and passwords and even certificates and onto stemming the bleeding, particularly against non-obvious endpoints. For some reason a surprising number of people think SSL is only for HTTP and browsers. No, it’s 2014. A lot of protocol implementations have basically evolved to use this one environment middleboxes can’t mess with.
A lot of corporate product implementations, by the way. This has nothing to do with Open Source, except to the degree that Open Source code is just basic Critical Infrastructure now.