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

ModSecurity rules for Tikiwiki 1.x tiki-graph_formula.php Function Injection Vulnerability

A new vulnerability has been found in Tikiwiki. Read more about it here.

I’ve created the following ModSecurity rule to block it.

SecDefaultAction “log,deny,phase:2,status:403,t:urlDecodeUni,t:lowercase”

SecRule REQUEST_FILENAME “tiki-graph_formula.php” “chain,msg:’TIKIWIKI tiki-graph_formula.php link inclusion attempt’,severity:2″
SecRule ARGS:/^s*[a-z]+$/ “^(ht|f)tps?://”

SecRule REQUEST_FILENAME “tiki-graph_formula.php” “chain,msg:’TIKIWIKI tiki-graph_formula.php f parameter Function Injection Vulnerability’,severity:2″
SecRule ARGS_NAMES “^s*f[.*]$”

Ivan, I hope these rules survive your scrutiny ;-)

Updated at 13:50: The first rule only covered the file inclusion in the title parameter which was what I was seeing in my logs. These rules should cover both the inclusion and the injection.

ModSecurity rule for Tikiwiki XSS

I just read about a Tikiwiki XSS here. Since the Vuurmuur wiki runs Tikiwiki I created a ModSecurity rule for it:

SecDefaultAction “log,deny,phase:2,status:403,t:urlDecodeUni,t:lowercase”

# XSS in remind password field
SecRule REQUEST_METHOD “^post$” “chain,msg:’TIKIWIKI lost password XSS’”
SecRule REQUEST_FILENAME “tiki-remind_password.php” “chain”
SecRule ARGS:/s*username/ “!^(:?[a-z0-9-_]{1,37})$”

This allows only valid usernames to be entered.

Update: Ivan Ristic privately pointed me at some possible problems with the rule:

  1. the escaping of the – and _ chars is not needed, although it seems to be harmless.
  2. the $ at the end of the filename is dangerous, because Apache treats tiki-remind_password.php/xxx as tiki-remind_password.php. In this case the rule is evaded.
  3. PHP (which Tikiwiki uses) ignores leading spaces in request arguments. So it treats ‘ username’ the same as ‘username’. The rule needs to deal with that.

Thanks for your feedback Ivan!

Old rule:

SecDefaultAction “log,deny,phase:2,status:403,t:urlDecodeUni,t:lowercase”

# XSS in remind password field
SecRule REQUEST_METHOD “^post$” “chain,msg:’TIKIWIKI lost password XSS’”
SecRule REQUEST_FILENAME “tiki-remind_password.php$” “chain”
SecRule ARGS:username “!^(:?[a-z0-9-_]{1,37})$”

New WordPress issue + Snort and ModSecurity rules

I just read about a new issue with WordPress here at SecurityFocus. It’s a potential credential stealing vulnerability, so I quickly created these ModSecurity 2 rules:

SecDefaultAction “log,deny,status:403,phase:2,t:lowercase,t:escapeSeqDecode”
SecRule REQUEST_FILENAME “/wp-login.php$” “chain,msg:’WORDPRESS wp-login.php redirect_to credentials stealing attempt’,severity:2,t:normalisePath”
SecRule ARGS_NAMES “^redirect_to$” “chain”
SecRule ARGS:redirect_to “(ht|f)tps?://”

I can still login to my WordPress install, so it seems that the rule does no harm. Use at your own risk!

Update: I’ve created a Snort rule as well:

alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (msg:”WORDPRESS wp-login.php redirect_to credentials stealing attempt”; flow:to_server,established; uricontent:”/wp-login.php”; nocase; uricontent:”redirect_to”; pcre:”/redirect_to=(ht|f)tps?://iU”; classtype:web-application-attack; sid:4000003; rev:1;)

Update 2: fixed the Snort rule, thanks to Shirkdog for pointing out that it had some broken pcre in it. The rule is now included in the BleedingThreats ruleset (check here), however that (slightly modified) rule doesn’t detect the attack for me.

Update 3: the Bleeding rule is now fixed. I’ve updated the above rule as well.

Update 4: updated the ModSecurity rule to prevent a possible evasion by prepending tab chars to the redirect url. Thanks to Ryan Barnett for pointing this out.

ModSecurity evasion vulnerability

ModSecurity author Ivan Ristic just reported that a ModSecurity evasion vulnerability has been published without him being notified in advance, so there is no update available yet. Check here for his announcement. And here for the advisory. Ivan Ristic suggests everyone to use this workaround until an updated version of ModSecurity is released (put on a single line):

SecRule REQUEST_BODY “@validateByteRange 1-255″ “log,deny,phase:2,t:none,msg:’ModSecurity ASCIIZ Evasion Attempt’”

I’ve been using that rule for an hour or so, and have seen no false positives so far.

Snort_inline in svn updated to 2.6.1.3

This week SourceFire published a security advisory for (among others) Snort version 2.6.1.2, on which Snort_inline is based. So I took some time to update Snort_inline. Normally this would have taken Will and me quite some time, but since we switched to using svn those days are gone. I was able to update it in under a hour. I was very happy I blogged about the procedure to follow, since I had already forgotten about it ;-)

Will is preparing a release based on this, which should also build with ClamAV 0.90.

Anyway, svn is up to date, so if you are using Snort_inline and rely on the DCE/RPC preprocessor, please pull the code from svn.

Check it out! :-)