This week, a denial of service vulnerability within WordPress was disclosed publicly, after the WordPress team refused to acknowledge it as a legitimate bug; despite an attacker being able to single handedly bring down the service.

As of 6th February 2018, there is still no official patch, despite an effective proof of concept being released by the original reporter of the problem (which can be seen in use in the cover image of this post).

The author released A Batch Script to patch the core code, however, this could be easily overwritten again by future WordPress updates.

An alternative to this, if you’re using Apache, is to use ModSecurity. The steps to set this up are going to be on the presumption you are using a Debian based system with apt.

Installing & Configuring The Module

First, install the ModSecurity module:

apt install libapache2-modsecurity

Next, create the default configuration file by copying the example conf file:

mv /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf

Now, open /etc/modsecurity/modsecurity.conf in whatever visual editor you prefer, and ensure the SecRuleEngine option is set to on. By default, this will be set to DetectionOnly.

Lastly, open /etc/apache2/mods-enabled/security2.conf, and verify that there is a line which reads IncludeOptional /etc/modsecurity/*.conf. If not, modify it so that it looks similar to the below:

<IfModule security2_module>
        # Default Debian dir for modsecurity's persistent data
        SecDataDir /var/cache/modsecurity

        # Include all the *.conf files in /etc/modsecurity.
        # Keeping your local configuration in that directory
        # will allow for an easy upgrade of THIS file and
        # make your life easier
        IncludeOptional /etc/modsecurity/*.conf
</IfModule>

Now, restart the Apache service and visit a web page, to ensure the default configuration is working:

service apache2 restart

Adding Protection Against The Vulnerability

To add the detection of CVE-2018-6389, create a new file in /etc/modsecurity and ensure it ends with .conf, e.g. /etc/modsecurity/cve-2018-6389.conf, and insert the below rule into the file:

SecRule REQUEST_URI "@rx (?i:/wp-admin/load-(styles|scripts)\.php\?.*?(load%5B%5D|load\[\]|load%5B\]|load\[%5D)=([^&,]*,){20,})" "id:1,msg:'Potential use of CVE-2018-6389',deny"

This will detect when more than 20 scripts are being loaded using load-scripts.php or load-styles.php, and if so - block the request. If you wish to lower or raise this threshold, simply change the number 20 to whatever value you prefer.

After placing this file in /etc/modsecurity, reload the service again:

service apache2 restart

Testing The Mitigation

In order to test that any attacks are blocked, issue the following curl request, and a 403 should be returned:

curl "http://wordpress.vm/wp-admin/load-scripts.php?c=1&load%5B%5D=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21&ver=4.9"

You should see output akin to the below:

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>403 Forbidden</title>
</head><body>
<h1>Forbidden</h1>
<p>You don't have permission to access /wp-admin/load-scripts.php
on this server.<br />
</p>
<hr>
<address>Apache/2.4.18 (Ubuntu) Server at wordpress.vm Port 80</address>
</body></html>

After confirming the ruleset to be working, re-running the original proof of concept will now no longer send the CPU usage roaring to 100%:

Further Mitigation

With ModSecurity now in place, any detections of this ruleset will now also be logged in /var/log/apache2/modsec_audit.log.

If you tail the file, you should be able to see the test being successfully blocked:

root@ubuntu:~# tail -n 100 /var/log/apache2/modsec_audit.log
***
[06/Feb/2018:14:39:36 --0800] WnouqH8AAQEAAAy6lV8AAAAE 10.2.0.1 59952 10.2.0.4 80
--2c170148-B--
GET /wp-admin/load-scripts.php?c=1&load%5B%5D=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21&ver=4.9 HTTP/1.1
Host: wordpress.vm
User-Agent: curl/7.47.0
Accept: */*

--2c170148-F--
HTTP/1.1 403 Forbidden
Content-Length: 312
Content-Type: text/html; charset=iso-8859-1

--2c170148-E--
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>403 Forbidden</title>
</head><body>
<h1>Forbidden</h1>
<p>You don't have permission to access /wp-admin/load-scripts.php
on this server.<br />
</p>
<hr>
<address>Apache/2.4.18 (Ubuntu) Server at wordpress.vm Port 80</address>
</body></html>

--2c170148-H--
Message: Access denied with code 403 (phase 2). Pattern match "(?i:/wp-admin/load-(styles|scripts)\\.php\\?.*?(load%5B%5D|load\\[\\]|load%5B\\]|load\\[%5D)=([^&,]*,){20,})" at REQUEST_URI. [file "/etc/modsecurity/cve-2018-6389.conf"] [line "1"] [id "1"] [msg "Potential use of CVE-2018-6389"]
Action: Intercepted (phase 2)
Apache-Handler: application/x-httpd-php
Stopwatch: 1517956776182873 435 (- - -)
Stopwatch2: 1517956776182873 435; combined=20, p1=8, p2=9, p3=0, p4=0, p5=3, sr=0, sw=0, l=0, gc=0
Response-Body-Transformed: Dechunked
Producer: ModSecurity for Apache/2.9.0 (http://www.modsecurity.org/).
Server: Apache/2.4.18 (Ubuntu)
Engine-Mode: "ENABLED"

--2c170148-Z--

The content of this file can now be used with other packages, such as fail2ban in order to further protect the server from potential attackers.

References