An In-Depth Analysis Of The WP-VCD Malware

Published 2 December 2021
Updated 20 July 2023
Dave Jong
CTO at Patchstack
Table of Contents

The WP-VCD malware for WordPress has existed for many years. It mainly spreads by injecting itself into legitimate plugins and themes after which it will spread itself on sites that offer downloads to (nulled) WordPress plugins and themes.

We noticed that during the corona-virus pandemic, the WP-VCD malware has also started injecting itself into plugins that can show statistics related to the coronavirus.

These plugins might be particularly popular at the moment which gives the maker of the WP-VCD malware an advantage.

We analyzed some samples that were downloaded from www[dot]downloadfreethemes[dot]co. The samples taken from different themes and plugins offered on this site were all infected with this malware.

Similar sites that do the same kind of practices are:

  • themesubmit[dot]com
  • www[dot]downloadfreethemes[dot]space
  • freesoft[dot]royalbeats[dot]in
  • freedownloadthemes[dot]co
  • raybans[dot]com[dot]co
  • coursefree[dot]co

Analysis of the WP-VCD malware

Injection point

During the analysis of multiple samples, we noticed that all themes contained a file called class.theme-modules.php and all plugins contained a file called class.plugin-modules.php. Both files contained the exact same code.

In plugins, the class.plugin-modules.php file would be loaded in the main file of the plugin on the first line by injecting the following (reformatted):

<?php
if (file_exists(dirname(__FILE__) . '/class.plugin-modules.php'))
    include_once(dirname(__FILE__) . '/class.plugin-modules.php');
?>

In themes, the class.theme-modules.php file would be loaded in the functions.php file by injecting the following (reformatted):

<?php
if (file_exists(dirname(__FILE__) . '/class.theme-modules.php'))
    include_once(dirname(__FILE__) . '/class.theme-modules.php');
?>

The injected file

Note that the domain name which the malware uses to communicate can change often, in this scenario it was set to www[dot]arilns[dot]com. At the time of publication, it did not have a web server attached to it.

Initial execution flow

Refer to the overview of functions, constants, and variables at the bottom of the page to see what some of the variables mentioned in the execution flow do and contain.

WP-VCD Malware

1. It has to meet a few conditions

The initial malware is only executed when it meets a few conditions: the user is an administrator and any of the following conditions:

The user is on the themes.php pages or the action parameter in the URL is set to activate or the plugin parameter is present in the URL.

2. If the statement in 1. is true

If the statement in 1. is true, it will iterate through all folders in /wp-content/themes/ and inject $install_code into functions.php if the file exists.

If the functions.php file does not exist in the root folder of the theme, it will go one level deeper and iterate through all sub-folders and attempt to find functions.php yet again.

3. If it managed to inject the backdoor code into any file

If it managed to inject the backdoor code into any file, it will send a ping request to www[dot]arilns[dot]com/o.php with 2 query parameters:

-> The host parameter which contains $_SERVER['HTTP_HOST'].

-> The password parameter which contains $install_hash.

4. Once the ping has been sent

Once the ping has been sent, whether it was successful or not, it will retrieve the path to the root directory of the WordPress site.

Then it will execute the WP_URL_CD function which creates the /wp-includes/wp-vcd.php backdoor containing $GLOBALS['WP_CD_CODE'] and also injects it into /wp-includes/post.php.

5. Finally, it will get the code of itself and execute 2 calls

Finally, it will get the code of itself (and store that in $file) and execute 2 calls to preg_replace after which the only code left in the file is <?php error_reporting(0);?> making it seem as if nothing happened.

-> preg_replace('!//install_code.*//install_code_end!s', '', $file) will remove most initial injection code from itself. (The class.theme-modules.php or class.plugin-modules.php file.)

-> preg_replace('!<\?php\s*\?>!s', '', $file)will remove all <?php ?> tags of which there is only white-space in-between.

Analyzing $install_code

$install_code is injected into all functions.php files that are present in the /wp-includes/themes/ directories. The flow of this code is described below.

WP-VCD Malware

1. If the action and password parameters are present

If the action and password parameters are present in the request ($_REQUEST) and the password equals md5($_SERVER['HTTP_HOST'] . AUTH_SALT), it can execute 2 actions:

-> change_domain

Find the following in the code of the current file: $tmpcontent = @file_get_contents("http://(.*)/code.php and replace the domain name with the new domain name that is present in the newdomain request parameter.

-> change_code

Find the following in the code of the current file: //$start_wp_theme_tmp([\s\S]*)//$end_wp_theme_tmp and inject PHP code supplied by the newcode request parameter in-between the lines //$start_wp_theme_tmp and //$end_wp_theme_tmp.

2. If no actions were executed in step 1

If no actions were executed in step 1, it will check if the current script is not wp-cron.php and not xmlrpc.php.

If the current script does not equal these 2 values, it will send a request to any of the following domains, depending on if they respond properly to the request or not:

  • www[dot]arilns[dot]com/code.php
  • www[dot]arilns[dot]pw/code.php
  • www[dot]arilns[dot]top/code.php.

If it cannot send a request to any of these URL’s, it will retrieve content from /wp-includes/wp-tmp.php.

3. If the returning data contains the string

If the returning data from the request to code.php on these domains contains the string held in the $wp_auth_key variable, it will inject the PHP code into the /wp-includes/wp-tmp.php file.

If it cannot be injected into this file, it will try to inject it into the root directory of the current theme. If that also fails, it will try to inject it into wp-tmp.php in the current directory.

Analyzing wp-tmp.php

This file can contain pretty much anything defined by the malware creator. We have seen things from backdoors to advertisements that are injected into all pages of the site.

WP-VCD Malware

Since they can inject any kind of PHP code, there is pretty much no restriction as to what they are able to do on the site.

One sample that we have shows that it:

  • Injected advertisements loaded from deloplen[dot]com and pushosubk[dot]com.
  • It only performs any malicious activity if the referrer of the visitor is from a search engine and not a user who is logged in on the WordPress site.
  • Loads advertisement code from /wp-includes/wp-feed.php

Definitions

Constants

-> MAX_LEVEL: Defines how deep it should iterate through folders.

-> MAX_ITERATION: Defines how many files it can read from a folder.

-> P: The value of $_SERVER['DOCUMENT_ROOT'].

Globals & variables

-> $GLOBALS['WP_CD_CODE']: Contains a base64 encoded string that when decoded, is almost similar to the code of the malware file itself except that it doesn’t contain the function that spreads itself in the functions.php files.

-> $GLOBALS['stopkey']: Array of folders’ names. When the malware is scanning for folders/files to inject into, it will stop once it hits one of the folder names in this array.

-> $GLOBALS['DIR_ARRAY']: All folders that are found to be in the $GLOBALS['stopkey'] array will be added to this array.

-> $search: Array used in the SearchFile function to find the location of wp-config.php.

-> $install_code: Backdoor code that will be injected into multiple files.

-> $install_hash: String containing an MD5 hash of $_SERVER['HTTP_HOST'] and AUTH_SALTAUTH_SALT is taken from the wp-config.php file.

-> $install_code: Replaces the string '{$password}' with $install_hash in $install_code.

-> $wp_auth_key: A MD5 string, most likely used so certain requests can only be executed by the malware creator.

Functions

-> getDirList($path): Get all folders in $path.

-> WP_URL_CD($path):

-> If the file /wp-includes/post.php exists, it will create a file called /wp-includes/wp-vcd.php containing the base64 decoded value of $GLOBALS['WP_CD_CODE'].

-> If /wp-includes/post.php does not contain the string ‘wp-vcd’, it will inject the inclusion of /wp-includes/wp-vcd.php into the first line of /wp-includes/post.php: <?php if (file_exists(dirname(__FILE__) . 'wp-vcd.php')) include_once(dirname(__FILE__) . 'wp-vcd.php'); ?>

-> SearchFile($search, $path): Given the $path, keep searching the entire site until the file in $search is found.

-> file_get_contents_tcurl($url): Send a request to a URL and return its contents.

-> theme_temp_setup($phpCode):

-> Creates a new temporary file in PHP’s temporary directory in which it will inject $phpCode. Once the code has been injected, it will load the file and immediately delete it after which it will return all defined variables returned by the PHP function get_defined_vars().

-> If it cannot create a temporary file in PHP’s temporary directory, it will attempt to create the file in the current directory instead.

Keywords

  • class.plugin-modules.php
  • class.theme-modules.php
  • wp-vcd.php
  • wp-tmp.php
  • WP_V_CD
  • WP_URL_CD
  • WP_CD_CODE
  • arilns
  • downloadfreethemes.co
  • install_code
  • install_hash
  • theme_temp_setup

How to protect a WordPress site from the WP-VCD Malware?

To protect your site from the WP-VCD malware you should not download plugins and themes from sites that offer nulled versions of the software.

Not only is it often against the terms and conditions of the plugin, but they are also loaded with malware and other suspicious backdoors, that can cause a lot of damage to your site and your reputation.

Only download software from the official wordpress.org site, through the WordPress backend and legitimate sites that offer premium plugins.

The latest in Security Advice

Looks like your browser is blocking our support chat widget. Turn off adblockers and reload the page.
crossmenu