Skip to content

Shared hosting attack mitigation, part 1: Apache MPM-ITK

When it comes to shared hosting we often get to see the same patterns and CMS installs over and over again. We have the big guns: Joomla, WordPress, Drupal, Typo3. And then there are smaller guys like e107, eZ Publish, XOOPS. Occasionally we run into TinyCMS, MiaCMS or even a YupiCMS install. They all have several things in common: they all try to be user friendly and easy to set-up. They’ll make you have a website online in a matter of hours or even minutes. So far, so good.

But what about patching? People tend to neglect to keep their installs up-to-date. We often get to hear people are afraid to break their corporate website or they rely on the web agency who built their website. However most of these agencies don’t want to take the risk either, unless there’s a hefty monthly support fee involved. And even when there is one they don’t always get around to do so.

This might become a serious problem for anyone running (on) a shared hosting server. XSS attacks, SQL injection and other kinds of intrusion might lead to collateral damage. Other people’s sites just might get attacked too. By default any vHost is readable and more importantly writeable by the user that is used to run PHP scripts. In most cases this is the Apache user.

If we can run our hosted PHP scripts using a separate user for each vHost we should be able to mitigate a large amount of common attacks towards other vHosts! However it isn’t feasible to run each hosting inside a separate chrooted environment. It would take too much time to set-up and it’s rather complex to patch it.

This is where Apache MPM-ITK comes into play. It’s an MPM (Multi-Processing Module) that is able to use a separate uid/guid per vHost without the need for a separate chroot for each hosting.

Enough chit-chat. Let’s get to it.

Install a default LAMP stack:

# apt-get install apache2-mpm-itk apache2-utils apache2.2-common 
defoma fontconfig-config libapache2-mod-php5 libapr1 libaprutil1 
libexpat1 libfontconfig1 libfreetype6 libgd2-xpm libjpeg62 
libltdl3 libmcrypt4 libpq5 libt1-5 libxpm4 openssl ssl-cert 
openssl-blacklist php5-common php5-cli php5-gd php5-mcrypt 
php5-mysql ttf-dejavu ttf-dejavu-core ttf-dejavu-extra

If you’re already running a LAMP stack it’s easy to replace the default MPM:

# apt-get remove apache2-mpm-prefork
# apt-get install apache2-mpm-itk

Configuring MPM ITK isn’t exactly brain surgery. Simply add an IfModule statement to your existing vHost config or use the following example to create a new one:

# cat /etc/apache2/sites-available/vhost-example.conf
<VirtualHost *:80>
  <IfModule mpm_itk_module>
    AssignUserId example example
  </IfModule>

  DocumentRoot /var/www/vhosts/example/public_html/
  ServerName example.com
  ServerAlias www.example.com

  CustomLog /var/www/vhosts/example/logs/access_log combined
  ErrorLog /var/www/vhosts/example/logs/error_log

  ScriptAlias /cgi-bin/ /var/www/vhosts/example/cgi-bin/
  DirectoryIndex index.php index.html index.htm

  <Directory "/var/www/vhosts/example/cgi-bin/">
    Options +ExecCGI
    AllowOverride none
  </Directory>
</VirtualHost>

Don’t forget to create the default user and appropriate folders. Change the permissions afterwards:

# useradd example
# mkdir -p /var/www/vhosts/example/
# mkdir -p /var/www/vhosts/example/public_html/
# mkdir -p /var/www/vhosts/example/cgi-bin/
# mkdir -p /var/www/vhosts/example/logs/
# chown -R example:example /var/www/vhosts/example/

Once this has been done, enable your website and test the configuration before reloading the Apache daemon:

# a2ensite vhost-example.conf
Enabling site vhost-example.conf.
Run '/etc/init.d/apache2 reload' to activate new configuration!

# apache2ctl configtest
Syntax OK

# /etc/init.d/apache2 reload
Reloading web server config: apache2.

And that’s it! Use phpinfo(); if you want to check you’re actually running on MPM ITK. It should be listed in Loaded Modules. Another way to verify is using ps or top. The PHP scripts for your newly created vHost should be running on it’s own separate user:

15059 example 20  0 24596 5624 2468 R  0.7  3.9  0:00.02 apache2
15060 example 20  0 24596 5496 2340 R  0.7  3.8  0:00.02 apache2
15061 example 20  0 24596 5412 2256 R  0.7  3.7  0:00.02 apache2
15062 example 20  0 24596 5360 2204 R  0.7  3.7  0:00.02 apache2

There is obviously a performance penalty involved when using MPM ITK.
I’ve compared both the default MPM Prefork and MPM ITK using Apache Bench and phpinfo() serving the content:

# ab -n 2000 -c 4 http://example.com/index.php

mpm prefork vs mpm itk

Please do bear in mind that this was tested on low power hardware (Atom 1.6GHz cpu).

Published inHowto'sLinuxNewsSecurity

10 Comments

  1. Gunawan34 Gunawan34

    I would like to say “wow” what a inspiring post. This is really great. Keep doing what you’re doing!!

  2. Mike Franks Mike Franks

    Very useful article, but what about mysql injection attacks. Those would still be a danger with this, right? Please tell me I’m wrong. 🙂

  3. Tom Tom

    This blog post was only about Apache’s worker/threading security and possible privilege escalation issues triggered by (php) scripts. To counter MySQL injections you’d need an application firewall like mod_security. That’s however for another blog post. 🙂

    In the meantime you can find more information at http://www.modsecurity.org/.

  4. hi, Tom.
    Thx for the tests, but have You tested with mod_fcgid?

  5. Tom Tom

    Not yet. I’ve only tested it with mod_php.

  6. This post is exactly what I was looking for. Many thanks.

  7. StandDuPp StandDuPp

    Very useful ! I tested !

  8. header. Old HTTP/1.0 clients do not send such a header and Apache has no clue what vhost the client tried to reach (and serves the request from the primary vhost). To provide as much backward compatibility as possible we create a primary vhost which returns a single page containing links with an URL prefix to the name-based virtual hosts.

Leave a Reply

Your email address will not be published. Required fields are marked *

Time limit is exhausted. Please reload CAPTCHA.