Skip to content

FUNDAMENTOS - SQL Injection Basics


PART A: Introduction

¿Qué es SQL Injection?

SQL Injection (SQLi) es una vulnerabilidad de seguridad donde un atacante inyecta código SQL malicioso en campos de entrada de una aplicación web. Si la aplicación no valida ni escapa la entrada, el atacante puede ejecutar comandos SQL arbitrarios en la base de datos.

Impacto

  • Confidentiality: Extracción de datos sensibles (contraseñas, registros)
  • Integrity: Modificación o eliminación de datos
  • Availability: Eliminación de tablas, DoS

Ejemplo Simple

URL: http://target.com/product?id=1
Consulta: SELECT * FROM products WHERE id=1

Ataque: http://target.com/product?id=1' OR '1'='1
Consulta resultante: SELECT * FROM products WHERE id=1' OR '1'='1'
Resultado: Retorna TODOS los productos (1 OR 1=1 siempre verdadero)

¿Por Qué Ocurre?

php
// ✗ VULNERABLE - Concatena entrada del usuario
$query = "SELECT * FROM users WHERE id = " . $_GET['id'];
$result = mysqli_query($conn, $query);

// ✓ SEGURO - Usa prepared statements
$stmt = $conn->prepare("SELECT * FROM users WHERE id = ?");
$stmt->bind_param("i", $_GET['id']);
$stmt->execute();

Prevalencia

Según OWASP Top 10:

  • SQLi está en posición #1 en vulnerabilidades críticas
  • Presente en 50%+ de aplicaciones web
  • Fácil de explotar, alto impacto

PART B: Databases

Tipos de Bases de Datos

Relational (SQL)

Usa tablas con filas y columnas. Estructura ordenada.

Ejemplos: MySQL, PostgreSQL, MSSQL, Oracle, SQLite

NoSQL

Datos no estructurados (documentos, pares clave-valor)

Ejemplos: MongoDB, Redis, CouchDB


Estructura Relacional (SQL)

1. Database (Base de Datos)

Contenedor lógico que agrupa tablas relacionadas.

MySQL Server
├── database_1
├── database_2 (target_app)
│   ├── Tabla: users
│   ├── Tabla: products
│   └── Tabla: orders
└── database_3

Comando:

sql
SHOW DATABASES;
-- information_schema
-- mysql
-- performance_schema
-- target_app

2. Table (Tabla)

Estructura de filas y columnas.

Ejemplo tabla users:

id  | username | password            | email
----|----------|---------------------|---------------------
1   | admin    | hash_password_123   | admin@target.com
2   | john     | hash_password_456   | john@target.com
3   | maria    | hash_password_789   | maria@target.com

Comando:

sql
SHOW TABLES IN target_app;
-- users
-- products
-- orders
-- comments

3. Column (Columna)

Define atributo de los datos y su tipo.

Comando:

sql
DESCRIBE users;

-- Field      | Type         | Null | Key
-- ----------|--------------|------|-----
-- id         | INT          | NO   | PRI
-- username   | VARCHAR(50)  | NO   | UNI
-- password   | VARCHAR(255) | NO   |
-- email      | VARCHAR(100) | NO   | UNI

4. Row (Fila)

Una entrada individual.

sql
id=1, username='admin', password='hash123', email='admin@target.com'

Tipos de Datos Comunes

TipoEjemploUso
INT123, -50Números enteros
VARCHAR(n)'admin'Texto variable
TEXTPárrafosTexto largo
DATETIME2024-01-15 10:30:45Fecha y hora
BOOLEANTRUE, FALSESí/No
FLOAT3.14, 99.99Decimales

Information Schema

MySQL almacena información sobre BD en information_schema.

Listar todas las tablas

sql
SELECT table_name, table_schema 
FROM information_schema.tables 
WHERE table_schema NOT IN ('information_schema', 'mysql', 'performance_schema');

-- table_name | table_schema
-- ----------|----------
-- users      | target_app
-- products   | target_app
-- orders     | target_app

Listar columnas de tabla

sql
SELECT column_name, data_type, column_key
FROM information_schema.columns
WHERE table_name = 'users' AND table_schema = 'target_app';

-- column_name | data_type | column_key
-- ----------|-----------|----------
-- id          | bigint     | PRI
-- username    | varchar    | UNI
-- password    | varchar    |
-- email       | varchar    | UNI

PART C: MySQL

Identificar Versión

sql
SELECT version();
-- Resultado: 5.7.30-28-log

SELECT @@version;
-- Resultado: 5.7.30-28-log

Funciones Útiles en SQLi

Información del Sistema

sql
-- Usuario actual
SELECT user();
-- Resultado: root@localhost

-- Base de datos actual
SELECT database();
-- Resultado: target_app

-- Directorio de instalación
SELECT @@datadir;
-- Resultado: /var/lib/mysql/

-- Sistema operativo
SELECT @@version_compile_os;
-- Resultado: Linux x86_64

Manipulación de Strings

sql
-- Concatenar
SELECT CONCAT('Hello', ' ', 'World');
-- Resultado: Hello World

-- Agrupar filas
SELECT GROUP_CONCAT(username) FROM users;
-- Resultado: admin,john,maria

-- Agrupar con separador
SELECT GROUP_CONCAT(username SEPARATOR ' | ') FROM users;
-- Resultado: admin | john | maria

-- Substring
SELECT SUBSTRING('hello', 1, 3);
-- Resultado: hel

SELECT SUBSTR(database(), 1, 1);
-- Resultado: t (primera letra de target_app)

-- Hexadecimal
SELECT HEX('admin');
-- Resultado: 61646d696e

SELECT UNHEX('61646d696e');
-- Resultado: admin

Agregaciones

sql
-- Contar filas
SELECT COUNT(*) FROM users;

-- Contar tablas en BD
SELECT COUNT(*) FROM information_schema.tables 
WHERE table_schema=database();

-- Min/Max
SELECT MIN(id), MAX(id) FROM users;

Condicionales

sql
-- IF
SELECT IF(1=1, 'verdadero', 'falso');
-- Resultado: verdadero

-- CASE
SELECT CASE 
  WHEN id=1 THEN 'admin'
  WHEN id=2 THEN 'user'
  ELSE 'unknown'
END FROM users;

-- IFNULL
SELECT IFNULL(null_column, 'default');

Timing (para Blind SQLi)

sql
-- SLEEP (MySQL)
SELECT SLEEP(5);
-- Se pausa 5 segundos

-- Condicional con sleep
SELECT IF(1=1, SLEEP(5), 0);

-- BENCHMARK (muy lento)
SELECT BENCHMARK(5000000, MD5('test'));

Comentarios en MySQL

sql
-- Comentario simple
SELECT * FROM users; -- esto es comentario

/* Comentario multi-línea */
SELECT * FROM users;
/* comentario
   multi-línea */

# Comentario (estilo MySQL)
SELECT * FROM users; # comentario

/*! Comentario especial MySQL */
-- Solo en MySQL, ignorado en otros DB

Uso en SQL Injection

URL: ?id=1' UNION SELECT 1,2,3 --
El -- comenta el resto de la consulta original

URL: ?id=1' UNION SELECT 1,2,3 /**/
Comentario vacío (evita error de sintaxis)

URL: ?id=1' /*!50000UNION*/ /*!50000SELECT*/ 1,2,3 --
Solo se ejecuta en MySQL 5.0.0+

Operadores Lógicos

sql
-- AND (ambas condiciones verdaderas)
SELECT * FROM users WHERE id=1 AND username='admin';

-- OR (al menos una verdadera)
SELECT * FROM users WHERE id=1 OR id=2;

-- NOT (negación)
SELECT * FROM users WHERE NOT (id=1);

-- IN (está en lista)
SELECT * FROM users WHERE id IN (1,2,3);

-- BETWEEN
SELECT * FROM users WHERE id BETWEEN 1 AND 10;

-- LIKE (búsqueda parcial)
SELECT * FROM users WHERE username LIKE 'ad%';
-- % = cualquier número de caracteres
-- _ = un solo carácter

UNION SELECT

Sintaxis

sql
SELECT column1, column2 FROM table1
UNION
SELECT column3, column4 FROM table2;

Requisitos:

  • Mismo número de columnas
  • Tipos compatibles
  • Output muestra nombres de primera SELECT

Ejemplo

sql
SELECT username, password FROM users
UNION
SELECT title, content FROM posts;

-- Resultado intercalado:
username | password
---------|----------
admin    | hash123
john     | hash456
MyBlog   | Welcome...
News     | Breaking news...

Sin Duplicados

sql
-- UNION elimina duplicados
SELECT id FROM users UNION SELECT id FROM admins;

-- UNION ALL mantiene duplicados
SELECT id FROM users UNION ALL SELECT id FROM admins;

Resumen - Estructura Jerárquica

MySQL Server
└── database: target_app
    ├── table: users
    │   ├── column: id (INT)
    │   ├── column: username (VARCHAR)
    │   ├── column: password (VARCHAR)
    │   └── rows:
    │       ├── [1, "admin", "hash123"]
    │       ├── [2, "john", "hash456"]
    │       └── [3, "maria", "hash789"]

    ├── table: products
    │   ├── column: id (INT)
    │   ├── column: name (VARCHAR)
    │   └── rows:
    │       ├── [1, "Laptop"]
    │       └── [2, "Phone"]

    └── table: orders
        ├── column: id (INT)
        ├── column: user_id (INT - FK)
        └── column: product_id (INT - FK)

Este es el conocimiento base para enumerar durante un SQL Injection.


Comandos SQL Clave (Referencia Rápida)

sql
-- Listar bases de datos
SHOW DATABASES;

-- Usar BD
USE target_app;

-- Listar tablas
SHOW TABLES;

-- Describir tabla
DESCRIBE users;
DESC users;

-- Usuario y BD actual
SELECT user(), database();

-- Información schema
SELECT * FROM information_schema.tables 
WHERE table_schema=database();

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

-- Privilegios
SHOW GRANTS FOR current_user();

-- Versión
SELECT version();