← Volver al buscador
Seguridad web Intermedio

IDOR y BAC — metodología manual para encontrar broken access control

Cómo identificar IDOR (Insecure Direct Object Reference) y BAC (Broken Access Control) manualmente: dual-account testing, parameter swap, role escalation, hidden parameters.

Respuesta rápida

IDOR y BAC siguen siendo el #1 de OWASP API Security en 2026. La regla: scanners automáticos no los encuentran — requieren contexto de negocio (¿qué hace este endpoint?) y dos cuentas para verificar el access boundary. La metodología: dos cuentas (A y B), capturar requests de A en Burp, swappear IDs/cookies por los de B, observar la respuesta. Si A puede ver/editar/borrar recursos de B, es IDOR. Si un user normal puede llegar a endpoints de admin, es BAC vertical. Bounties típicos: €500-€10.000+ según el impacto.


Setup — dos cuentas en paralelo

El error de principiante: probar IDOR con una sola cuenta. Sin la cuenta B no tienes baseline — no sabes si el server rechaza al user de A o si simplemente el ID no existe.

Stack:

  • Burp Suite (Community vale) con dos browsers (Chrome perfil A, Firefox perfil B).
  • O dos perfiles del mismo browser + extensiones tipo Auth Analyzer o Autorize.
  • Match-and-replace en Burp para swappear cookies automáticamente.
Browser A (Chrome)  →  Burp Proxy  →  target.com
Browser B (Firefox) →  Burp Proxy  →  target.com

Captura un request de A, manda a Repeater, cambia solo la cookie/header de auth por la de B (todo lo demás igual). Si la respuesta es la misma que la de A → IDOR confirmado.

[!tip] Auth Analyzer extension Autoriza Burp a re-enviar cada request con la sesión de un user diferente y comparar la respuesta. Lo más rápido para auditar 50+ endpoints sin script.


Las 8 superficies donde aparece IDOR

#SuperficieEjemplo de URLTest
1Path parameter numérico/api/users/1234512344, 12346, 0, -1
2Path parameter UUID/api/orders/abc-def-ghiUUID de B obtenido por otra vía
3Query parameter/profile?userId=42Cambiar a 43
4Body JSON field{"userId": 42, "data": "..."}Swap userId al de B
5Header customX-User-Id: 42Cambiar a 43
6Cookie valueCookie: uid=42; ...Cambiar a 43
7Hidden form field<input type="hidden" name="user_id" value="42">Cambiar antes de submit
8JWT claim{"sub": "42", "role": "user"}Re-firmar con sub=43 si firma débil

El truco de oro: muchas apps validan el ID en el path pero no el del body. Si el endpoint es POST /api/users/42/profile con body {"userId": 42, "newName": "..."}, prueba dejar el path en 42 pero meter userId: 43 en el body. Frecuentemente el server ignora el path y confía en el body.


Cómo obtener IDs ajenos

Sin IDs de la cuenta B (o de otros users) no puedes confirmar IDOR. Fuentes:

  • Tu propia cuenta B: regístrala con email distinto y observa qué IDs aparecen.
  • Endpoints de listado público: /users/search, /api/leaderboard, /comments?postId=X.
  • Funcionalidades que filtran IDs: avatars (/avatars/USER_ID.jpg), notifications (from_user_id), public posts.
  • URLs compartidas: invitación, magic link, recibo de compra que incluye order ID.
  • Source maps + bundles JS: a veces los routers en frontend listan IDs hardcoded de demos.
  • GraphQL introspección + queries de búsqueda sin filtro de visibilidad.

[!warning] Privacy + scope Si encuentras IDOR que filtra PII (email, phone, dirección, DNI), documenta CON tu propia cuenta de control — no tires bulk extraction contra users reales. La mayoría de programs prohíbe extraction de >1-2 records de cuentas no propias.


IDOR horizontal vs vertical

Horizontal — mismo rol, otra identidad. User A accede a recursos de user B:

GET /api/orders/B_ORDER_ID
Authorization: Bearer JWT_DE_A
                                    ← 200 OK con datos de B = IDOR horizontal

Vertical — escalación de privilegios. User normal accede a endpoints/funciones de admin:

DELETE /api/admin/users/12
Authorization: Bearer JWT_DE_USER_NORMAL
                                    ← 200 OK = BAC vertical

Vertical pesa más en CVSS — usualmente Critical (9.0+). Bounties típicos €5K-€20K+.


Parameter swap — el patrón más rentable

Casi todos los IDOR rentables vienen de swappear un parámetro en un endpoint que parece inofensivo:

Cambio de email — sin verificación

PUT /api/users/me/email
{"email": "atacante@evil.tld", "userId": ID_DE_VICTIMA}

Server actualiza email del userId del body, ignora el me del path → reset password vía email controlado → ATO.

Cambio de password — oldPassword no verificado

POST /api/users/CHANGE_PASSWORD
{"userId": ID_VICTIMA, "newPassword": "atacante"}

Endpoint no pide oldPassword. Tipicamente bounty €3K-€8K.

Cancelación de orden — refund a cuenta atacante

POST /api/orders/B_ORDER_ID/refund
{"refundTo": "atacante_bank_account"}

Asignación de rol en team

POST /api/teams/T_ID/members
{"userId": ATACANTE_ID, "role": "owner"}

Si el endpoint no verifica que el actor sea owner del team → cualquier user puede unirse como owner a cualquier team.


Hidden parameters — los que generan bounties grandes

Muchos endpoints aceptan parámetros que no aparecen en requests legítimos del UI. El backend los procesa si están presentes, pero el frontend nunca los manda. Resultado: features no documentadas, a veces de admin.

Wordlist de parámetros frecuentes

admin, isAdmin, is_admin, role, userRole, accountType
debug, test, dev, sandbox, preview
force, bypass, override, skipAuth
verified, isVerified, emailVerified
status, accountStatus, suspended, banned
internal, system, super, root
hidden, public, visible

Tools

# Arjun — descubre parámetros HTTP ocultos
arjun -u https://target.com/api/users -m GET

# Param Miner (Burp extension)
# Right-click request → Extensions → Param Miner → Guess params

Ejemplos de bounty real con hidden params

  • POST /api/users con body normal {email, password} + extra {"role": "admin"} → user nuevo creado como admin.
  • PUT /api/posts/X con extra {"approvedBy": "system"} → bypassea cola de moderación.
  • GET /api/orders/X?debug=true → response expandida con campos internos (PII, internal IDs, cost).

Function-level BAC — endpoints que el frontend no llama

El UI normal nunca llama a /api/admin/users desde un user normal — pero el endpoint sigue existiendo y a veces no chequea el rol.

Cómo encontrarlos

  1. Login como admin (test account si el program lo permite, o user normal con permisos altos).
  2. Captura todos los endpoints que el admin dashboard llama.
  3. Logout, login como user normal.
  4. Re-tira los mismos endpoints. ¿Hay alguno que responda 200?

Frecuentemente encuentras endpoints que verifican el token (auth) pero no el rol (authorization).

admin → GET /api/admin/users → 200 [lista de users]
user  → GET /api/admin/users → 200 [lista de users]    ← BAC vertical

Method swap

Algunos endpoints solo validan el método HTTP correcto. Prueba:

POST /api/admin/users     → 403 Forbidden
GET  /api/admin/users     → 200 OK             ← BAC
PUT  /api/admin/users/42  → 403 Forbidden
PATCH /api/admin/users/42 → 200 OK             ← BAC

Trailing slash + extension trick

Algunos WAFs filtran rutas exactas. Prueba variantes:

/api/admin/users     → 403
/api/admin/users/    → 200            ← trailing slash bypass
/api/admin/users.json → 200           ← extension
/api/admin/users;.css → 200           ← matrix params
/api/admin/users%20  → 200            ← trailing whitespace
/api/Admin/users     → 200            ← case
/api/admin//users    → 200            ← double slash

IDOR en GraphQL

GraphQL multiplica la superficie: un solo endpoint expone N queries. El control de acceso suele estar a nivel de resolver, no de field — muy fácil olvidarse de alguno.

Test pattern

query {
  user(id: "OTRO_USER_ID") {
    email
    phoneNumber
    addresses { street }
    paymentMethods { last4 }
  }
}

Si la app no chequea ownership en el resolver de user, lo devuelve. Repite con node(id: ...) (interface common en relay) y con queries de búsqueda sin filtro de visibilidad.

Mutations

mutation {
  updateUser(id: "VICTIMA_ID", input: { email: "atacante@evil.tld" }) {
    id
  }
}

Muchos backends GraphQL verifican que el user está autenticado pero no que sea owner del id que pide modificar.


Reporting tips

  • Severity boost: si el IDOR filtra PII regulado (DNI, datos médicos, financieros) → impact privacy, GDPR.
  • Account takeover chain: si IDOR permite cambiar email → ATO inmediato, severity Critical.
  • Bulk extraction warning: documenta el patrón con 2-3 records de tu cuenta + cuenta control. NO extraigas miles.
  • Bypass docs: lista cada filtro intentado por el server (path validation, body validation, method check) y cómo lo bypaseaste — sube el reward y el dev fix más sólido.

Hunting checklist

  • Setup dos cuentas (A y B) en paralelo con Burp/Auth Analyzer.
  • Mapea todos los endpoints que aceptan ID en path, query, body, header o cookie.
  • Swap ID con sesión de B, observa respuesta.
  • Prueba todas las acciones (GET / PUT / DELETE / POST) — algunas validan GET pero no DELETE.
  • Hidden parameters con Arjun + Param Miner.
  • Login como admin (si tienes), captura endpoints admin, reproduce con user normal.
  • Method swap + trailing slash + extension tricks en endpoints 403.
  • GraphQL: prueba user(id), node(id), queries de listado sin filtro.
  • Cross-tenant: si la app es multi-tenant, prueba accesos cross-org.
  • Documenta con 2-3 records máx, never bulk extract.

Labs relacionados

Practica IDOR horizontal/vertical, hidden params y BAC function-level en labs de IDOR y BAC.

Practica esto en un lab

Idor Api Newsletter Suscriptores

Resolver

Sigue aprendiendo · cuenta gratis

Guarda tu progreso, desbloquea payloads avanzados y rankea tus flags.

Crear cuenta
Premium · 1 técnica más

Hay un payload extra al final

Los 12 parámetros ocultos que tests automáticos no detectan pero generan bounties de €1500-€5000 con regularidad.

Desbloquear

7,99 €/mes · cancela cuando quieras

Artículos relacionados

Premium$3500

Client-side admin bypass — boolean manipulation + BAC en SPA moderna

Report real Quora: SPA con isAdmin boolean en localStorage que controla UI + backend que no valida server-side. Cómo encadenar boolean flip con BAC para admin takeover.

13 minbacadmin-bypassclient-side
Leer artículo
Gratis

IDOR en API de newsletters — la UI lo oculta, la API lo regala

Un endpoint sin comprobación de autorización en servidor. Un parámetro público en la URL. Acceso a la lista de suscriptores de cualquier newsletter de una red social profesional.

9 minidorbroken-access-controlapi
Leer artículo
Gratis

Mass PII Extraction vía GraphQL — 93 perfiles reales en 1 hora

Un endpoint GraphQL de sincronización de contactos sin rate limiting, sin verificación de propiedad y con batching de 200 números por petición. Resolución teléfono → identidad real.

13 mingraphqlenumerationpii
Leer artículo
Nivel intermedioToda la Academy

Contenido educativo de Kerb3r0ps. Úsalo solo sobre sistemas para los que tengas permiso. Volver al buscador.