ModSecurity: more security by obscurity

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 🙂

Vuurmuur: first baby steps in traffic shaping

Quite a while ago a placed a poll on the Vuurmuur Wiki, asking for the most important feature Vuurmuur needs. It turns out most people want traffic shaping. Traffic shaping has been on my todo list for a long time, but i never really got into using it, let alone understand it enough to integrate it into a GUI. So the last couple of days i had some spare time, and i have been checking it out. So far i am distinguishing the following types of traffic shaping.

First there is simple priorization: my VoIP/Gaming traffic should have priority over people up- and downloading ISO images. This is quite simple, and could be done using setting the ToS and creating some rules for that. In Vuurmuur, setting ToS could for example be done in a service.

Second, there is some more advanced priorization, with soft limits. This could for example be used in a situation where you say VoIP/Gaming should have a guaranteed bandwith of 20kb/s, but if on VoIP is active or not using the full 20kb/s, other traffic is allowed to use the 20kb/s in addition to the other bandwidth. Most important here is to keep interactive traffic responsive.

Third, the hard limits. For example saying that p2p should never be able to use more than 40kb/s, no matter how many bandwidth you have available. This could also be useful for assigning speed limits to specific hosts, for example in hosting companies.

Fourth and last, there is some misc stuff for which shaping can be useful, like limiting the rate of SYN packets, giving smaller packets priority over larger, etc.

Okay, on to my baby steps:

DEV=ppp0
$TC qdisc add dev $DEV root handle 1: htb default 30

This creates a htb root qdisc, which defaults to class 1:30.

MAX_PPP_UP=512kbit
$TC class add dev $DEV parent 1: classid 1:1 htb rate $MAX_PPP_UP

Here we create the class, where we define the max speed of this class to be MAX_PPP_UP.

MAX_PPP_UP_BULK=350kbit
$TC class add dev $DEV parent 1:1 classid 1:10 htb rate 100kbit ceil $MAX_PPP_UP burst 4k prio 1
$TC class add dev $DEV parent 1:1 classid 1:20 htb rate $MAX_PPP_UP_BULK burst 0k prio 2
$TC class add dev $DEV parent 1:1 classid 1:30 htb rate 200kbit burst 1k prio 3
$TC class add dev $DEV parent 1:1 classid 1:40 htb rate 100kbit burst 0k prio 4

Here we define the actual limits. The first rule gets 100kbit guaranteed, but as a ceiling of the maximum speed. It has the highest priority. The second class is for bulk uploading, and it is set to about 70% of the maximum upload speed. With this set, i can upload at about 40kb/s, and still have a ping of around 80-100ms, while setting this higher will cause it to go into the 200+ms levels very quickly. I’ve also disabled burst for this class, because i don’t want ping spikes. The other two have hard limits, and can be used to really rate limit some traffic.

Like stated above, unclassified traffic gets into the default class 1:30. To have some traffic go into another class, i’m using the iptables CLASSIFY target:

# icmp gets high prio
$IPTABLES -t mangle -A FORWARD -i eth0 -o ppp0 -p icmp -j CLASSIFY –set-class 1:10

# http data from dmz to wan is bulk
$IPTABLES -t mangle -A FORWARD -i eth1 -o ppp0 -p tcp –sport 80 -j CLASSIFY –set-class 1:20

I like the CLASSIFY iptables target over the tc filter rules because it enables me to use the netfilter connection tracking helpers. This way i could for example say:

$IPTABLES -t mangle -A FORWARD -i eth0 -o ppp0 -m helper –helper sip -j CLASSIFY –set-class 1:10

So this way all traffic related to the SIP VoIP connection (the RTP stream) gets into the highest priority class.

This is all egress shaping, the only shaping that works well, or so everyone says. Ingress shaping is not as easy, for a number of reasons. First, we have no real control over the rate of traffic being sent to us. Second, linux shaping is not as advanced for ingress shaping as it is for egress shaping. IMQ and later IFB have been invented to deal with this, but i have never looked at it yet.

However, in a gateway setup, egress shaping can do all we need. Traffic that comes in on my ppp0 interface, gets out on my eth1 interface. At this eth1 interface we can do egress shaping for incoming traffic coming in on ppp0.

This about sums up my first attempt at understanding and using traffic shaping. So far i think it works very well. The next big question will be how this can be integrated into Vuurmuur. If i get some ideas about this, i’ll post them here.

Oh yeah, if anyone is interested in participating in this process, i have setup a page on the wiki to help determine what we want and how we want to do it: here. Feel free to add to it, edit, etc.

ModSecurity: further improvements to the reverse proxy

People can reach my webserver in three ways: by my domain inliniac.net, by the hostname connected to my dsl, and by my ipaddress. What i now wanted is setup the proxy in such a way, that only people visiting inliniac.net would be proxied to the webserver.

Blocking requests that are IP based instead of name based have an important advantage. IP based requests are mostly used by scantools and other forms of malicious traffic that just attempt connecting to port 80 on large IP-ranges. So this way one should be able to keep a lot of crap like worm traffic out.

Implementing this turned out to be a little more complicated than i thought. Essentially the only way i got it working was by creating three virtual hosts and put the proxy configuration in the virtual host for inliniac.net. The other two virtual hosts just deny access, so visiting them gives a 403.

Willam Metcalf told me that the server signature rewrite function from ModSecurity does not hide the original server signature in all cases. In normal 200 and 300 series responses, the original signature is still in the header. Enabling the ‘header’ module and adding this to your config, helps:

Header set Server “Apache”

This way people will know you run Apache, but won’t know which version.

Vuurmuur: a new audit: passed

Last week a user of Vuurmuur let me know he had another security audit at his work, and Vuurmuur passed without any remarks whatsoever. The auditors even said that this was quite unusual.

The user is working in a Dutch company involved in stocktrading, and are forced to have the same level of security as their parent company, which is a bank. After the last time they had an audit, i added the auditlog feature to Vuurmuur, and it seems that has pleased them because unlike last time, they didn’t even complain about Vuurmuur’s beta status 😉

Now, i don’t know any specifics about the audit, so take it for what it’s worth. I still think it is cool to see Vuurmuur pass the security checks of financial institutions though!

Sguil: full content logging in combination with Snort_inline, revisited *again*

Note to self: never assume something works, instead, test it.

Yesterday there was some discussion in the #snort channel over whether or not passing multiple interface to snort works or not. As a reminder, some time ago i noted that passing two interfaces to snort like this: ‘snort -i eth0:eth1’ worked just fine. However, common mentioned in irc that he could not imagine it to be working. Determined to proof him wrong, i decided to run a few test. On my gateway, i ran ‘snort -v -i eth0:eth1 ip proto 1’. This should print all ICMP packets to the screen for both interfaces. The first clue that something wasn’t right was this message:

OpenPcap() device eth0:eth1 network lookup:
eth0:eth1: no IPv4 address assigned

Anyhow, i continued a pinged the gateway from the eth0 network. Worked fine. Then from the eth1 network. No dice. Damn. So i switched the interfaces like this ‘snort -v -i eth1:eth0 ip proto 1’. Guess what? Now eth1 worked and eth0 didn’t.

This was about the time i also remembered that in Sguil i had a few cases where i didn’t get any data in a transscript, although it should have been there. Because i am very busy, i had not yet investigated it.

On #snort a few more people said that it didn’t work for them, but for Joel Esler it still does. Weird. Anyhow, i am now back to running sancp and the full content logger on the ‘any’ pseudo interface, both with a BPF filter excluding local loopback from being recorded. So that look like this ‘snort -v -i any not host 127.0.0.1’.

What remains is the nat issue, but i have decided that i also want the full content logging on the wan side, so i think there is no solution for the double recording of natted connections.

ModSecurity: redirection

Another nice feature of ModSecurity is rule based redirection. Lets say i want to block visitors of my website from opening the login page of wordpress, /blog/wp-login.php. I could of course just deny access to it, so the visitor gets a 403 error. This works fine, however sometimes you might want to use a more userfriendly message, for example: ‘Due to maintainance logins are currently disabled’.

To do this i first created a very simple html file called nologin.html, and placed it in the webroot of the server. Then i added the following rules to Mod_Security:

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

These rules check first if the ipaddress is not 192.168.1.2, then look for /wp-login.php in the URI. If it is found, the request is logged and blocked. The server then sends a redirect 302 response to the client which will open the nologin.html page. Since the original request is blocked, the webserver behind the reverse proxy never sees the request.

ModSecurity: directory hiding a.k.a. security by obscurity

Ok, that’s a bit misleading, because i’m not just hiding, but also blocking and logging. What i wanted is this: I’m running awstats on my reverse proxy, but i don’t want anyone to know. So i just made the entire ‘cgi-bin’ part forbidden for everyone, so that covers the script. The fact that my webserver has a cgi-bin directory is nothing special and won’t tell you i’m using awstats. However, awstats also uses icons, and these are by default in /awstats-icon/

Now, i could have made that restricted as well, but that still would give you the information that it exists! ModSecurity to the rescue. I want only access to awstats from my workstation, so i added these rules:

SecFilterSelective REMOTE_ADDR “!192.168.1.2” chain
SecFilterSelective REQUEST_URI “/awstats-icon/” log,deny,status:404

These say: if the ipaddress of the visitor is not 192.168.1.2, and his request contains /awstats-icon/, we log it, block it, and send back a 404 error. This makes the visitor think the directory doesn’t exist on the server.

I’m not sure how easy this can be extended to giving an entire subnet access though, maybe i’ll investigate this later.