Supply chain attacks have gained massively increasing attention recently, with the hugely notable cases of SolarWinds in 2020 affecting the US Federal Government; and the Colonial pipeline ransomware attack in 2021 leading to stockpiling of petrol over the US.

Hewlett-Packard Enterprise have taken supply chain attacks so seriously that they have released a “Trusted Supply Chain” edition line of servers that have robust and traceable supply chains to prevent these attacks. Even suspected but unproven supply chain attacks can seriously impact the reputation of companies involved, such as the SuperMicro hardware backdoor rumours.

More recently, a number of WordPress themes and plugins from a single vendor have come into the spotlight for a supply chain attack – distributing a PHP backdoor with their themes and plugins.

What happened?

A PHP backdoor was discovered by WordPress plugin developer Jetpack in a large number of WordPress themes and plugins distributed by AccessPress. It was confirmed that an attacker compromised the AccessPress website in September 2021 and uploaded malicious code to the themes and plugins available to download. This was the weak link in the supply chain, every administrator that installed an affected theme or plugin was unknowingly adding a backdoor to their WordPress site. This vulnerability has been assigned CVE-2021-24867.

How does the backdoor get added?

The malicious themes and plugins contained code in initial.php that would add the backdoor to the WordPress site. A base64 encoded PHP backdoor is decoded by the dropper, and added to wp-includes/vars.php. This backdoor snippet defines a new function, and a call to this function immediately below. The function is titled “wp_is_mobile_fix” to blend in with the legitimate “wp_is_mobile” function immediately following it, and is obfuscated to hide its true purpose.

The function wp_is_mobile_fix

The script vars.php is used by essentially every WordPress page, and as such the call to the backdoor function occurs with HTTP requests to any WordPress page.

How does the code work?

While the code is obfuscated, renaming variables makes it considerably easier to understand. Understanding that the PHP superglobal “$_COOKIE” is an associative array (key-value pair) of cookie names and values also helps to understand the code.

code screenshot outlining superglobal $_COOKIE

Initially the code checks if there are 8 total cookies set, then if the User-Agent header is “wp_is_mobile”. This header serves dual purposes, it both attempts to hide the back door as part of the function name, and restricts the backdoor to those that set the User-Agent header correctly.

If both checks succeed, the backdoor begins to execute code. Cookies are referenced by name, with numerical names that seem random. The first two cookies, 33 and 32, are concatenated to determine what PHP function to call, and this function is then called. Cookies 78 and 18 are concatenated to provide the argument to the function, and the return value of the function call is stored in $iv.

The code then calls our chosen function again, with a different argument – 12 and 17 concatenated, and stores the result in $_iv. These variables are subsequently called as functions, but the code gets hard to follow and can largely be ignored for exploitation – the important part is the first function call as this is all that is required for remote code execution.

How do we exploit it?

Recall from the exploit that cookies 33 and 32 are concatenated to define the function to call, and 78 and 18 are concatenated to supply the argument to that function. To trivially achieve and demonstrate remote code execution, we can set cookie 33 to “system” and cookie 78 to “uname -a”. The other cookies must be present as there must be 8, but their values can be left empty. The attack demonstrated on a test machine below using BurpSuite.

The attack demonstrated on a test machine using BurpSuite.

Entering and URL encoding commands within BurpSuite becomes somewhat irritating, so we can automate this using Python to write a more formal exploit script. Adding some filtering and a simple loop makes this a somewhat interactive shell, from which we can spawn a reverse shell for further exploitation and privilege escalation.

An exploit script in Python

How do we detect and remediate it?

To remove the backdoor, you should reinstall WordPress. While you could edit the vars.php file to remove the backdoor function, further changes may have been made. The optimal solution would be to start from a fresh system, as with the presence of a backdoor it’s unclear whether an attacker has established persistence through other means. Systems should be assumed to be compromised, especially with recent privilege escalation vulnerabilities in Linux such as PwnKit.
Jetpack have supplied YARA rules to detect the backdoor, which are available from https://jetpack.com/2022/01/18/backdoor-found-in-themes-and-plugins-from-accesspress-themes/

Lessons Learnt

Supply chain attacks are a significant risk to organisations and their customers. Outstanding security issues in your infrastructure can lead to compromise of customer systems, causing great harm to a business’ reputation. While it’s infeasible to audit every line of code in every piece of software, care must be taken to avoid introducing deliberately or accidentally vulnerable software or code. Ongoing penetration testing can help to prevent supply chain attacks by identifying vulnerabilities before a malicious actor can exploit them, reducing the risk to both organisations and their clients.