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?
// ✗ 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_3Comando:
SHOW DATABASES;
-- information_schema
-- mysql
-- performance_schema
-- target_app2. 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.comComando:
SHOW TABLES IN target_app;
-- users
-- products
-- orders
-- comments3. Column (Columna)
Define atributo de los datos y su tipo.
Comando:
DESCRIBE users;
-- Field | Type | Null | Key
-- ----------|--------------|------|-----
-- id | INT | NO | PRI
-- username | VARCHAR(50) | NO | UNI
-- password | VARCHAR(255) | NO |
-- email | VARCHAR(100) | NO | UNI4. Row (Fila)
Una entrada individual.
id=1, username='admin', password='hash123', email='admin@target.com'Tipos de Datos Comunes
| Tipo | Ejemplo | Uso |
|---|---|---|
| INT | 123, -50 | Números enteros |
| VARCHAR(n) | 'admin' | Texto variable |
| TEXT | Párrafos | Texto largo |
| DATETIME | 2024-01-15 10:30:45 | Fecha y hora |
| BOOLEAN | TRUE, FALSE | Sí/No |
| FLOAT | 3.14, 99.99 | Decimales |
Information Schema
MySQL almacena información sobre BD en information_schema.
Listar todas las tablas
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_appListar columnas de tabla
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 | UNIPART C: MySQL
Identificar Versión
SELECT version();
-- Resultado: 5.7.30-28-log
SELECT @@version;
-- Resultado: 5.7.30-28-logFunciones Útiles en SQLi
Información del Sistema
-- 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_64Manipulación de Strings
-- 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: adminAgregaciones
-- 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
-- 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)
-- 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
-- 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 DBUso 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
-- 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ácterUNION SELECT
Sintaxis
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
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
-- 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)
-- 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();