Detecting OpenSSL Heartbleed with Suricata
The OpenSSL heartbleed vulnerability is a pretty serious weakness in OpenSSL that can lead to information disclosure, in some cases even to to private key leaking. Please see this post here http://blog.existentialize.com/diagnosis-of-the-openssl-heartbleed-bug.html for more info.
This is a case where an IDS is able to detect the vuln, even though we’re talking about TLS.
LUA
I’ve written a quick and dirty LUA script to detect it:
alert tls any any -> any any ( \
msg:"TLS HEARTBLEED malformed heartbeat record"; \
flow:established,to_server; dsize:>7; \
content:"|18 03|"; depth:2; lua:tls-heartbleed.lua; \
classtype:misc-attack; sid:3000001; rev:1;)
The script:
function init (args)
local needs = {}
needs["payload"] = tostring(true)
return needs
end
function match(args)
local p = args['payload']
if p == nil then
--print ("no payload")
return 0
end
if #p < 8 then
--print ("payload too small")
end
if (p:byte(1) ~= 24) then
--print ("not a heartbeat")
return 0
end
-- message length
len = 256 * p:byte(4) + p:byte(5)
--print (len)
-- heartbeat length
hb_len = 256 * p:byte(7) + p:byte(8)
-- 1+2+16
if (1+2+16) >= len then
print ("invalid length heartbeat")
return 1
end
-- 1 + 2 + payload + 16
if (1 + 2 + hb_len + 16) > len then
print ("heartbleed attack detected: " .. (1 + 2 + hb_len + 16) .. " > " .. len)
return 1
end
--print ("no problems")
return 0
end
return 0
Regular rules
Inspired by the FOX-IT rules from http://blog.fox-it.com/2014/04/08/openssl-heartbleed-bug-live-blog/, here are some non-LUA rules:
Detect a large response.
alert tls any any -> any any ( \
msg:"TLS HEARTBLEED heartbeat suspiciuous large record"; \
flow:established,to_client; dsize:>7; \
content:"|18 03|"; depth:2; \
byte_test:2,>,200,3,big; classtype:misc-attack; \
sid:3000002; rev:1;)
Detect a large response following a large request (flow bit is either set by the LUA rule above or by the rule that follows):
alert tls any any -> any any ( \
msg:"TLS HEARTBLEED heartbeat attack likely succesful"; \
flowbits:isset,TLS.heartbleed; \
flow:established,to_client; dsize:>7; \
content:"|18 03|"; depth:2; byte_test:2,>,200,3,big; \
classtype:misc-attack; \
sid:3000003; rev:1;)
Detect a large request, set flowbit:
alert tls any any -> any any ( \
msg:"TLS HEARTBLEED heartbeat suspiciuous large request"; \
flow:established,to_server; content:"|18 03|"; depth:2; \
content:"|01|"; distance:3; within:1; \
byte_test:2,>,200,0,big,relative; \
flowbits:set,TLS.heartbleed; \
classtype:misc-attack; sid:3000004; rev:1;)
Suricata TLS parser
Pierre Chifflier has written detection logic for the Suricata TLS parser. This is in our git master and will be part of 2.0.1. If you run this code, enable these rules:
alert tls any any -> any any ( \
msg:"SURICATA TLS overflow heartbeat encountered, possible exploit attempt (heartbleed)"; \
flow:established; app-layer-event:tls.overflow_heartbeat_message; \
flowint:tls.anomaly.count,+,1; classtype:protocol-command-decode; \
reference:cve,2014-0160; sid:2230012; rev:1;)
alert tls any any -> any any ( \
msg:"SURICATA TLS invalid heartbeat encountered, possible exploit attempt (heartbleed)"; \
flow:established; app-layer-event:tls.invalid_heartbeat_message; \
flowint:tls.anomaly.count,+,1; classtype:protocol-command-decode; \
reference:cve,2014-0160; sid:2230013; rev:1;)
Ticket: https://redmine.openinfosecfoundation.org/issues/1173 Pull Request: https://github.com/inliniac/suricata/pull/924
Other Resources
- My fellow country (wo)men of Fox-IT have Snort rules here: http://blog.fox-it.com/2014/04/08/openssl-heartbleed-bug-live-blog/ These rules detect suspiciously large heartbeat response sizes - Oisf-users has a thread: https://lists.openinfosecfoundation.org/pipermail/oisf-users/2014-April/003603.html - Emerging Threats has a thread: https://lists.emergingthreats.net/pipermail/emerging-sigs/2014-April/024049.html - Sourcefire has made rules available as well http://vrt-blog.snort.org/2014/04/heartbleed-memory-disclosure-upgrade.html These should work on Suricata as well.
Update 1: - Pierre Chifflier correctly noted that hb_len doesn’t contain the ’type’ and ‘size’ fields (3 bytes total), while ’len’ does. So updated the check. Update 2: - Yonathan Klijnsma pointed me at the difference between the request and the response: https://twitter.com/ydklijnsma/status/453514484074962944. I’ve updated the rule to only inspect the script against requests. Update 3: - Better rule formatting - Add non-LUA rules as well Update 4: - ET is going to add these rules: https://lists.emergingthreats.net/pipermail/emerging-sigs/2014-April/024056.html Update 5: - Updated the LUA script after feedback from Ivan Ristic. The padding issue was ignored. Update 6: - Added Pierre Chifflier’s work on detecting this in the Suricata TLS parser. - Added reference to Sourcefire VRT rules