Detecting Heartbleed with Haka v0.2
As most of you must have heard, a very nasty bug was discovered few weeks ago in the OpenSSL project, a widely used open source implementation of the SSL/TLS protocol. This bug which is better known as the heartbleed bug, relies on a wrongly implemented SSL extension called "heartbeat".
As you know, the initial version of Haka doesn't ship with a SSL dissector. However, the 0.2 version — which will be released soon — features a new grammar allowing to specify network protocols and their underlying state machine. Thanks to that grammar, we were able to write, with a little effort, a dissector covering almost the full specification of SSLv3 protocol. This specification will be covered in upcoming post.

Hereafter, we give a set of rules to detect/block hearbleed attacks.
Detecting heartbeat extensions
This first rule warns if a heartbeat extension is used in Client Hello Handshake.
-- Let's use our brand new SSL dissector
-- on port 443
local ssl_dissector = require('protocol/ssl')
ssl_dissector.install_tcp_rule(443)
haka.rule{
-- hook syntax has slightly changed in version 0.2.
hook = ssl_dissector.events.client_hello,
eval = function (ssl, data)
-- ssl fields are available through data param
for i = 1, #data.extensions do
-- extension type 15 is heartbeat extension
if data.extensions[i].type == 15 then
print("Heartbeat extensions detected")
print("### Warning, this is probably heartbleed ###")
end
end
end
}
On a pcap containing a SSL heartbeat extension, Haka will output the following message:
Heartbeat extensions detected
### Warning, this is probably heartbleed ###
That's a first step, but with Haka you can do better than that. Haka detects heartbeats, but a heartbeat is not necessary a heartbleed attack.
Detecting SSL state machine violation
We made some pcap traces with an exploiting tool (link not given) and observed that heartbeat requests are sent during SSL negociation which violates the RFC 6520: "a HeartbeatRequest message SHOULD NOT be sent during handshakes". Our dissector has an internal state machine analyzing each step of the SSL handshake. The attack made by this tool is therefore blocked due to an incorrect state transition. More precisely, the attack tool sends a heartbeat request just after the ServerHelloDone while Haka expects a ClientKeyExchange message. The default behavior is to raise an alert and to drop the connection:
info alert: id = 7
time = Wed Apr 23 10:38:09 2014
severity = low
description = awaited client key exchange handshakes
debug state-machine: ssl: error transition on state 'server_hello_done'
debug state-machine: tcp: transition from state 'established' to state 'reset'
debug state-machine: tcp: enter transition on state 'reset'
Haka can now detects the attacks launched by any tool which doesn't respect RFC, but what if attacker takes care of each step of the SSL negociation?
Detecting unexpected hearbeat messages length
RFC 6520 states that: "... the receiver MUST send a corresponding HeartbeatResponse message carrying an exact copy of the payload of the received" which is not the case with a heartbleed attack. Moreover, we must have only one heartbeat message in flight at a time. In the following rule we check if these two requirements are met. Otherwise, we raise an alert and drop the ssl connection:
haka.rule{
hook = ssl_dissector.events.data,
eval = function (ssl, data, direction)
-- type == 24 => Heartbeat
if data.type ~= 24 then return end
-- create a table to store hearbeat requests
if not ssl.heartbeat then ssl.heartbeat = {} end
-- we should not have more that one heartbeat
-- message in flight at a time
if ssl.heartbeat[direction] then
haka.alert{
description = "unexpected heartbeat request",
sources = haka.alert.address(ssl.flow.srcip)
}
ssl:drop()
else
local opposite_direction = haka.dissector.other_direction(direction)
if ssl.heartbeat[opposite_direction] then
if data.length > ssl.heartbeat_len then
haka.alert{
description = "unexpected heartbeat response data length",
sources = haka.alert.address(ssl.flow.srcip),
}
ssl:drop()
else
ssl.heartbeat[direction] = nil
end
else
ssl.heartbeat[direction] = true
ssl.heartbeat_len = data.length
end
end
end
}
For a sake of simplicity, we assumed that only one side is requesting heartbeats in order to distinguish between encrypted heartbeat requests and responses. However, with better heuristics this configuration case could be also covered by Haka.
Conclusion
Heartbleed was an interesting test case for Haka. We were able to write quickly a dissector for a complex protocol along with its state machine and define advanced security rules.