sábado, 6 de diciembre de 2008

Inyeccion SQL - Ejemplo de inyeccion SQL (SQL injection) en C# y MySQL

Los requisitos



En esta entrada les mostraré un sencillo ejemplo de inyección SQL en un programa escrito en C# con Visual Studio 2005 en un Sistema Operativo WIndows Vista Homa Basic y utilizando MySQL como gestor de base de datos. También se ha instalado en Service Pack 1 para Visual Studio y su respectiva actualización para Windows Vista.

Primeros Pasos:

Lo primero para realizar la demostración es crear un nuevo proyecto en Visual Studio 2005, y realizar la respectiva conexión con MySQL. Dentro de MySQL se tiene una base de datos con nombre "ejemplo" y una tabla de nombre "login", en la tabla login se cuenta con dos registros, uno para cada usuario; un usuario es "alfonso" y su contraseña es "123", el otro usuario es "jesus y su contraseña es "456".

La lógica para el acceso es muy simple y no debería emplearse para uso en sistemas reales, pero para este ejemplo bastara.


Visual Studio:

Dentro del proyecto de Visual Studio, el programa únicamente verificará que existen registros cuyos datos se ingresan mediante un campo de texto de usuario y otro de contraseña; la verificación en la base de datos se realiza mediante una consulta SQL:

SELECT * FROM login WHERE usuario='nombre_usuario' AND pass='contraseña_usuario';

Dentro del código de C# tenemos una función autenticación que recibe una consulta SQL de formato parecido a la consulta de la parte de arriba y devuelve un valor booleano si la consulta devuelve por lo menos un registro:

public bool Autenticacion(string query)
{
bool nivel;
MySqlCommand miComando = new MySqlCommand(query, this.miConexion);
MySqlDataReader miLector;

miLector = miComando.ExecuteReader();
if (miLector.Read())
{
nivel = true; // si la consulta SQL devuelve algun registro
miLector.Close();
}
else
{
nivel = false; //los datos no coinciden
miLector.Close();
}
return nivel;
}



esta función se llama desde el formulario principal, el cual sustituye el nombre de usuario y la contraseña con los valores que se obtienen del cuadro de texto de usuario y del cuadro de texto contraseña. Este procedimiento se lleva a cabo por medio de dos botones: Ver instruccion SQL y Ejecutar instrucción.

El boton Ver instrucción imprime en pantalla el contenido de la consulta SQL que se mandará como parametro a la función autenticación:

private void button1_Click(object sender, EventArgs e)
{
q = "SELECT * FROM login WHERE usuario='" + textBoxUsuario.Text + "' and pass='" + textBoxContra.Text + "';";
labelSQL.Text = q;
}


El botón Ejecutar Instrucción ejecuta la función autenticación con la consulta SQL como parametro y si la función autenticación devuelve un valor verdadero, muestra en pantalla un mensaje que indica que el usuario si se encuentra registrado; si por el contrario, la función devuelve un valor falso, se muestra en pantalla un mensaje que indica que los datos no se encontraron dentro de la base de datos.

Ejemplos de Inyección SQL


En nuestro formulario, si introducimos como alfonso como usuario y 123 como contraseña y damos clic sobre el botón Ver instrucción SQL, podemos observar la consulta SQL tal y como se enviaría a la función autenticación:

SELECT * FROM login WHERE usuario='alfonso' AND pass='123';



y si presionamos el botón Ejecutar instrucción, esta consulta SQL se envia como parametro esta consulta. Podemos observar que se muestra en el formulario que el usuario si cuenta con derechos de acceso.








Si modificamos la contraseña y ahora ponemos 456 como contraseña y presionamos el botón Ver instrucción SQL, observamos que la consulta SQL quedaria asi:

SELECT * FROM login WHERE usuario='alfonso' AND pass='456';

Si en este momento presionamos el botón Ejecutar instrucción, recibiremos de parte de la función autenticación un valor falso, y esto muestra en el formulario un mensaje de que el usuario no tiene derecho de acceso.




Comencemos con en el ejemplo:

Al momento de ingresar un nombre de usuario, podemos engañar al sistema si utilizamos la comilla simple en el cuadro de texto y a la vez escribimos con una operación OR alguna condición que siempre de como resultado un valor verdadero (ejemplos: 1=1, 5=5, 5>1, 1<2 -="">SELECT * FROM login WHERE usuario='as' or '2'='2' AND pass='as' or '9'='9';


en esta instrucción tenemos operaciones de tipo OR que siempre dan en verdadero, ya que '2' es igual a '2' y '9' es igual a '9', esto ocasiona que siempre se devuelvan registros de la consulta (siempre y cuando existan registros en la tabla), y ya que la consulta SQL devuelve por lo menos un registro, la función autenticación devolverá un valor verdadero, esto podrá otorgarle acceso al sistema sin que realmente tenga los derechos de accesar.

Otra forma de obtener el acceso al sistema mediante inyeccion SQL es utilizar la capacidad de poder hacer comentarios en las sentencias SQL, de esta forma aprovechariamos el no tener que escribir contraseña alguna, de esta forma podriamos escribir algo como esto:

usuario: t' and 2=2;--
contraseña:

y la consulta SQL quedaria de esta forma:

SELECT * FROM login WHERE usuario='t' or 2=2;-- and pass='';

ya que utilizamos el simbolo de comentarios (--), todo lo que va después del simbolo de comentarios es ignorado por el sistema de base de datos, es como se no se escribiera, lo que nos da una sentencia SQL asi:

SELECT * FROM login WHERE usuario='t' or 2=2;

y ya que utilizamos una operacion de tipo OR en donde siempre da un resultado verdadero, obtenemos por lo menos un registro y la función autenticación nos permite el acceso del atacante aunque realmente no tenga derechos de acceso.

Actualización (21 Agosto 2013):
Un video que muestra que hasta las instituciones de gobierno sufren este tipo de problemas, realmente recomiendo verlo en pantalla completa para alcanzar a visualizar el texto que introducen.