Archive for the ‘ModSecurity’ Category

Migrating from ModSecurity 1.9.4 to 2.0.4

Saturday, January 20th, 2007

ModSecurity 2 has been out for a while now, and although I have played with it some, I never found some time to upgrade my own servers. The upgrading generally went quite smooth, even though ModSecurity 2 changed quite a bit.

First of all there are now 5 phases where you can filter. Actually, one of them only applies to the logging, so you can filter in 4 phases. The phases are headers and body for both request and response traffic. Filtering on specific URIs can be done in phase 1 (request headers), while inspecting a POST payload requires phase 2 (request body).

Next, some shortcuts where removed. In 1.9.4 there was a variable called POST_PAYLOAD, that enabled the user to match against payloads from POST requests easily. Now there is REQUEST_BODY, but since that can be part of non-POST requests as well, you have to use:

SecRule REQUEST_METHOD “POST” chain
SecRule REQUEST_BODY “evil”

instead of:

SecFilterSelective POST_PAYLOAD “evil”

One other change is visible above already. The keyword to create a rule has been changed from SecFilterSelective to SecRule. Many rules can be converted by just replacing the keyword, but certainly not all. A simple find/replace should not be done without a manual review!

I use a number of custom rules to protect certain parts of my server, so I needed to convert my rules. For most of them it was simply enough to replace SecFilterSelective with SecRule. For a few I had to replace the OUTPUT_STATUS variable with the RESPONSE_STATUS variable, as it is called now.

For one rule however, I had quite some problems to get it running correctly. This was the rule in 1.9.4 syntax:

# block wp-login.php
SecFilterSelective REMOTE_ADDR “!10\.1\.1\.1″ chain
SecFilterSelective REQUEST_URI “/wp-login.php” \
log,deny,redirect:http://www.inliniac.net/nologin.html

This rule makes sure only 10.1.1.1 can open the login page, everyone else is redirected to a simple html page containing a ‘Access Denied – Logins disabled’ message. I converted it to the following:

SecRule REMOTE_ADDR “!10\.1\.1\.1″ chain
SecRule REQUEST_URI “/wp-login.php” \
log,deny,redirect:http://www.inliniac.net/nologin.html

Guess what? It didn’t work. I’ve spend quite some time trying all kinds of variations of the rule, and finally I found out what the issue is. In 1.9.4 the rule actions, like deny, redirect etc could be in the final rule of a series of chained rules. With 2.0.4 this doesn’t work correctly. So when I changed the rules to the following, it worked:

# block wp-login.php
SecRule REMOTE_ADDR “!10\.1\.1\.1″ \ “chain,phase:1,log,deny,redirect:http://www.inliniac.net/nologin.html”
SecRule REQUEST_URI “/wp-login\.php$”

I haven’t looked into this further to find out whether this is a bug or a feature.

The last thing that was interesting is the modsec2sguil script. There have been some changes to the alert files. So expect a new version of the script soon!

Rules for reported Tikiwiki vulnerabilities

Thursday, November 2nd, 2006

Yesterday there was a mail to the bugtraq mailinglist about two types of vulnerabilties in Tikiwiki 1.9.5. The most serious is a claimed MySQL password disclosure through a special URI. The second is an XSS, also through an special URI. The message can be found here.

I wrote ‘claimed password disclosure’, because on the Tikiwiki server I run, I could not reproduce it. With that I mean the password disclosure, since I do see that Tikiwiki gives an error that reveals other information, most notably the location of the website on the local filesystem.

Anyway, since I’m running Tikiwiki I was eager to protect myself, so I started to write some rules.

XSS

Since I run ModSecurity on this server, I started with a rule for that:

SecFilterSelective REQUEST_URI “\/tiki-featured_link\.php\?type” “chain,status:403,msg:’LOCAL tikiwiki featured link XSS attempt’,severity:6″
SecFilterSelective REQUEST_URI “\/iframe>” log,deny,status:403

I did the same for Snort, and submitted it to the Bleeding Edge ruleset, see here.

Passwd/filesystem disclosure

This one is much harder to catch in a rule. The problem is in how Tikiwiki handles the sort_mode option in an URI. Only if the argument to sort_mode is valid (such as hits_asc or hits_desc for sorting on number of hits) the error is prevented. If the argument to sort_mode is empty or invalid then the disclosure condition triggers.

The only way I can think of to write rules for this is by adding some positive security filtering. In other words, create a rule that defines the valid arguments to sort_mode and drop anything else. Below is an example of one of the affected pages in Tikiwiki:

SecFilterSelective REQUEST_URI “tiki-listpages\.php” chain
SecFilterSelective REQUEST_URI “sort_mode=(pageName|hits|lastModif|creator|user|version|
comment|flag|versions|links|backlinks|size)_(asc|desc)” pass,skip:2

SecFilterSelective REQUEST_URI “tiki-listpages\.php” “chain,msg:’LOCAL tikiwiki listpages mysql passwd disclosure attempt’,severity:7″
SecFilterSelective REQUEST_URI “sort_mode=” log,deny,status:403

As you can see, here are two logical rules, each consisting of two chained rules. The first rule defines all the possible valid options to sort_mode and then has the action ‘pass,skip:2′. This says that this rule should not use the default action of deny and that the next two rules should be skipped. These next two rules drop every use of the sort_mode option, thus blocking the attack.

I have not yet looked at doing this in Snort. According to the advisory, there are 21 different vulnerable URI’s in Tikiwiki, which all have different arguments to sort_mode. So only 20 more to go! ;-)

Modsec2sguil 0.6 released

Saturday, October 7th, 2006

I’ve just release a new version of modsec2sguil, the set of Perl scripts that feeds ModSecurity alerts to Sguil. No new features, but many changes ‘under the hood’. I’ve created two modules, ModsecAlert and SguilBarnyardComms. These can be used in a Object Oriented way to parse ModSecurity events and communitcate a Sguil sensor agent.

It would be interesting to see if the SguilBarnyardComms module could be connected with the work of Jason Brevnik of SourceFire, who wrote a Barnyard replacement in Perl. If I have some spare time, I will have a look at this.

After this release, I want to look at bypassing the sensor_agent altogether and instead connect directly to the Sguil server. Bamm Visscher has plans to redesign parts of the agent – server communications. In the new ideas Sguil moves away from the one monolithic sensor_agent. Instead, different tasks will have their own agent which connects directly to the sguil server. For example a sancp sensor, a snort sensor, a pcap sensor, etc. Next, a number of the same sensors would be able to share a common id, called network id. This way the user can ask a transcript for an alert produced by a modsec sensor. It is my intention to create a Perl module or library that will make creating new agents for this setup easy.

Anyway, thats the future, modsec2sguil 0.6 is ready for your testing right now! Let me know how it works for you!

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

First (beta) release of modsec2sguil 0.5

Wednesday, September 20th, 2006

I have been writing about getting ModSecurity alerts into Sguil before. Today I can finally release a first public version. It’s pretty crude, but it WorksForMe(tm).

The release can be found here. If you are interested, please try it. There is some documentation in the archive.

Sguil: adding support for ModSecurity alerts, continued

Friday, September 8th, 2006

After the successful test with the Perl script to add ModSecurity alerts to Sguil, I have been working on a more robust implementation, also in Perl. Let me first describe the basic setup. The setup works with two scripts. The first places links to event files into a special queue directory. The second reads the links from that directory, parses them and sends the alerts among these events to Sguil. After that, the links are removed.

In ModSecurity there is a logging method called concurrent. What it does is that it creates a directory structure based on date and time. For each event a file is created in the directory structure, with the details of the event. It also writes a logfile called index, that adds one line for every event, with location of the file in the date/time directory layout.

ModSecurity also supports using a external script to take care of this indexing task, which is what the script modsec-auditlog-collector in the ModSecurity source tarball does. I have modified this Perl script to create a link to the actual event file in a special queue directory. The links all have a name like: modsec.log.-timestamp-, like Snort uses with unified logging. I have chosen to use links because I think it might be faster than copying, but I have yet to benchmark that.

The second script takes care of processing the links and communicating with Sguil. It basically has the following workflow. It gets a list of all the files in the queue. Each file in the queue is parsed, then it is checked whether it is an alert. If so, the data is preprocessed to make sure it is what Sguil expects. Next it is send to Sguil. Finally, all the files are removed.

ModSecurity has a different rule syntax than Snort and sees a different type of data. Snort sees packets, and thus knows about TCP checksums, sequence numbers, etc. ModSecurity works on a higher level, so it has no access to that data. One thing that ModSecurity alerts do include is the action taken: blocked or redirected and with what HTTP code. If available the rule msg is used for the Event Message, otherwise the ModSecurity message with (a part of) the rule that matched. Below is a screenshot that shows both, and also the HTTP code.

Sguil and Mod_Security msg view

The current implementation acts as a drop-in replacement of Barnyard. This way no changes to Sguil are necessary. Currently this means that Barnyard cannot run on the same sensor, although multiple instances of sensor_agent on a host could fix that. Sguil author Bamm Visscher suggested I can try to connect to the Sguil server directly instead of via the sensor_agent to fix this. I will probably have a look at that later.

Another issue is the way the alert data is presented in the Sguil interface. Currently I attach the entire alert file to the alert that is being send to Sguil, as the packet payload. However the Sguil packet payload view is not very usable for this kind of data, as can be seen on the screenshot below.

Sguil and Mod_Security payload view

So here is room for much improvement. Ideally Sguil would be able to show the uri, the post payload if applicable, useragent, etc. I’ve never worked with TCL/TK, but I did use Perl/TK in the past, so that might help me a little if I decide to give it a shot.

I expect a public beta version to be ready some time next week, although I have not yet decided how to release it. I could create a project on SourceForge or just have a simple webpage. I just haven’t decided yet. Stay tuned…

ModSecurity: rule for latest Tikiwiki vulnerability

Wednesday, September 6th, 2006

A few days ago a new vulnerability was reported in Tikiwiki 1.9.x, the software I use for the Vuurmuur Wiki. Luckily, the Snort.org Community rules quickly had a rule for detecting the attack. Because I also run ModSecurity on the webserver, i wanted to have protection there as well. This rule should block the attack:

SecFilterSelective POST_PAYLOAD “jhot.php” “log,deny,status:403,msg:’LOCAL tikiwiki jhot.php attempt’”

Let’s see if I ever get a hit on it. An update for Tikiwiki as been released, so that should fix the issue completely.

Sguil: adding support for ModSecurity alerts

Wednesday, August 30th, 2006

I’m a huge fan of both Sguil and ModSecurity, but sadly the alerts generated by ModSecurity can’t show up in Sguil… or… can they? Well, if it all works out, soon they can!

Today I have hacked together a perl script that emulates barnyard for ModSecurity. It very much in a proof-of-concept phase, but it somewhat works already, at least good enough so i can show this screenshot.

Sguil screenshot showing experimental Mod_Security support
Nice huh? It is not ready for release yet, but when it is i’ll announce it here. I plan to release it under the GPL. Sguil author Bamm Visscher told me that the next release of Sguil will have support for having barnyard and PADS on the same sensor. By then, i hope that ModSecurity can be added to that list! :-)

Sguil: using advanced queries to get more info on Snort events

Monday, August 28th, 2006

Today, David Bianco showed me a way of creating SQL queries that I didn’t even know was possible. This is a technique with which it is possible to query the payload of Snort events in the Sguil database. These payloads are stored by Snort when it alerts and is the payload the actual rule triggered on. David showed a nice example of retrieving url’s for PHP url inclusion attacks.

I have written before about my usage of Mod_Security. I let Mod_Security respond with a 403 Forbidden message. Sadly, the alert generated by Mod_Security can not be displayed in Sguil. As somewhat of a replacement for that, I let Snort alert on the 403 Forbidden messages, so i can see in Sguil that Mod_Security blocked something. The disadvantage of this is that the 403 alert in itself does not contain much info. The sheer number of 403′s makes inspecting every single one with requesting a transcript a bit to much work.

This is where the new query comes in. The query creates a list of url’s that the server reported to be 403 Forbidden. Interesting is that we are not looking at an attack, but at an attack response. This means the the attackers IP is actually the destination IP.

SELECT COUNT(*) AS cnt, INET_NTOA(dst_ip) AS “Dest IP”, trim(LEADING “access ” FROM substring_index(substr(unhex(data_payload),locate(‘access ‘,unhex(data_payload))), ‘\n’, 1)) AS url FROM event INNER JOIN data ON event.sid = data.sid and event.cid = data.cid where (signature like “%ATTACK-RESPONSES 403 Forbidden%”) GROUP BY dst_ip,url ORDER BY cnt DESC LIMIT 10;

The result is this:

MySQL result for query for 403 Forbidden event url's

As you can see, the first six results are from the comment spam I wrote about earlier. I left the source IP out because there is only one webserver. The query can easily be extended to show source IP’s as well.

ModSecurity: rules against comment spam

Wednesday, August 23rd, 2006

Lately the wiki of my Vuurmuur project has been receiving quite a lot of comment spam. Although removing the spam manually is boring work, i still don’t really mind the spam, because it enables me to practice with ModSecurity rules to fight it off. So far, the spam seems to be following a pattern, in which the spam is posted by bots, and has the same general layout for longer periods of time. That makes it worthwhile to spend time on creating rules against it. Yesterday a new type of spam emerged on the wiki. The following audit_log is for one of them. I had to slightly edit it for layout reasons.

–9075cb7a-A–
[22/Aug/2006:20:20:46 +0200] SPO4w5FhwZUAADItDEgAAAAC 195.225.177.131 34189 192.168.1.101 80
–9075cb7a-B–
POST /tiki/tiki-index.php HTTP/1.1
Host: wiki.vuurmuur.org
Referer: http://wiki.vuurmuur.org/tiki/tiki-index.php?page=Vuurmuur
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)
Content-Length: 1304
Content-Type: application/x-www-form-urlencoded

–9075cb7a-C–
page=Vuurmuur&cols=60&comments_sort_mode=points_desc&
comments_parentId=0&rows=6&comments_postComment=
post&comments_threshold=0&comments_threadId=0&
comments_data=Chevrolet+-+%5BURL%3Dhttp%3A%2F%2F
canonprnbf.kickme.to%2F+%5D+Chevrolet+%5B%2FURL%5D+
home+based+businesses+-+%5BURL%3Dhttp%3A%2F%2F
1964cadulj.blog.kataweb.it%2F1964cadulj%2Findex-home-
based-businesses.html+%5D+home+based+businesses+
%5B%2FURL%5D+diet+pills+-+%5BURL%3Dhttp%3A%2F%2F
aemerge4li.web1000.com%2Findex-diet-pills.html+%5D+diet+
pills+%5B%2FURL%5D+Cash+Advance+-+%5BURL%3D
http%3A%2F%2Fseamlesmnp.su.pl%2F+%5D+Cash+Advance
+%5B%2FURL%5D+Azithromycin+-+%5BURL%3D
http%3A%2F%2Fthelacefab7ne.kickme.to%2F+%5D+
Azithromycin+%5B%2FURL%5D+allergy+-+%5BURL%3D
http%3A%2F%2Fgeo.ya.com%2Faeggcelpzg%2Findex-
allergy.html+%5D+allergy+%5B%2FURL%5D+Cash+Advance+
-+%5BURL%3Dhttp%3A%2F%2Faofficeuov.ir.pl%2F+%5D+
Cash+Advance+%5B%2FURL%5D+free+games+-+%5BURL
%3Dhttp%3A%2F%2Fwww.geocities.com%2Fthebestjwb
%2Findex-free-games.html+%5D+free+games+%5B%2F
URL%5D+Ambien+-+%5BURL%3Dhttp%3A%2F%2F
beadedluwu.su.pl%2F+%5D+Ambien+%5B%2FURL%5D+altace
+-+%5BURL%3Dhttp%3A%2F%2Facellphonehy4.tripod.com
%2Findex-altace.html+%5D+altace+%5B%2FURL%5D
+&comments_reply_threadId=0&comments_title=Chevrolet&
comments_offset=0&comments_previewComment=preview&
comments_grandParentId=
–9075cb7a-F–
HTTP/1.1 200 OK
X-Powered-By: PHP/4.3.10-16
Set-Cookie: PHPSESSID=b2497fd593f56c5af4f3613ba78a7619; path=/tiki
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Connection: close
Transfer-Encoding: chunked
Content-Type: text/html; charset=utf-8

–9075cb7a-H–
Stopwatch: 1156270844524739 1475657 (17717* 38503 0)
Producer: ModSecurity v1.9.2 (Apache 2.x)
Server: Apache/2.0.54 (Debian GNU/Linux) PHP/4.3.10-16 mod_ssl/2.0.54 OpenSSL/0.9.7e

–9075cb7a-Z–

A general rule against the comment spam would probably not be that hard. Just blocking “http://” would probably to the trick. However, I’m not quite willing to do this, since people might actually post real and interesting links to the wiki. I noticed that the above comment and the 30 other already posted messages all contained the uppercase word URL, so i decided to block on that. Below are the rules, which as you can see are quite an improvement over these rules, because they now only match on actual comments posts ;-)

SecFilterSelective REQUEST_URI “\/tiki\/tiki-index\.php” “chain,msg:’LOCAL comment spam’”
SecFilterSelective POST_PAYLOAD “URL” chain
SecFilterSelective POST_PAYLOAD “comments_postComment=post” log,deny,status:403

An Apache restart and just wait… but not for long:

[Tue Aug 22 21:35:44 2006] [error] [client 195.225.177.131] mod_security: Access denied with code 403. Pattern match “comments_postComment=post” at POST_PAYLOAD [msg "LOCAL comment spam"] [hostname "wiki.vuurmuur.org"] [uri "/tiki/tiki-index.php"] [unique_id "VTGBGJFhwZUAADMnAWAAAAAA"]

This morning there were 59 attempts blocked already which i would have to remove manually without these rules. So taking the time to setup the rules really pays off.

ModSecurity: more security by obscurity

Thursday, August 17th, 2006

Yesterday, Philippe Baumgart showed me that my obscurity setup is not yet perfect. In fact, he could very easily enter an URL that didn’t exist and caused the webserver behind my proxy to respond with a 404. In this 404 the name and the version of the webserver were exposed.

After some testing i found that adding the following to my config worked very well.

# enable output scanning in Mod Security.
SecFilterScanOutput On

# hide outgoing 404 by webserver behind proxy
SecFilterSelective OUTPUT_STATUS 404 deny,status:404

This catches outgoing 404 errors, and replaces them by the 404 from the proxy. For some reason, this still didn’t exaclty look like the 404 from the proxy itself, because it contained a message that an additional 404 was encountered. I solved this by changing the ErrorDocument in de Apache config:

ErrorDocument 404 “<html><head><title>404 Not Found</title></head><body><h1>Not Found</h1><p>The requested URL was not found on this server.</p></body></html>”

After this, there was no longer any difference between 404′s produced by the proxy and by the webserver behind it.

Next, Phil showed me that i also leaked my version number of PHP. By using WordPress hiding the fact that I use PHP is impossible and pointless, but hiding the exact version still looks like a good idea. The version was leaked in the header from a server response: X-Powered-By: PHP/4.4.1build1. Solving this requires the mod_header module again:

# unset X-Powered-By to prevent leaking the PHP version
Header unset X-Powered-By

This hides this header. Thanks to Phil for doing some pen-testing :-)