Using Modsec2sguil for HTTP transaction logging revisited

Recently I wrote about the idea to log all HTTP transactions into Sguil using my Modsec2sguil agent. I’ve implemented this in the current 0.8-dev5 release and it works very well. All events go into Sguil smoothly and I’ve not experienced slowdowns on the webserver. I’ve been running it for almost a week now, like to share the first experiences here.

I find it to be quite useful. When receiving an alert, it is perhaps more interesting to see what else was done from that ipaddress than to see what was blocked (unless you are suspecting a false positive of course). One area I find to be useful is when I’m creating rules against comment spam on this blog. By seeing all properties of a spam message I can create better rules. For example on broken user-agents or weird codes inserted into the comment field of WordPress.

It’s easy to search and filter on HTTP response codes because the code is a part of the RT message. For example, when searching for all HTTP 500 error codes, add the following ‘WHERE’ clause to a query:

WHERE event.signature like “%MSc 500%”

This works quite fast although you best limit the query on properties like date and port as well. To get all the HTTP code 500 alerts from the last days do something like:

WHERE event.timestamp > ‘2007-08-18’ AND (event.dst_port = 80 OR event.dst_port = 443) AND event.signature like “%MSc 500%”

One thing that is disappointing is the inabillity to search in the event payloads stored in the database. Technically it’s possible to create mysql queries that search for certain strings, but this process is so slow that it’s hardly usable in practice. The problem here is that the database field containing the payload is not indexed. I’ll show the query I used here (ripped from David Bianco’s blog)

WHERE event.timestamp >= ‘2007-08-18’ AND (event.dst_port = 80 OR event.dst_port = 443) AND data.data_payload like CONCAT(“%”, HEX(“Mozilla/5.0”), “%”)

If you know a more efficient query, please let me know!

Using Modsec2sguil for HTTP transaction logging

Modsec2sguil is currently configured to send alerts to Sguil. ModSecurity can be configured to log any event or transaction, including 200 OK, 302 Redirect, etc. Modsec2sguil distinguishes between alerts and other events by only processing HTTP codes of 400 and higher. Since 0.8-dev2 there is a configuration directive to prevent certain codes, such as 404, from being treated as an alert.

Now I have the following idea. Since ModSecurity can log all events with details of request headers, response headers and POST message body, it may be interesting to just send all these events to Sguil. They should not be appearing as alerts, but having them in the database can perhaps be interesting. I know using flow data and full packet captures the same data can be accessed, but having it in the database makes querying it a lot easier and longer available.

Possible problems are mostly the performance hit the webserver may take for sending all these events to Sguil and the storage requirements in Sguil’s database. I estimate the events are about 1kb in size on average, so on a busy site this may cause the database to grow very rapidly. Of course this behavior would be optional so it can be disabled.

Any thoughts on this idea?

First Modsec2sguil release for Sguil 0.7-CVS

I just uploaded a new version of Modsec2sguil. I’ve been working on it the last weeks to get it updated to Sguil 0.7. The scripts are changed all over the place. This is because in the 0.7 framework, my scripts would no longer be a replacement for Barnyard only talking to the sensor_agent on the localhost, instead now it would become a full agent talking to the Sguil server directly.

This brings some challenges. First the connection can be going over the internet, or another untrusted network, so the agent needs ssl support. Second, since the connection may be unreliable we need to be able to detect and deal with lost connections. Next to this I wanted to be able to run without superuser privileges.

The new version of modsec2sguil supports it all, and more:

  • Converted into a real agent for Sguil 0.7 (no more barnyard replacement)
  • Agent can drop privileges
  • Agent can daemonize
  • Pinging the server is supported
  • The agent reconnects to the server if the connection is lost
  • Agent supports SSL for the connection to the server
  • A sguil-compatible configuration file is now used
  • A debug mode was added

So if you run Sguil 0.7-CVS and ModSecurity, go check it out at http://www.inliniac.net/modsec2sguil/

Last but not least, the agent contains a SguilAgent.pm Perl library. I hope it enables developers to easily create Perl agents for Sguil. If you need help with that, please let me know!

Running IPv6 with Freenet6 when on the road

I wrote about my experiments with IPv6 before. These were done for my home network where I have an ISP that offers an IPv6 tunnel broker. The last two months I have not been in my home, but instead using internet ‘on the road’ mostly through wireless LANs. There are a number of techniques for using IPv6 if your provider doesn’t offer it, and today I stumbled on one in this NetworkWorld article, so I decided to give it a try.

The artice is about a new IPv6 portal called go6.net, where you can find IPv6 related news and forums. Next to this access to a free IPv6 broker is offered: freenet6. Freenet6 works by tunneling the IPv6 packets in UDP packets over IPv4. Getting it is easy, register an account and download the software. When you are running Debian or Ubuntu you can even skip the last step, a mere ‘apt-get install freenet6’ will do it. This is what I did. Next I just had to enter the username and password I had entered in the registration process in a file called ‘/etc/tsp/tspc.conf’ and issue the command ‘tspc -f /etc/tsp/tspc.conf’. Opening go6.net and kame.net comfirmed I was using IPv6!

Since I’m behind NAT-router internet hosts can’t connect to my laptop directly, but with IPv6 this changes. My laptop is now using a public IPAdress, so I set up a simple firewall script using ip6tables. I found two sites enabling you to check how the internet sees you, here and here. Both showed that my firewall is working. Good.

So now I wanted to blog about this, so I tried to login to my blog… ‘Access Denied’. Oops! Forgot that I only allow certain IPv4 addresses to the admin interface of my blog. This was a good time to see how ModSecurity deals with IPv6 addresses in its rules:

SecRule REMOTE_ADDR “!(192.168.1.2|2001:5c0:8fff:fffe::62fd)” “chain,phase:1,deny,redirect:http://www.inliniac.net/nologin.html”
SecRule REQUEST_URI “/wp-login.php$”

This rule blocks access to wp-login.php for everyone but 192.168.1.2 and 2001:5c0:8fff:fffe::62fd, and redirects them to a static page called nologin.html. This works using IPv6 as well! As you can see ModSecurity does not only support IPv6, it even allows you to mix IPv4 and IPv6 addresses in rules! Now all that was left was the /wp-admin/ section that didn’t block in ModSecurity, but just with Apache itself:

<Location /blog/wp-admin>
Order deny,allow
Deny from all
Allow from 192.168.1.2
Allow from 2001:5c0:8fff:fffe::62fd
</Location>

After an Apache restart I could write this post using IPv6!

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.

Modsec2sguil 0.7 released

I’ve just released version 0.7 of Modsec2sguil, the set of perl scripts to feed ModSecurity alerts to the Sguil NSM system. The main change of this release is that it adds support for alerts produced by ModSecurity 2.x, while 1.9.x remains to be supported. Next to this the conversion between ModSecurity’s severity and Snort’s priority was fixed, so alerts should show up in the right pane in Sguil again.

Please give this release a try and let me know how it works for you!

Download it here: http://www.inliniac.net/files/modsec2sguil-0.7.tar.gz

Experimenting with IPv6

My ISP is one of the few here in the Netherlands that provides a IPv6 tunnel broker. I have played with it some during the last year or so, but now decided to get a little more serious with it. So I’ve decided to enable it for my blog. When opening up my site to IPv6 one thing that is important is security. I will describe the status of IPv6 support of my current setup:

Linux firewalling: IPtables supports IPv6 for quite some time, however it only very recently gained stateful packet filtering support. This hasn’t made it into Debian Sarge or even backports yet, so I’m just using stateless filtering now.

Vuurmuur: my own IPtables frontend has no support for IPv6 at all. I’ve been thinking about adding it for years, but decided to wait at least until stateful support would be available. Next to this my coding time is limited, and many other features are probably more interesting to Vuurmuur users.

Snort/Snort_inline: both Snort and Snort_inline lack support for IPv6. Sourcefire is working on it as far as I know, but no code is available from them. I did find a IPv6 patch for Snort 2.3.3, which can be found here. I ran it in sniffer mode and that works. I haven’t played with it much other than that, but I certainly will in the future.

ModSecurity: my Apache 2 installation has IPv6 enabled by default and ModSecurity 2.x just worked with it without any configuration change! I haven’t looked into how to create rules specific for IPv6 addresses however, so maybe surprises will come up here. I do know from looking at the source that the rbl functionality doesn’t support IPv6 addresses yet, but I haven’t even checked if realtime blacklists exist for IPv6.

Sguil/Modsec2sguil: my modsec2sguil script, that takes ModSecurity alerts and feeds them to Sguil, doesn’t act on the IPv6 alerts because it expects IPv4 addresses. This is not a problem however, since Sguil doesn’t support IPv6 addresses. This makes sense since Snort doesn’t support it either.

So compared to my IPv4 access, protection is somewhat limited. I’m only enabling HTTP for now, so ModSecurity should be able to handle that just fine.

Anyway, it seems to be working fine now, but consider the IPv6 support experimental, as I’m playing with how it all works. So don’t be surpised if it’s broken all of a sudden 😉

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.

Update on using realtime blacklists with ModSecurity

A few days ago I posted a blog article about stopping comment spam with ModSecurity using realtime blacklists (rbl). While the approach was working, I noted having problems with rules when I tried to match on POST methods in HTTP requests.

Luckily, ModSecurity creator Ivan Ristic was quick to point out where the problem is. I’m using the Core Ruleset for ModSecurity, and one thing that ruleset does is use the ‘lowercase’ transformation. This converts all text from arguments to lowercase, so my ^POST$ match would never be able to match. So like Ivan suggested, using ^post$ solved this part.

Next Ivan pointed out a weakness in the rules. My rules looked for /blog/wp-comment-post.php, and would be easily evaded by just using /blog//wp-comment-post.php. He suggested using the ‘normalisePath’ transformation. I did this, but I also slightly changed the rules to not look for the /blog/ part at all (maybe this makes normalisePath useless, but I decided to rather be safe than sorry).

The rules I’m using now look like this:

SecRule REQUEST_METHOD “^post$” “log,deny,chain,msg:’LOCAL comment spammer at rbl list.dsbl.org'”
SecRule REQUEST_URI “wp-(comments-post|trackback).php$” “chain,t:normalisePath”
SecRule REMOTE_ADDR “@rbl list.dsbl.org”

SecRule REQUEST_METHOD “^post$” “log,deny,chain,msg:’LOCAL comment spammer at rbl bl.spamcop.net'”
SecRule REQUEST_URI “wp-(comments-post|trackback).php$” “chain,t:normalisePath”
SecRule REMOTE_ADDR “@rbl bl.spamcop.net”

SecRule REQUEST_METHOD “^post$” “log,deny,chain,msg:’LOCAL comment spammer at rbl sbl-xbl.spamhaus.org'”
SecRule REQUEST_URI “wp-(comments-post|trackback).php$” “chain,t:normalisePath”
SecRule REMOTE_ADDR “@rbl sbl-xbl.spamhaus.org”

Thanks a lot Ivan Ristic for your comments!