Have you been wp-gdpr-compliance’d?

An ugly vulnerabilty in the wordpress plugin wp-gdpr-compliance was recently discovered and reported by Mikey Veenstra of wordfence. Please read his very comprehensive write-up of the vulnerability and its IOC right after updating to the latest version to be safe.

Since I was also using the plugin, this vulnerability was giving me a headache today. Based on wordfences report, I wrote a quick and dirty shellscript to search for indicators of compromise on the various wordpress hosts I am sadly administrating. As usual, please do not run the script without thouroughly checking und understanding what it does. You will likely need to modify constants and paths.

Also, please make sure you stay up to date and on top of things while other researchers discover more indicators of compromise and develop better detection techniques.

#!/usr/bin/env bash
WEBROOT="/var/www/wordpress/" # the folder you keep your wordpress in
DATABASE="enter_db_name_here" # the mysql db name
USERTABLE="wp_users" # the wordpress user table name (prefix + 'users')
OPTIONSTABLE="wp_options" # the wordpress options table name (prefix + 'users')
FRIENDLY_IP="xx.xx.xx.xx" # the IP address which you left in your logs when updating wp-gdpr-compliance :-)
echo "ATTACK ATTEMPTS:"
grep "/wp-admin/admin-ajax.php" /var/log/nginx/access.log | grep "Nov/2018" | grep -v $FRIENDLY_IP # change the acccess.log location according to your config
echo "WORDPRESS USERS:"
mysql -u root << EOF
use $DATABASE;
select * from $USERTABLE;
EOF
echo "SUSPICIOUS OPTIONS:"
mysql -u root << EOF | grep 2mb_autocode
use $DATABASE;
select * from $OPTIONSTABLE;
EOF
echo "INFECTED FILES:"
find $WEBROOT -type f -exec md5sum {} \; | grep 'b6eba59622630b18235ba2d0ce4fcb65\|c62180f0d626d92e29e83778605dd8be'

The script does the following:

Under “ATTACK ATTEMPTS:” it will list request to the vulnerable php file. In my case, they looked like this:

109.234.37.214 - - [08/Nov/2018:08:31:47 -0500] "POST /wp-admin/admin-ajax.php HTTP/1.1" 403 33 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.143 Safari/537.36"
109.234.39.250 - - [08/Nov/2018:13:47:18 -0500] "POST /wp-admin/admin-ajax.php HTTP/1.1" 403 33 "https://linus-neumann.de/wp-login.php?action=rp" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.143 Safari/537.36"

The IP addresses 109.234.37.214 and 109.234.39.250 have been identified by wordfence as a common source of attacks, so this is not a good thing to find in your logs. (As you may already notice, the requests were not permitted and responded to with a 403 status code due to additional security configurations described below.)

Under “WORDPRESS USERS:”, it will list all active wordpress users. Check for any unknown or unauthorized users, in particular usernames including the string “trollherten” – remove them immediately, if found.

Under “SUSPICIOUS OPTIONS:”, it will list your wordpress options IF the plugin “2MB autocode” is installed. This is a bad sign unless you have intentionally installed it.

Finally, unter “INFECTED FILES:”, it scans your webroot for file hashes of the reverse shells the reported wave of attacks commonly placed there. Remove these files immediately, if any are found.

Why I was (apparently) not affected

In my case, no indicators of compromise were found despite an attack attempt and my site using a vulnerable version of the plugin.

The vulnerabilty enables attackers to change values in the wordpress options table. In the comman attack scenarios, the change the options to allow new user registration and to change the default role to administrator.

Once they have changed these settings, the can use wp-login.php to create a new user and then access wp-admin/ with this user’s administrative privileges.

However, I have restricted access to both locations on the webserver level by an additional http basic authorization in the site configuration:

location /wp-login.php {
auth_basic "Restricted Content";
auth_basic_user_file /etc/nginx/.htpasswd;
}
location /wp-admin {
auth_basic "Authorization Required";
auth_basic_user_file /etc/nginx/.htpasswd;
}

I have been doing this for years and this is not the first time this setting saved my sorry ass 🙂