BBLABS v2BBLABSv2
>Inicio>Labs
>New labs

Últimos 3 labs

Cargando…

Ver todos los labs →
>Creators>Ranking
>Aprender

Aprender bug bounty

AcademyGuías, cheatsheets y diccionarioVulnerabilidadesXSS, SQLi, IDOR, SSRF y másHacker RoadmapTu ruta de bug bounty paso a pasoBlogGuías y noticias de bug bounty
>Empresa>Precios
EN
AccederAcceder
>Inicio>Labs>New labs>Creators>Ranking>Aprender>Empresa>Precios
EN
Iniciar SesiónCrear Cuenta
  1. Inicio
  2. Labs
  3. SQL injection error-based en la resolución de tenant de un portal de identidad
MediaVDP50 min

SQL injection error-based en la resolución de tenant de un portal de identidad

Por @gorka

El login y el 'olvidé mi contraseña' resuelven tu organización por username antes de validar nada; un fallo ahí filtra, trozo a trozo, un secreto interno que ningún endpoint sirve.

204 visitas1 completadosActualizado sept 2026
Iniciar sesión para empezar

Aprende a encontrar este bug

Un hackeo real de HackerOne, reproducido para que lo practiques.

Crea tu cuenta y practica bugs reales que se pagaron. Descarga el entorno, encuéntralo y aprende la técnica exacta — tu camino a tu primer bounty.

650

hunters entrenando

50

labs de hackeos reales

380

completaciones

$12.000

pagados por estos bugs

40 flags capturadas esta semana
Crear cuenta
Ya tengo cuenta

Acceso a todos los labs · sin permanencia · cancela cuando quieras

Hackers que lo han resuelto· 1

w4tchw0lf1
@w4tchw0lfHace 5 días

Objetivos

1
Detectar que el username del login/reset alcanza una consulta SQL sin parametrizar.
2
Provocar el error de sintaxis y leer el mensaje crudo del motor más la sentencia completa.
3
Reflejar en el error el resultado de una subconsulta propia dentro de una función XPath.
4
Enumerar information_schema hasta localizar una tabla interna que ningún endpoint expone.
5
Superar la truncación del error (~32 caracteres) partiendo la extracción con substring().
6
Descartar el auth-bypass y el resto de decoys con pruebas acotadas.
7
Capturar la flag almacenada en vault_secrets.federation_root_secret.

Información

Plataforma
HackerOne
Dificultad
Media
Duración
50 min
Bounty
VDP
Completados
1
Creador
gorka@gorka
Actualizado
sept 2026

Descarga el entorno

Reprodúcelo y encuentra el bug tú mismo

Crear cuenta

Herramientas

curlNavegador webBurp SuitePython (requests)

Prerequisitos

  • HTTP y formularios web
  • SQL básico (SELECT/WHERE)
  • Uso de curl o un proxy HTTP

Tags

SQLiInformation Disclosure

Logro que recibirás

Cuando resuelvas este lab desbloqueas este logro compartible

BBLABS.ESLab Resuelto
MediaVDP
// achievement_unlocked

SQL injection error-based en la resolución de tenant de un portal de identidad

SQLiInformation Disclosure
sept 2026
gorka
solved_by@gorkaMiembro desde mar 2026
bblabs.es// real hacking practice

Writeups de la comunidad

Contenido del lab

Escenario

Ingressia es un SaaS de identidad y acceso para plantillas (workforce identity): decenas de organizaciones clientes ("tenants") delegan en Ingressia el login de sus empleados. Cada tenant tiene su propio directorio de identidades y su propia configuración SSO; antes de comprobar ninguna credencial, el portal necesita saber a qué tenant pertenece el username que el empleado teclea, para pintar el branding correcto y enrutar la petición al backend de auth de su organización.

Te contratan como pentester externo, sin ninguna credencial del sistema, para auditar el portal público de acceso: la pantalla de login y el flujo de "olvidé mi contraseña". Ambos flujos son pre-auth y aceptan el mismo dato de entrada: un username.

Tu misión, sin usar la cuenta de demostración que Ingressia te entrega para orientarte: demuestra que puedes alcanzar datos internos que ningún endpoint documentado sirve, y tráete la prueba — un secreto de federación guardado en un almacén interno — como flag.

Qué tienes

  • Cuenta demo: attacker@ingressia.local / password123 — te deja entrar y ver el dashboard y otras pantallas, pero la inyección corre pre-auth: no la necesitas para explotarla.
  • Dos formularios públicos que piden un username (login y "olvidé mi contraseña") — la superficie de ataque completa está a la vista, sin credenciales de por medio.

Guía paso a paso

  1. Reconoce las dos superficies. El login (POST /api/auth/login) y el "olvidé mi contraseña" (POST /api/auth/password-reset) piden ambos un username antes de nada — es el paso de resolución de tenant. Mete un simple ' en ese campo (username=x', cualquier password) → 500 en vez del rechazo normal.
  2. Lee el error con calma. El cuerpo del 500 trae db_message (el texto crudo de MariaDB, tipo You have an error in your SQL syntax…) y statement (la sentencia completa: SELECT id, tenant_id FROM directory_identities WHERE username = 'x'' LIMIT 1). Conclusión: username se concatena crudo en la query, y la tabla detrás es directory_identities.
  3. Descarta el atajo evidente (Decoy A). Antes de perseguir la extracción, prueba si esto es un auth-bypass: username=' OR 1=1-- en el login. Resultado: 401, sin error, sin sesión. La comprobación de la contraseña es una segunda query, parametrizada + bcrypt.compare, totalmente separada de la resolución de tenant. Concluyes: esto es exfiltración, no bypass.
  4. Confirma la extracción in-band. Inyecta ' AND updatexml(1,concat(0x7e,(select version()),0x7e),1) AND '1'='1 en username. El 500 refleja algo como ~10.11.x-MariaDB~ en db_message — el error te devuelve el resultado exacto de tu subconsulta. Repite con database() para confirmar el schema (ingressia_directory).
  5. Enumera el schema. Con el mismo primitivo, pide (select group_concat(table_name) from information_schema.tables where table_schema=database()). Entre las tablas de negocio (tenants, sso_connections, auth_audit_log, reset_tokens…) aparece vault_secrets — que no está detrás de ningún endpoint que hayas visto. Pide sus columnas del mismo modo: secret_name, secret_value.
  6. Localiza la fila correcta. Enumera secret_name de vault_secrets: aparecen smtp_relay_password, webhook_signing_key, scim_bearer_token, session_signing_key y federation_root_secret — el nombre que destaca por describir un secreto raíz de federación entre Ingressia y sus tenants.
  7. Extrae con chunking. Pide secret_value where secret_name='federation_root_secret' — el db_message te lo devuelve cortado a ~32 caracteres (~FLAG{…~, sin cierre). La flag mide 38 caracteres. Parte la lectura en dos: substring(secret_value,1,31) y substring(secret_value,32,20), y concatena los dos fragmentos reflejados.
  8. Confirma el punto ciego / verifica. Reproduce el mismo ataque contra la segunda superficie (/api/auth/password-reset) para comprobar que no es una casualidad del login, y valida tu flag con bash flag/verify.sh (md5 de la preimagen).

Canales de feedback (no vuelas a ciegas)

  • El cuerpo del 500 (db_message + statement) en cada intento — el error crudo del motor y la sentencia SQL completa que se ejecutó.
  • El string reflejado entre ~…~ tras cada updatexml — confirma exactamente qué subconsulta se evaluó y con qué resultado.
  • La longitud visible del valor reflejado (~32 caracteres, cortado) — la señal explícita de que hace falta partir la extracción.

Decoys (descártalos por razonamiento acotado)

  • Decoy A — auth-bypass (username=' OR 1=1-- ): 401, sin error, sin login — el password-check va parametrizado con bcrypt.compare, aislado de la resolución de tenant.
  • Decoy B — typeahead de organizaciones (GET /api/directory/orgs?q='): 200 con results: [], ecoa q pero busca con WHERE name LIKE ? (bind) — el ' es texto literal, no delimitador.
  • Decoy C — ORDER BY con allowlist (GET /api/directory/reset-history?sort=(select 1)): 400 invalid sort field — el valor nunca llega a interpolarse.
  • Decoy D — campos hermanos parametrizados: un ' en password o en tenant (hint opcional del login) no dispara ningún error — solo username alcanza la query cruda.

La falla del laboratorio

Clase: CWE-89 (SQL Injection) + CWE-209 (Generation of Error Message Containing Sensitive Information) + CWE-200 (Exposure of Sensitive Information to an Unauthorized Actor). OWASP A03:2021 (Injection) + A05:2021 (Security Misconfiguration).

La causa raíz vive en lib/directory.ts: resolveTenantByUsername() (login) y findAccountForReset() (reset) construyen la query de resolución de tenant concatenando username directamente en el string SQL y la ejecutan con pool.query(sql), sin values de bind. Es una función con un propósito legítimo — decidir a qué directorio de tenant pertenece un empleado antes de validar su contraseña — que casualmente interpola el identificador crudo. El propio password-check, en cambio, va por una segunda query parametrizada (WHERE tenant_id = ? AND username = ?) más bcrypt.compare, por eso la inyección nunca salta la autenticación: solo puede hacer que la consulta de resolución se comporte mal.

El segundo defecto amplifica al primero: middleware/verboseError.ts reenvía err.sqlMessage y la sentencia reconstruida (err.statement/err.sql) tal cual al cliente "para facilitar el diagnóstico de la federación entre Ingressia y el directorio del tenant". Sin ese error verboso, updatexml() seguiría rompiendo la query, pero el cliente solo vería un 500 genérico — el texto reflejado es lo que convierte cada fallo de sintaxis en un canal de exfiltración in-band, y también lo que le enseña al atacante la tabla directory_identities sin tener que adivinarla.

El usuario de base de datos de la aplicación, ingressia_app, tiene privilegios SELECT/INSERT/UPDATE únicamente sobre su propio schema (ingressia_directory), sin FILE, PROCESS ni superusuario. No existe ruta a LOAD_FILE/INTO OUTFILE ni a stacked queries: el techo de la explotación es exfiltración pura, lo que mantiene el laboratorio en Medium en vez de escalarlo a un RCE.

Lección: parametriza siempre los identificadores dinámicos, incluso en pasos que parecen "de infraestructura" (resolver un tenant, enrutar una petición) y corren antes del chequeo de negocio real; y nunca devuelvas al cliente el mensaje crudo del motor de base de datos ni la sentencia ejecutada — un handler de errores verboso convierte cualquier fallo de sintaxis en un oráculo de datos.

Laboratorio basado en la reproducción anonimizada (empresa ficticia Ingressia) de una técnica real de bug bounty sobre inyección SQL error-based en un flujo de autenticación.

Contacto

Practica, aprende y hackea

Plataforma de práctica de bug bounty con labs basados en hackeos reales. Aprende hacking ético en entornos seguros.

contactar→

Síguenos

YouTube
@0xGorka
X
@gorkaelbochi
LinkedIn
gorka-el-bochi-morillo
Instagram
@_.gorkaaa.b
Email
team@bblabs.es

Accede a todos los labs desde 7,99€/mes

Nuevos labs cada semana. Cancela cuando quieras.

Crear cuenta

BBLabs es la plataforma de laboratorios de bug bounty en español donde aprender bug bounty con vulnerabilidades reales extraídas de hackeos pagados en HackerOne, YesWeHack y Bugcrowd. Aquí practicas hacking web —XSS, SQLi, IDOR, SSRF, CSRF y más— en entornos descargables, capturas la flag, lees el writeup y aplicas la técnica en programas activos de bug bounty.

BBLabs es la alternativa en español a HackTheBox, TryHackMe y PentesterLab para quienes quieren practicar bug bounty con hackeos reales en lugar de CTFs artificiales. Desde 7,99€/mes, sin permanencia.

→ Aprender bug bounty desde cero→ Cómo hacer bug bounty paso a paso→ Reportes de bug bounty reales→ BBLabs para empresas y academiasLabsAcademyVulnerabilidadesHerramientasRanking de hackersLabs de XSSLabs de IDORLabs de SSRFLabs de CSRFHackTheBox alternativaHack4u alternativaTryHackMe alternativaPortSwigger alternativaPentesterLab alternativaBug Bounty Labs comparativaHackerOne para practicarOffSec / OSCP alternativaINE / eWPT alternativaHTB Academy alternativaDVWA alternativaJuice Shop alternativaVulnHub alternativaPentesterAcademy alternativaRoot-Me alternativaHackTheBox vs TryHackMeMejores plataformas bug bounty 2026BlogSpoilers¿Qué es el bug bounty?¿Cuánto se gana en bug bounty?OWASP Top 10 explicadoMejores webs para practicar hacking webCómo ser hacker ético desde ceroTutorial de Burp Suite en españolOSCP en español: guía y preparaciónGoogle Dorks para bug bountyCuánto gana un hacker ético en EspañaHerramientas de bug bounty 2026Mejores certificaciones de ciberseguridad 2026Burp Suite tutorialsqlmap tutorialffuf fuzzing webnuclei tutorialHTTP Request SmugglingWAF bypassPrompt injection (LLM)Google Dorks
Hecho cony código
TérminosPrivacidadCookiesComparativaEN

© 2026 BBLABS v2 — Todos los derechos reservados