sábado, 3 de julio de 2010

Inyección SQL en GHL Hoteles

GHL Hoteles es una cadena hotelera presente en varios paises latinoamericanos a la que pertenecen hoteles de prestígio como el Sheraton o el Four Points pero lamentablemente parece que no han puesto el mismo interes en la calidad de su página web como en sus hoteles.

La web de GHL Hoteles contiene errores de programación de manual en lo que se refiere a inyección SQL ya que con solo acceder a uno de los hoteles mediante una URL del tipo


podemos introducir código SQL junto con el parámetro id ya que no se realiza ningún tipo de filtrado de forma que si accedemos a la URL


Podemos ver el siguiente mensaje de error


lo que, además de confirmarnos que es posible la inyección de código SQL, nos da información sobre el contenido del servidor, como por ejemplo que una de las tablas del servidor se llama hotel y que, por lo menos contiene los campos nro_hotel, ghl y publicar.

Pero no es la única página en la que se puede hacer inyección sql, existe una sección llamada NotiHoteles desde la que se puede acceder a noticias relacionadas con los distintos hoteles de la cadena.
Las distintas noticias tienen urls del tipo:


y, como en el caso anterior el parámetro id tampoco tiene ningún tipo de filtrado de forma que es posible acceder a un mensaje de error similar al obtenido anteriormente utilizando la url


En esta ocasión se obtienen más datos sobre el servidor. Se conoce la existencia de las tablas noticia, seccion_noticias y modulo_noticias así como algunos campos de dichas tablas nombre, nro_modulo, ubicacion, site...

¿Podría modificar la consulta para escribir mi propia noticia? para ello existen varias opciones, una seria insertar información en la tabla noticia pero esto no lo voy a hacer ya que no quiero modificar datos de un servidor ajeno sin el consentimiento previo. La otra opción seria "forzar" que la instrucción select devolviese la información que quisieramos visualizar como noticia pero para ello necesitamos conocer los campos existentes en la tabla noticia para saber que campo almacena el título de la noticia, la fecha, el cuerpo de la noticia, etc.

Para conocer cuantos campos existen en la tabla noticia podemos hacerlo por el método de prueba y fallo intentando realizar un UNION de la consulta que se nos muestra con una consulta ficticia nuestra, por ejemplo:

SELECT n.*, m.nombre modulo, s.nombre seccion, m.nro modulo
FROM noticia n, seccion_noticias s, modulo_noticias m
WHERE n.nro_seccion = s.nro_seccion
AND s.nro_modulo = m.nro_modulo
AND n.nro_noticia = '2403' UNION SELECT 1 /*
AND n.publicar = 'S'
AND FIND_IN_SET('SECCION', n.ubicacion)>0
AND FIND_IN_SET('GHL', n.site)>0

En rojo he añadido la consulta que utilizaremos para saber cuantos campos tiene la tabla noticia.
He añadido también los caracteres /* para que SQL interprete el resto de la consulta (verde) como si fueran comentarios de forma que no se tendrán en cuenta.
De esta forma si añadimos ' UNION SELECT 1 /* al parámetro id de la url obtenemos un mensaje de error similar al anterior pero que nos indica que la nueva consulta select tiene diferente número de campos


Ahora solo nos queda ir añadiendo campos a nuestra consulta hasta que el servidor nos devuelva una respuesta positiva, por ejemplo:

http://www.ghlhoteles.com/noticia.php3?id=2403' UNION SELECT 1,2 /*
http://www.ghlhoteles.com/noticia.php3?id=2403' UNION SELECT 1,2,3 /*
....
http://www.ghlhoteles.com/noticia.php3?id=2403' UNION SELECT 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28 /*

Si, hay que tener un poco de paciencia o valerse de algún programa que vaya generando las distintas url. En fin, el caso es que con 28 campos el servidor nos devuelve la noticia correcta.


Ahora ya sabemos que la consulta resultante es válida pero ¿porque no se muestran nuestros campos en la web?. Simplemente porque ahora se estan devolviendo dos noticias (la real y la falsa) pero la página web solo muestra la primera así que para anular el primer registro que es el que tiene la noticia real es suficiente con indicarle un id que no exista, por ejemplo -1, quedando así:

http://www.ghlhoteles.com/noticia.php3?id=-1' UNION SELECT 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28 /*

En principio nos aparecen 4 de los 28 campos "falsos" que hemos introducido (la fecha 31/12/69 también es uno de los campos que ha sido convertido a DATE pero para no hacer demasiado largo el post no me detendré en él). Ahora ya sabemos que lo que escribamos en lugar del 3 aparecera como si fuera el título de la noticia, el 4 representa el "lugar" mientras que el 6 es el cuerpo de la noticia y, pese a que no se ve en la imagen adjunta, el campo 16 representa la imagen de forma que la siguiente URL muestra esta noticia tan sexy.


Pero vayamos un poco más allá, hasta el momento solo hemos utilizado la inyección SQL para modificar la visualización de la página como si de un simple XSS se tratara pero mediante inyección SQL podemos obtener la información contenida en las tablas del servidor. ¿Existirá alguna tabla interesante en este servidor?

Si continuamos navegando por la web de GHL vemos que también existe un formulario de contacto que, como era de esperar, tampoco realiza ningún tipo de filtrado sobre los campos del mismo de forma que con la ya famosa "comilla simple" y rellenando algunos campos obtenemos lo siguiente:


Con este nuevo mensaje de error vemos una nueva tabla que parece interesante, la tabla Contacto así como todos los campos que existen en ella de forma que podríamos visualizar la información de esta tabla en la página de noticias, es decir, en lugar de visualizar una noticia podríamos visualizar cualquier campo de la tabla Contacto.


Entendereis que no ponga la url exacta de como sacar esta información aunque creo que no resultará dificil de obtener si habeis leido el post completo.

A fecha de hoy existen 10912 registros en la tabla Contacto por lo que es de suponer que habrá 10912 direcciones de correo electrónico, teléfonos, nombres, direcciones... información muy sensible que no deberia ver la luz.

Esto es solo un pequeño ejemplo de la cantidad de información a la que se puede acceder pero existen otras muchas tablas accesibles (112 en total) con lo que el daño a la empresa y a los clientes puede ser muy elevado.

viernes, 2 de julio de 2010

El meridiano de Greenwich

Imagino que todos sabeis que el meridiano de Greenwich cruza España y, sino lo sabeis ya os lo digo yo, pero uno no siempre se da cuenta de lo cerca que lo tiene e incluso de cuando lo cruza.

Hace unas semanas hice un viaje de Madrid a Barcelona por la autopista AP2 y me sorprendió ver este letrero que indicaba allá por el kilómetro 85 que faltaba un kilómetro y medio para cruzar el meridiano de Greenwich pero lo que más me gustó fué ver como brillaba al oscurecer.

No es más que un arco que representa el meridiano pero es una sensación curiosa pasar por dicho lugar y, además, quedaba muy bonito.


domingo, 27 de junio de 2010

Split, función vs método

En VisualBasic.NET existen dos definiciones para la instrucción Split, una es un método y la otra una función que, si bien pienso que deberian funcionar exactamente igual, tienen sus particularidades.

La función Split está definida en el NameSpace Microsoft.VisualBasic mientras que el método Split se encuentra en el NameSpace System.String. En principio parece ser que el NameSpace Microsoft.VisualBasic se definió como un conjunto de instrucciones para facilitar la migración de aplicaciones hechas en versiones anteriores de VisualBasic a .NET por lo que debemos entender que es el método Split el que Microsoft propone para los nuevos desarrollos en .NET

Para quien no lo sepa Split se utiliza para dividir una cadena en subcadenas utilizando uno o varios caracteres como elemento de corte, es decir, si tenemos el texto "Texto1@Texto2@Texto3" podriamos obtener tres cadenas independientes "Texto1", "Texto2", "Texto3" llamando al método (o a la función) Split con @ como caracter de corte.


Utilizando ambos métodos se obtiene que:
SubCadenas(0) = "Texto1"
SubCadenas(1) = "Texto2"
SubCadenas(2) = "Texto3"

El problema es que, en ocasiones necesitamos especificar varios caracteres de corte, por ejemplo, si en lugar de @ tenemos dos caracteres, por ejemplo @& y la cadena de texto original fuera "Texto1@&Texto2@&Texto3" se supone que deberiamos obtener el mismo resultado llamando al método o a la función utilizando esos caracteres pero realmente obtenemos lo siguiente.


Con el método Cadena.Split("@&") el resultado es:
SubCadenas(0) = "Texto1"
SubCadenas(1) = "&Texto2"
SubCadenas(2) = "&Texto3"

Mientras que utilizando la función Split(Cadena, "@&") si se obtiene:
SubCadenas(0) = "Texto1"
SubCadenas(1) = "Texto2"
SubCadneas(2) = "Texto3"

¿A que se debe esta discrepancia? el problema es que el método Split acepta una variable de tipo caracter como parámetro, es decir, un único caracter por lo que al pasarle "@&" realemnte solo esta teniendo en cuenta el caracter @ mientras que & es despreciado.
La función Split si acepta un String como parámetro por lo que si se estan considerando ambos caracteres y su resultado es el esperado.

Realmente el método Split si tiene una sobrecarga en la que se puede indicar un valor de tipo String (realmente un array de strings) pero dicha sobrecarga, tiene, además, otro parámetro StringSplitOptions que, en este caso no nos interesa pero a no ser que lo especifiquemos no conseguiremos que el método Split funcione como deseamos así que la llamada correcta seria:


De esta forma el valor de SubCadenas si es el mismo que utilizando la función Split, es decir:
SubCadenas(0) = "Texto1"
SubCadenas(1) = "Texto2"
SubCadneas(2) = "Texto3"

Pienso que en la definición del método Split se les pasó por alto hacer una sobrecarga para permitir un parámetro String de forma similar a la función Split, por lo menos creo que es bastante más cómodo.

sábado, 26 de junio de 2010

¿Te asusta tu Air Wick?

Esta semana hemos comprado un ambientador Air Wick Freshmatic I-Motion, si si, un nombre muy rimbombante pero es que el aparatito se las trae, se trata de un ambientador en spray que se acciona automáticamente a intervalos de 9, 18 o 36 minutos pero la característica principal de este modelo, el I-Motion, es que lleva incorporado un sensor de movimiento de forma que cuando detecta que hay "alguien" cerca acciona el disparador dispersando la fragancia...

Es precisamente esto lo que hace que nos hayamos pegado unos cuantos sustos al entrar al aseo ya que, por lo general, uno entra al cuarto de baño sin demasiadas preocupaciones y no espera escuchar ningún ruido "extraño" pero desde que tenemos el Air Wick Freshmatic I-Motion cada vez que entramos el sensor de movimiento nos detecta y acciona el disparador lo que produce un sonido característico de sssssssssss que nos suele pillar por sorpresa.

Ya nos vamos acostumbrando pero los primeros dias fueron de lo más "curiosos" y es que al final pasa lo que pasa, en los anuncios de Air Wick los cuartos de baño que salen son inmensos y seguramente no se escuchará el disparador y todos felices y contentos pero cuando se pone este tipo de aparatitos en un aseo "normal" da hasta yuyu jeje.

Ah, por cierto, ya puestos a comentar cosas del Air Wick debo decir que, para mi gusto, es demasiado grande, tiene practicamente el tamaño de una botella de champú y como no se puede esconder ya que sino dejaria de ser util el sensor de movimiento pues hay que tenerlo casi en primera línea y desentona un poco pero en fin, es lo que hay, por lo menos la fragancia Nenuco es bastante agradable.

Actualización 26/11/2010
Recién hoy se han acabado las 3 pilas tipo AA que lleva. No esta mal para estar todo el día puesto. Han durado 5 meses.