SECURITY RESEARCH, TOOLS |

Defending WordPress with OSSEC

In a previous post, I covered the ways a WordPress site can be attacked. Using the open source OSSEC the majority of those attacks can be detected and even blocked at the system level.

OSSEC LogoOSSEC is a host based Intrusion Detection System (HIDS). It can also be installed as an Intrusion Prevention System (IPS) as it has the capability of blocking attacks in real time as they are detected.

Using OSSEC requires you to have full control of your server, generally, this means either hosting on a dedicated server or a VPS. In a shared hosting or managed WordPress environment, protection at the system level is the responsibility of the hosting company.

Detecting WordPress attacks

During the installation of OSSEC you choose to have the system run in IDS (passive monitoring) or IPS (active response) mode.

When using the active response option real time firewall blocking will stop attackers in their tracks. If you are using the HackerTarget.com vulnerability scanning service or your own scanning solution you need to white list the IP addresses of the scanning servers.

In a default installation of OSSEC, some common WordPress attacks will be detected and blocked automagically if in active response (IPS) mode. If you are using non-blocking mode (IDS), an email will usually be generated to alert you to the fact that an attack is underway.

Attackers brute forcing plugins, themes or timthumb's will find themselves blocked by the level 6 rule that detects multiple 404's. If your site is broken and does produce several 404's for normal visitors you may want to confirm that legitimate visitors are not being blocked by this rule.

Alert example

Let's examine the alert below generated by the Multiple 404 rule. This was generated by the WPScan WordPress security testing tool that is looking for readable versions of the wp-config.php file. This file contains database details, including the password.

This alert was found in the /var/ossec/logs/alerts/alerts.log file.

** Alert 1383085992.19700: mail  - web,accesslog,web_scan,recon,
2013 Oct 30 09:33:12 xwing01->/var/log/apache2/access.log
Rule: 31151 (level 10) -> 'Multiple web server 400 error codes from same source ip.'
Src IP: 192.168.1.50
192.168.1.50 - - [30/Oct/2013:09:33:12 +1100] "GET /wordpress/wp-config.php.old HTTP/1.1" 404 487 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0"
192.168.1.50 - - [30/Oct/2013:09:33:12 +1100] "GET /wordpress/wp-config.old HTTP/1.1" 404 483 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0"
192.168.1.50 - - [30/Oct/2013:09:33:12 +1100] "GET /wordpress/wp-config.save HTTP/1.1" 404 484 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0"
192.168.1.50 - - [30/Oct/2013:09:33:12 +1100] "GET /wordpress/wp-config.php.bak HTTP/1.1" 404 487 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0"
192.168.1.50 - - [30/Oct/2013:09:33:12 +1100] "GET /wordpress/wp-config.bak HTTP/1.1" 404 483 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0"
192.168.1.50 - - [30/Oct/2013:09:33:12 +1100] "GET /wordpress/wp-config.php_bak HTTP/1.1" 404 487 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0"
192.168.1.50 - - [30/Oct/2013:09:33:12 +1100] "GET /wordpress/wp-config.php.swo HTTP/1.1" 404 487 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0"

The test OSSEC installation has active response enabled, so the source IP address 192.168.1.50 is automatically blocked with a firewall rule.

Notice the above alert was from Rule 31151 that is classed as level 10. The default active response (block) level is any rule level 6 or greater, this can be found in the /var/ossec/etc/ossec.conf file.

The triggered active responses can be seen in the log /var/ossec/logs/active-responses.log. After 10 minutes (600 second default) the block rule is removed.

Wed Oct 30 09:33:12 EST 2013 /var/ossec/active-response/bin/host-deny.sh add - 192.168.1.50 1383085992.19700 31151
Wed Oct 30 09:33:12 EST 2013 /var/ossec/active-response/bin/firewall-drop.sh add - 192.168.1.50 1383085992.19700 31151
Wed Oct 30 09:43:43 EST 2013 /var/ossec/active-response/bin/host-deny.sh delete - 192.168.1.50 1383085992.19700 31151
Wed Oct 30 09:43:43 EST 2013 /var/ossec/active-response/bin/firewall-drop.sh delete - 192.168.1.50 1383085992.19700 31151

Following the testing using WPScan I tried to brute force the user account 'admin2'. This valid user account was detected by enumerating with the author archives method.

Against a low-end VPS, an attacker can brute force a WordPress user account with around 500 passwords per minute. That is 720000 passwords per day. Without security monitoring these attacks continue until the correct password is found!

Using the Nmap NSE WordPress password brute force script I attempted a password brute force.

root@xwing01:~# nmap -sV --script http-wordpress-brute --script-args 'http-wordpress-brute.uri=/wordpress/wp-login.php' 192.168.1.50

Starting Nmap 6.25 ( http://nmap.org ) at 2013-10-30 10:15 EST
Stats: 0:05:08 elapsed; 0 hosts completed (1 up), 1 undergoing Script Scan
NSE Timing: About 33.33% done; ETC: 10:30 (0:10:06 remaining)
Nmap scan report for 192.168.1.50
Host is up (0.0000050s latency).
Not shown: 996 closed ports
PORT     STATE SERVICE         VERSION
80/tcp   open  http            Apache httpd 2.2.22 ((Ubuntu))
| http-wordpress-brute: 
|   Accounts
|     No valid accounts found
|   Statistics
|_    Performed 244 guesses in 605 seconds, average tps: 0
443/tcp  open  ssl             SSLv3
902/tcp  open  ssl/vmware-auth VMware Authentication Daemon 1.10 (Uses VNC, SOAP)
3000/tcp open  ntop-http       Ntop web interface 4.99.3

Service detection performed. Please report any incorrect results at http://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 610.98 seconds

This attack was blocked by a rule triggered by the multiple WordPress login attempts. This default OSSEC rule will auto block (or alert) if an attacker attempts to brute force user accounts.

** Alert 1383088521.45613: - web,appsec,attack
2013 Oct 30 10:15:21 xwing01->/var/log/apache2/access.log
Rule: 31510 (level 6) -> 'WordPress wp-login.php brute force attempt.'
Src IP: 192.168.1.50
192.168.1.50 - - [30/Oct/2013:10:15:20 +1100] "POST /wordpress/wp-login.php HTTP/1.1" 200 3598 "-" "Mozilla/5.0 (compatible; Nmap Scripting Engine; http://nmap.org/book/nse.html)"
192.168.1.50 - - [30/Oct/2013:10:15:20 +1100] "POST /wordpress/wp-login.php HTTP/1.1" 200 3598 "-" "Mozilla/5.0 (compatible; Nmap Scripting Engine; http://nmap.org/book/nse.html)"
192.168.1.50 - - [30/Oct/2013:10:15:20 +1100] "POST /wordpress/wp-login.php HTTP/1.1" 200 3598 "-" "Mozilla/5.0 (compatible; Nmap Scripting Engine; http://nmap.org/book/nse.html)"
192.168.1.50 - - [30/Oct/2013:10:15:19 +1100] "POST /wordpress/wp-login.php HTTP/1.1" 200 3598 "-" "Mozilla/5.0 (compatible; Nmap Scripting Engine; http://nmap.org/book/nse.html)"
192.168.1.50 - - [30/Oct/2013:10:15:19 +1100] "POST /wordpress/wp-login.php HTTP/1.1" 200 3598 "-" "Mozilla/5.0 (compatible; Nmap Scripting Engine; http://nmap.org/book/nse.html)"
192.168.1.50 - - [30/Oct/2013:10:15:19 +1100] "POST /wordpress/wp-login.php HTTP/1.1" 200 3598 "-" "Mozilla/5.0 (compatible; Nmap Scripting Engine; http://nmap.org/book/nse.html)"

Tuning

Without active response enabled these rules will send an email alert advising you of the attack. In recent months there was a massive increase in automated brute force attacks. This resulted in a steady stream of alert emails for those monitoring their WordPress. Excessive alerts can easily be suppressed. In IDS speak this is known as tuning.

Add a new rule to OSSEC

It is not difficult to create custom rules. The following rule is added to get visibility into attackers performing reconnaissance against a WordPress installation. As seen in the Attacking WordPress article, finding the exact version of the WordPress installation is achieved by looking for the presence of the /readme.html file.

To create a rule to detect recon against /readme.html, add the following to the local_rules.xml file.

<rule id="100040" level="6">
   <if_sid>31100</if_sid>
   <match>readme.html</match>
   <description>WordPress Recon - /readme.html accessed.</description>
</rule>

This rule will trigger whether you have deleted (recommended) the /readme.html or not. The rule simply looks for a matching HTTP request in the web servers log file that has the string /readme.html.

** Alert 1383091680.53706: - local,syslog,
2013 Oct 30 11:08:00 xwing01->/var/log/apache2/access.log
Rule: 100040 (level 6) -> 'WordPress Recon - /readme.html accessed.'
Src IP: 192.168.1.50
192.168.1.50 - - [30/Oct/2013:11:07:58 +1100] "GET /wordpress/wp-admin/css/install.css?ver=20100228 HTTP/1.1" 304 210 "http://192.168.1.50/wordpress/readme.html" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.34 Safari/537.36"

File integrity checks

A powerful feature of OSSEC is file integrity checking. This feature detects changes to the servers file system indicating a compromise has occurred, or a problem in the system. We can also add the WordPress installation path to the directories that are checked in the file integrity monitoring.

Here is the relevant part of the /var/ossec/etc/ossec.conf file that requires changing if you wish to add the WordPress installation path to the file. It is also possible to change the frequency of the checks as currently it is configured to check once every 22 hours.

 <syscheck>
    <!-- Frequency that syscheck is executed - default to every 22 hours -->
    <frequency>79200</frequency>
    
    <!-- Directories to check  (perform all possible verifications) -->
    <directories check_all="yes">/etc,/usr/bin,/usr/sbin,/var/www/wordpress</directories>
    <directories check_all="yes">/bin,/sbin</directories>

    <!-- Files/directories to ignore -->
    <ignore>/etc/mtab</ignore>
    <ignore>/etc/mnttab</ignore>
    <ignore>/etc/hosts.deny</ignore>

If you add the WordPress path to the file monitoring in the ossec.conf, you may need to include ignore paths for the uploads and any caching folders as these contain files that regularly change.

The benefit of adding the WordPress path to your file integrity monitoring is if someone does compromise the system and adds nasty javascript or dodgy PHP to any of your WordPress files, this will be detected and you will be alerted.

Default Rules for Server Monitoring

In addition to directly monitoring the WordPress application and Web server logs, having OSSEC on your host will also detect:

  • SSH brute force attempts
  • New users added to the system
  • First time user logged in
  • New services (backdoors!) listening (netstat diff)
  • lots more..... take a look at /var/ossec/rules/
One of the advantages of using the OSSEC approach is you do not need to add any plugins to your WordPress installation. While there are solid security plugins available for WordPress, it is preferable to minimise the use of plugins of any sort in WordPress installations. Reducing the number of plugins is a simple way to reduce the size of your attackable footprint.

In Conclusion

Spending 10 minutes setting up OSSEC on your server will provide you with a solid base of security monitoring. With a small investment of time and the right tools, your WordPress install can be as secure as the big boys. Get OSSEC, Get Visibility.

Test WordPress and Server Security in 2 Clicks

Scan Now