File Uploads and Mod_security vs. WordPress wp-admin/admin-ajax.php

By Ken | Website

May 12

After having a site hacked because mod_security was disabled I’ve been in search of a better way to allow WordPress to work and still have mod_security running. There are many places that recommend placing the following code in your site .htaccess file:
<IfModule mod_security.c>
SecFilterEngine Off
SecFilterScanPOST Off
</IfModule>

DO NOT DO THIS! Else you’ll likely fall victim to the same SQL Insertion hack I did that allowed the infiltrator to directly change elements of my database and redirect the site. Thankfully the damage was very minor, limited to a few WordPress configuration changes that were easily undone. It could have been much, much worse.

In my case, there were two separate issues to contend with as exhibited in the Apache server error log.

Case 1: Patern Match

You will see a line in the server error log that contains text similar to:

mod_security: Access denied with code 403. Pattern match "!(^application/x-www-form-urlencoded$|^multipart/form-data;)" [severity "EMERGENCY"] [hostname "hostname"] [uri "/wp-admin/admin
-ajax.php"]

In some cases the code might be other than 403 and the quoted pattern might be different. Note that the uri field will point to the location of the admin-ajax.php script in your install. There are several options to correct this false positive without completely disabling mod_security.

  • Fix the mod_security rule that defines the pattern.

    There are a number of references that indicate the mod_security rule is incorrect. A good summary can be found at The Team Extreme Blog. What it all boils down to is improper matching of the content type application/x-www-form-urlencoded. The suggested rule requires that the content type match exactly. In at least one failing case, this string has been observed to have the value application/x-www-form-urlencoded; UTF-character8. A possible solution is to remove the “$” at the end of the related phrase in the filter rule. For example, it should read:
    SecFilterSelective HTTP_Content-Type "!(^$|^application/x-www-form-urlencoded|^multipart/form-data;)"
    Another option would be to add the offending string to the Filter rule, for example:
    SecFilterSelective HTTP_Content-Type "!(^$|^application/x-www-form-urlencoded$|^application/x-www-form-urlencoded; UTF-character8$|^multipart/form-data;)"

  • Add wp-admin/admin-ajax.php to mod_security white list

    My host provider made this change to the mod_security rules so I can’t report on the specific changes they made. The blog No Logo Required has some whitelisting instructions. I’ve not tried this myself so I can’t confirm the instructions.

  • Disable mod_security filter ONLY for admin-ajax.php

    This might work:
    <IfModule mod_security.c>
    <Files admin-ajax.php>
    SecFilterInheritance Off
    </Files>
    </IfModule>

Case 2: Error processing request body

Once I had the filter issue resolved, I was getting a new log entry containing the following:
mod_security: Access
denied with code 403. Error processing request body: Multipart: final boundary m
issing [severity "EMERGENCY"] [hostname "hostname"] [uri "/wp-admin/admin
-ajax.php"]

It seems that some (all?) versions of the flash player send a poorly formatted message body that gets tripped up on mod_security rules. The javascript library in WordPress that handles the image uploads is SWFupload and it requires Flash to operate. The reliance on Flash is creating other problems as well. At least for now, it looks like the solutions are limited as there is no clear ajax based replacement for SWFupload in WordPress.

Some searching exposed the solution in an article at Intersice Solutions. Based on that information and a check on the modsecurity.org site, I placed the following in the .htaccess file in my wp-admin directory:
<IfModule mod_security.c>
SetEnvIfNoCase Content-Type "^multipart/form-data;" "MODSEC_NOPOSTBUFFERING=Do n
ot buffer file uploads"
</IfModule>

Leave a Comment:

Leave a Comment:

css.php