Attackers are always finding new and creative ways to compromise websites and maintain their foothold in environments. This is frequently done via the use of backdoors: PHP scripts designed to allow attackers access and control even after you’ve changed your passwords and thought that the worst was over.
Since external scans are unable to see website backdoors they can often be identified through the usage of server-side scans and file-integrity monitoring, which we offer as part of our services. This is also offered through a number of available WordPress security plugins that can be used on your website.
However, we recently started observing attackers making use of an unorthodox type of backdoor and reinfection method which would go completely undetected if website monitoring doesn’t happen to include the database.
Almost all of the time website backdoors are coded in the PHP programming language: the backbone of the modern web. WordPress itself (making up over 40%+ of the web) is largely PHP based, as well as most other major CMS platforms like Joomla, Magento and others. PHP is an incredibly versatile language, which also means that it can be misused by attackers. One of the most common (mis)usages by attackers are backdoors.
According to our recent 2022 Website Threat Report, we can see that remote code execution backdoors, webshells, and uploaders are the most popular among attackers to deploy to infected environments:
However, with good file integrity monitoring and server side scanning, backdoors can be effectively monitored for, detected, and removed to keep your websites safe from further attacks.
Over the last few weeks we noticed that some infected website’s databases were being injected with the following code into the wp_posts table:
[evalphp]file_put_contents($_SERVER[‘DOCUMENT_ROOT’].’/b0773c8d php’,’ ‘);[/evalphp]
This code is quite simple: It uses the file_put_contents function to create a PHP script into the docroot of the website with the specified remote code execution backdoor. All the attacker needs to do is to visit one of the infected posts or pages and the backdoor will be injected into the file structure.
It’s not exactly a new backdoor, however; more conventional PHP backdoors of this variety were found as early as last summer and over 6,000 instances of this backdoor were cleaned from compromised sites in the last 6 months alone. However, the backdoor being injected into the database is certainly a new and interesting development.
Misuse of legitimate plugin
In the code sample above you may notice the [evalphp] WordPress shortcodes (small code tags used in WordPress environments that make it easy to add complex functionality to your website). These are related to a very old WordPress plugin available in the official repository with the same name Eval PHP:
This plugin allows PHP code to be inserted into pages and posts of WordPress sites and then executed every time the posts are opened in a browser. What could go wrong, right?
It hasn’t been updated in over a decade and has very few real active installations. However, we can see that since the beginning of April it has surged in popularity:
For the ten years leading up to the end of March, 2023, this plugin rarely had 1 download a day. But around March 29, 2023 we saw daily downloads spike to 7,000. After that, every single day we have seen 3k-5k downloads — with over 100,000 downloads total.
This WordPress data correlates to our own logs, where we see that starting March 29, 2023, some attackers started installing the EvalPHP plugin on compromised sites and using it to create the earlier mentioned backdoors.
In all cases the requests originate from these three IP addresses:
- 220.127.116.11 – AEZA-AS, RU
- 18.104.22.168 – AEZA-AS, RU
- 22.214.171.124 – AEZA-AS, RU
126.96.36.199 - - [08/Apr/2023:07:28:21 -0700] "PUT /wp-json/wp/v2/plugins/evalphp/evalphp/?status=active HTTP/1.1" 200 635 "http://<redacted>.com/wp-json/wp/v2/plugins" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2902.99 Safari/537.36" 613 188.8.131.52 - - [08/Apr/2023:07:28:30 -0700] "POST /wp-json/wp/v2/pages HTTP/1.1" 201 2029 "http://<redacted>.com/wp-json/wp/v2/plugins/evalphp/evalphp/?status=active" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2902.99 Safari/537.36" 504 184.108.40.206 - - [08/Apr/2023:07:28:31 -0700] "GET /3e9c0ca6bbe9.php HTTP/1.1" 200 27 "http://<redacted>.com/wp-json/wp/v2/pages" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2902.99 Safari/537.36" 17
Here you can see a sequence of requests that:
- Checks to make sure that the Eval PHP plugin is active.
- Creates a page with malware inside the [evalphp] shortcodes. It is enough to execute the PHP code and drop the 3e9c0ca6bbe9.php backdoor (the filename is unique for each environment) in the site root.
- Accesses the newly dropped backdoor.
Since the backdoor uses the $_REQUEST[id] to obtain the executable PHP code, it doesn’t require a POST request to conceal its parameters in access logs — it can pass them as cookies, since $_REQUEST contains the contents of $_GET, $_POST and $_COOKIE.
GET requests without visible parameters look less suspicious than POST requests. But in the case of this backdoor, GET can be equally dangerous.
Pages with evalphp malware
In our experience, hackers sometimes create a test page (new pages are not displayed by default on the home page) slug publish, (the URL on a typical WordPress site will be <site-domain>.com/publish/) and the word “Test” as its only contents.
However, the real backdoors are created in multiple posts that are saved as drafts and not publicly visible at all. The way the Eval PHP plugin works it’s enough to save a page as a draft in order to execute the PHP code inside the [evalphp] shortcodes.
This is how these page drafts look in the SQL dump of the wp_posts table:
In all cases, attackers were able to successfully log into WordPress admin. And the malicious pages are created with a real site administrator as their author. However, on some of the compromised sites we found created malicious admin users with random names and outlook.com emails — for example: 5faf461e / 5faf461e@outlook[.]com, df8a6aa9 / df8a6aa9@outlook[.]com, etc.
The compromised sites sometimes have the same backdoor installed in other files. Most often we find it in /wp-content/plugins/background-image-cropper/accesson.php — in logs we find how hackers upload a custom version of the legitimate background-image-cropper plugin. We also find it in the theme’s functions.php file when attackers modify this file using the WordPress theme editor.
Why are attackers putting backdoors into wp_posts?
You might be wondering why the attackers would choose this new tactic of injecting backdoors into compromised website environments rather than just sticking with good old fashioned PHP backdoors.
Although the injection in question does drop a conventional backdoor into the file structure, the combination of a legitimate plugin and a backdoor dropper in a WordPress post allows them to easily reinfect the website and stay hidden — all they need to do is to visit a “benign” web page.
Fortunately, some WordPress security plugins such as our Sucuri Scanner do log administrator activity within a website, such as plugin installations and changes to pages/posts which would be a symptom of this attack. If you notice the Eval PHP plugin installed on your website and it wasn’t you who did it then there’s a good chance that your website has been compromised.
Potentially dangerous plugins in WordPress repository
At this point, WordPress has a warning when you open the EvalPHP page in the official plugin repository:
This plugin hasn’t been tested with the latest 3 major releases of WordPress. It may no longer be maintained or supported and may have compatibility issues when used with more recent versions of WordPress.
However, this may not be enough for plugins that can be easily abused. Maybe such plugins should be completely delisted, especially when they are not updated for 10+ years and have a really small legitimate user base.
EvalPHP is not the only plugin like this. You can find other similar plugins in the official WordPress plugin repository. For example:
This PHPEval plugin that hasn’t been updated for 11+ years and has 40+ active users. Is there a reason to keep it in the repository after so many years of inactivity? And by the way, we can see an increased interest in this plugin during the last week…
Keeping such plugins in the official repository makes it easier for hackers to stay under radar since they can install a legitimate unmodified plugin from a reputable source instead of installing fake plugins or modifying existing plugins, which can be detected by scanners that monitor integrity of known plugins.
Mitigation steps to protect your environment
In checking logs from environments affected by these backdoors, so far all of them seemed like the attackers already had established administrator access to the websites which allowed them to install the evalphp plugin within the environments.
This is a testament to how crucially important it is to secure the wp-admin panel of your WordPress environment as well as monitor any administrator activity taking place. In addition to regular file cleanup and changing passwords, don’t forget to review your WordPress users and pages — some of them may have been created by hackers.
Other steps to mitigate risk from infection include:
- Keep your website patched and up to date with the latest security releases
- Place your admin panel behind 2FA or some other access restriction
- Have a regular website backup service running for a rainy day
- Use a web application firewall to block bad bots and virtually patch known vulnerabilities