Tuesday, April 8, 2014

Heartbleed Memory Disclosure - Upgrade OpenSSL Now!

Heartbleed is a serious vulnerability in OpenSSL 1.0.1 through 1.0.1f.   If you have not upgraded to OpenSSL 1.0.1g or installed a version of OpenSSL with -DOPENSSL_NO_HEARTBEATS it is strongly recommended that you do so immediately.

This vulnerability allows the attacker to read up to 64KB of heap memory from the victim without any privileged information or credentials. How is this possible? In short, OpenSSL's heartbeat processing functions use an attacker controlled length for copying data into heartbeat responses. Both DTLS and TLS heartbeat implementations are vulnerable.

The vulnerable functions are tls1_process_heartbeat() in ssl/t1_lib.c (for TLS) and dtls1_process_heartbeat() in ssl/d1_both.c (for DTLS). Looking at these functions you can see that OpenSSL first reads the heartbeat type and length:

hbtype = *p++;
n2s(p, payload);
pl = p;

n2s is a macro that takes two bytes from "p" and copies them to "payload". This is the length indicated by the SSL client for the heartbeat payload.  Note: The actual length of the SSL record is not checked. The variable "pl" is a pointer to the heartbeat data sent by the client.

OpenSSL allocates as much memory as the client asked for (two byte length up to 65535 bytes) plus 1 byte for heartbeat type, 2 bytes for payload length, and 16 bytes for padding:

buffer = OPENSSL_malloc(1 + 2 + payload + padding);
bp = buffer;

Then it builds the heartbeat response by copying the payload size sent in the request to the response using the macro s2n (opposite of n2s).  Finally (and here's the critical part), using the size supplied by the attacker rather than its actual length, it copies the request payload bytes to the response buffer.

*bp++ = TLS1_HB_RESPONSE;
s2n(payload, bp);
memcpy(bp, pl, payload);

If the specified heartbeat request length is larger than its actual length, this memcpy() will read memory past the request buffer and store it in the response buffer which is sent to the attacker. In internal testing we were able to successfully retrieve usernames, passwords, and SSL certificates.

To detect this vulnerability we use detection_filter ("threshold") rules to detect too many inbound heartbeat requests, which would be indicative of someone trying to read arbitrary blocks of data. Since OpenSSL uses hardcoded values that normally result in a 61 byte heartbeat message size, we also use rules to detect outbound heartbeat responses that are significantly above this size. Note: you can't simply compare the TLS record size with the heartbeat payload size since the heartbeat message (including the indicated payload size) is encrypted.

We have released detection in SIDs 30510 through 30517 to detect attacks targeting this vulnerability.

To keep people updated, Heartbleed rules have been added to the community ruleset.
Add to Technorati Favorites Digg! This

13 comments:

Redbaron said...

It is worth pointing out that these rules will only work in cases where the heartbeat is not encrypted, i.e. the TLS Handshake has not been completed. This adequately covers most of the "in-the-wild" exploits and PoC. But a more elaborate exploit that does the TLS handshake will send encrypted heartbeats (i.e. everything after the first 5 bytes will be encrypted), so heartbeat length etc. will not be visible to Snort and the signature will not trigger.

pmullen said...

You are correct that the Heartbeat Message is encrypted. However, we do not use any data from within the Heartbeat Message. We use the unencrypted TLS message headers that encapsulate the Heartbeat Message. As you stated, "everything after the first 5 bytes will be encrypted." Our detection uses only those first five bytes as you can see from the content match's depth:3 modifier and the byte_test operating on the next two bytes of the payload.

Thank you for the question. We have seen others' detection that does use the Heartbeat Message data in their detection which as you state can be encrypted and therefore break that detection.

Greg S said...

How do you tell what version of OpenSSL you are using or if you are even using OpenSSL. I inherited this system.

Redbaron said...

Ah didn't see it fully. My Bad. But these do not trigger for the online test tool http://filippo.io/Heartbleed/. Maybe thresholds are a problem?

Benoit Donneaux said...

Hi. Thanks for sharing those rules. I'm trying them right now in a lab. But since I'm not using directly any exploit, I was trying to trigger them using some testing tools available online (for instance: https://www.ssllabs.com/ssltest or http://filippo.io/Heartbleed/). And this does not seem to work... Am I right, or those tools are using the vulnerability ? Any suggestion (I'm already double checking my Snort config...) ?

Chad said...

I had to modify the "dsize" rule option from ">40" to ">7" before they would alert on my test traffic. The tool I used did not include anything extra in the TCP payload, so the dsize check was causing false negatives. Can you share the PCAP you used to validate these rules, please? I can provide PCAP and modified rules at your request.

Just Me said...

I do have a Sourcefire DC and Sensors and i cant see the rule working i used the main PoC and even the fillipo.io Test and nothing happen .

pmullen said...

Redbaron, Benoit, Chad, and Just Me -- Today we are releasing updated versions of the Heartbleed rules that address your concerns. The rules we released on Tuesday were modified from our original form after analyzing alerts on our real-world test sensors. Ironically, our rules worked so well that with everyone on the Internet exploiting everyone, it was difficult to determine what was a True Positive and what was a False Positive. Because this detection was so important, we wanted to make sure rules were released that could safely be enabled by default and provide valid, useful detection while we performed additional research. Today's rule updates will remove the dsize from the request checks, remove the detection_filter ("threshold") from the response checks, and add more ports for analysis.

pmullen said...

Greg S -- You'd have to look on your server to find out. The fastest way to find out if you're vulnerable, though, would be to just run one of the test scripts or sites. It's actually "okay" to run the vulnerable version of openssl as long as heartbeats aren't enabled.

Benoit Donneaux said...

Thanks pmullen. It's been a while I've not used Snort and I was wondering about the size and the threshold... But it makes sense you've done it this way.

Ken said...

I have been testing the snort rules for heartbleed with ssltest.py and the online services and it will not trigger. Is there additional configuraiton that needs to occur?

Ken said...

Testing the new rules I am not able to trigger alerts when the exploits currently in the wild.

Patrick Mullen said...

Ken, the inbound (attack) rules use a detection_filter ("threshold") to avoid false positives so a single check will not trigger an alert.

If the targeted server is not vulnerable, it will not send a response heartbeat containing leaked data, so the outbound (exfiltration) rules will not fire.

This is expected behaviour, and a side effect of not being able to tell if a heartbeat request is inherently malicious because the data is encrypted.