OWASP TOP 10: Inyección

Si recuerdan el post que publicamos hace poco más de una semana titulado OWASP Top 10 2010. Release Candidate, éste iniciaba una serie de entradas a través de las que pretendemos mostrar en qué consiste cada una de las vulnerabilidades que forman el TOP 10 de OWASP, así como ofrecer algunas indicaciones y recomendaciones sobre la mejor forma de evitar que nuestras aplicaciones sufran estas conocidas vulnerabilidades. Con algo de retraso sobre la fecha prevista, he aquí el primero.

La vulnerabilidad más comúnmente explotada desde el año 2004 que OWASP lleva realizando esta clasificación es la inyección. Aunque la más común sea probablemente la Inyección de SQL, existen otros tipos de inyecciones que es posible que no nos resulten tan familiares: LDAP, XPath, XSLT, XML, OS injection, etc., y que al igual que la Inyección SQL se aprovechan de la sintaxis del interprete que se va a encargar de ejecutar una determinada acción. Las vulnerabilidad de inyección pueden permiten a un atacante obtener cualquier tipo de información disponible en la aplicación, pudiendo llegar a comprometer totalmente la aplicación, así como los sistemas relacionados con ésta. Y ya saben que de ahí al infinito y más allá.

Veamos el siguiente ejemplo como demostración del tipo de situaciones en los que podemos encontrar una inyección SQL. Sea una aplicación que dispone de un frontal web en el que se muestra un formulario. Al seleccionar el usuario una determinada categoría, pulsa el botón de buscar y le aparece el conjunto de artículos que contiene dicha categoría. Al pulsar sobre «Seleccionar», se envía una petición al servidor del tipo:

http://owasp.s2grupo.es/catalog/searcharticles.jsp?id=3

Una vez recibida en el servidor, dicha petición se transforma en el siguiente código para obtener el listado de artículos de una determinada categoría:

SELECT * FROM articles WHERE idcatalog = request.getParameter(“id”);

Un atacante de nuestra plataforma podría modificar la petición esperada y solicitar información no controlada, por ejemplo:

http://owasp.s2grupo.es/catalog/searcharticles.jsp?id=3%20or%201=1

De esta forma, el atacante podría obtener el listado de todos los artículos de la base de datos con una simple modificación que puede ser realizada directamente desde el navegador con, por ejemplo, el plugin Hack Bar de Firefox. Aunque esto parezca trivial y quizá en algún caso pueda interesar que un usuario se pase toda la tarde viendo mi página web para comprar un cabecero para su dormitorio, la cosa cambia sustancialmente cuando la información que se pretende mostrar son los ingresos de un trabajador o el grado de minusvalía de una determinada persona. Si a esto le añadimos la posibilidad de algunos sistemas gestores de base de datos de concatenar sentencias en una misma ejecución, el resultado podría ser la modificación de una tabla o incluso el borrado de la propia base de datos.

Pasando a otra tipología, veamos ahora una inyección de sistema operativo. Supongamos que en la interfaz de administración de la aplicación de catálogo comentada anteriormente existe una interfaz de administración que permite ejecutar unas tareas administrativas sobre el servidor, cuyo resultado es mejorar la indexación de las distintas bases de datos que componen la aplicación. Una vez seleccionada la base de datos, el usuario pulsa el botón de optimizar y se envía una petición al servidor del tipo:

http://owasp.s2grupo.es/catalog/admin/upgradebbdd.jsp?id=4

Una vez recibida en el servidor, dicha petición se transforma en el siguiente código para optimizar la base de datos solicitada:

Runtime.getRuntime().exec(«upgradebbdd.sh» +”-“ +request.getParamter(‘id’));

Cuando el proceso termina se envía un mensaje al espacio privado del usuario con el resultado de la ejecución. Un atacante de nuestra plataforma podría modificar la petición esperada y solicitar información no controlada, por ejemplo de la siguiente manera:

http://owasp.s2grupo.es/catalog/upgradebdd.jsp?id=4;cat%20/etc/passwd

De esta forma, podría obtener el listado de todos los usuarios y sus contraseñas en su espacio de usuario, únicamente esperando a que el proceso termine su ejecución (seguro que en lugar de /etc/passwd pueden pensar alternativas mejores).

Aunque los ejemplos de vulnerabilidades se han mostrado siempre con peticiones GET, las aplicaciones son igualmente vulnerables a peticiones POST. Del mismo modo, estas vulnerabilidades son independientes del lenguaje utilizado en el servidor, aunque el uso de determinados frameworks puede mitigar la existencia de estas vulnerabilidades. Los dos ejemplos mostrados son sólo un par de situaciones en las que es posible encontrar vulnerabilidades de inyección, pero la filosofía es extensible al resto de tipos de inyecciones.

La primera manera de protegerse, independientemente del tipo de inyección que podamos sufrir, es asegurar que los datos que se utilizan para componer la visualización dinámica de la aplicación —aquella que depende de la petición del usuario— se encuentran correctamente validados antes de su interpretación. Es decir, si «estamos esperando» un número, se debe validar que el parámetro utilizado será un número, y si por el contrario esperamos una dirección de correo electrónico, utilizaremos ese dato únicamente si éste es conforme al formato establecido. En segundo lugar, es importante prestar especial atención a la existencia de determinadas secuencias de caracteres y cuando se presenten, «escaparlas» mediante las funciones apropiadas. Por último, la mayoría de lenguajes disponen de APIs con funciones diseñadas para proteger la aplicación, y que ofrecen la posibilidad de ejecutar consultas especialmente preparadas para evitar este tipo de problemas de seguridad.

Y hasta aquí todo lo referente a ataques de inyección, de momento. Como saben, si quieren extenderse en la materia, más allá de los innumerables recursos de la red, pueden acudir a la web de OWASP, donde encontrarán mucha información de utilidad. Si desean que demos más detalles sobre alguna de las vulnerabilidades mostradas, no tienen más que indicarlo en los comentarios.

Comments

  1. Francisco Benet says

    Buen post, tal vez sea bonito hacer una serie con ejemplos prácticos, sobre todo cuando se utilizan ORM’s o cuando se intenta acceder a los datos de un ldap… cosas que en el desarrollo con frameworks se dan por resueltos pero que cada vez son más vulnerables.

    Me ha gustado.

    Saludos.

  2. Un almendro en flor es bonito. Así que más que bonito, quizá la palabra sea «útil» :^)

  3. David Monteagudo says

    Muchas gracias por el comentario Paco, del de Manolo mejor no decir nada.
    El tema de las inyecciones es muy amplio y pensamos que un post en el que se publicarán un par de ejemplos podría suponer un reflejo de lo que nos podemos encontrar en los desarrollos y aplicaciones existentes.
    Tomamos nota de tu sugerencia y en próximas fechas ampliaremos este post con ejemplos de otras inyecciones y cómo evitarlas.

  4. Joaquin Moreno says

    Gracias David, muy buen post.

    Solo me ha quedado una duda, y no se si es porque me acabo de levantar o por la edad jaja :P

    Cuando pones esto:
    Runtime.getRuntime().exec(”upgradebbdd.sh” +”-“ +request.getParamter(‘id’));

    No sería esto:
    Runtime.getRuntime().exec(”upgradebbdd.sh ” +”-“ +request.getParamter(‘id’));

    O esto:
    Runtime.getRuntime().exec(”upgradebbdd.sh” +” -“ +request.getParamter(‘id’));

    Es decir, dejando un espacio en blanco entre el script y el guión de la opción.

  5. David Monteagudo says

    Muchas gracias por el comentario Ximo.

    Evidentemente es un error tipográfico, ya que de otra forma no se ejecutaría el script porque no lo encontraría, pero lo importante no es el ejemplo en concreto, sino la forma de explotarlo, que supongo que habrá quedado clara, independientemente del typo.

    Cuando acabe la serie del Top 10 tendré que hacer un Top 10, fe de erratas.