Improper Inventory Management
CWE: CWE-1059 - Incomplete API Documentation
Problema: Falta de control sobre versiones de API, endpoints expuestos, etc
¿Qué es?
No mantener un inventario adecuado de:
- Versiones de API (v1, v2, v3)
- Endpoints activos/deprecados
- Recursos expuestos
- Hosts/dominios
- Documentación actualizada
Vectores de Ataque
1. Versiones Antiguas Sin Actualizar
bash
# API actual
GET /api/v5/users
# Requiere autorización y validación
# Versión antigua aún funcional
GET /api/v1/users
# Sin validación, BOLA vulnerable
GET /api/v2/users
# Validación débil2. Endpoints Deprecados Activos
bash
# Endpoint antiguo aún retorna datos
GET /api/admin/backup-download
# Retorna backup de la DB
# Endpoint de testing aún expuesto
GET /api/test/all-credentials
# Endpoint internal exposición
GET /api/internal/debug3. Descubrimiento de Endpoints
bash
# Escanear endpoints comunes
endpoints = [
'/api/admin',
'/api/superadmin',
'/api/debug',
'/api/test',
'/api/internal',
'/api/backup',
'/api/export',
'/admin/users',
'/superadmin/settings'
]
for endpoint in endpoints:
curl "https://api.app.com$endpoint" -w "%{http_code}\n"4. Documentación Pública con Secretos
bash
# Documentación expone detalles
GET /api/docs # Swagger/OpenAPI
GET /api/v1/docs
GET /graphql
GET /graphiql
# Swagger revela:
- Todos los endpoints
- Parámetros esperados
- Tipos de respuesta
- Fallos de seguridad
curl https://api.app.com/api/docs | jq '.paths | keys'
# Ver todos los endpoints5. Múltiples Dominios/Hosts
bash
# API en múltiples locaciones
api.app.com
api-v1.app.com
api-dev.app.com
api-staging.app.com
api.app.co.uk
api-backup.app.com
# Algunos sin protección
curl https://api-dev.app.com/api/users
# Sin autenticación
curl https://api-staging.app.com/api/admin
# Credenciales test6. Falta de Control de Versiones
bash
# Endpoints sin versión
/api/users
/api/products
# Imposible suportar versiones antiguas
# Resultado: Cambios breaking afectan a todosEnumeración y Explotación
python
import requests
import json
from itertools import product
def discover_api_inventory(target):
"""
Descubrir todos los endpoints y versiones
"""
# Versiones comunes
versions = ['v1', 'v2', 'v3', 'v4', 'v5', 'api', 'beta', 'alpha']
# Paths comunes
paths = [
'users', 'products', 'orders', 'admin', 'settings',
'test', 'debug', 'internal', 'backup', 'export',
'reports', 'analytics', 'logs', 'config'
]
# Dominios
domains = [
'api',
'api-v1', 'api-v2',
'api-dev', 'api-staging',
'api-prod', 'api-backup',
'internal-api', 'test-api'
]
endpoints_found = []
print("[*] Buscando endpoints...")
# Probar versiones
for version in versions:
for path in paths:
url = f"https://{target}/api/{version}/{path}"
try:
r = requests.head(url, timeout=3, allow_redirects=False)
if r.status_code < 500:
endpoints_found.append((url, r.status_code))
print(f"[✓] {url} ({r.status_code})")
except:
pass
# Probar dominios
domain_base = target.split('.')[0]
tld = '.'.join(target.split('.')[1:])
for subdomain in domains:
host = f"{subdomain}.{tld}"
for path in ['', '/api', '/api/users', '/api/admin']:
url = f"https://{host}{path}"
try:
r = requests.head(url, timeout=3, allow_redirects=False)
if r.status_code < 500:
endpoints_found.append((url, r.status_code))
print(f"[✓] {url} ({r.status_code})")
except:
pass
return endpoints_found
# Ejecutar
discover_api_inventory("app.com")Parsing de Swagger/GraphQL
bash
# Extraer endpoints de Swagger
curl -s "https://api.app.com/api/swagger.json" | jq '.paths | keys'
# Resultado:
[
"/api/users",
"/api/users/{id}",
"/api/admin/settings",
"/api/internal/debug",
...
]
# Extraer parameters
curl -s "https://api.app.com/api/swagger.json" | \
jq '.paths["/api/users"]["get"].parameters'
# GraphQL - Introspection
curl -X POST "https://api.app.com/graphql" \
-H "Content-Type: application/json" \
-d '{"query": "{__schema{types{name,fields{name}}}}"}'Mitigación
1. Versionamiento Explícito
python
# ✓ Correcto
/api/v1/users # Versión 1
/api/v2/users # Versión 2 con cambios
/api/v3/users # Versión 3
# Soportar múltiples versiones
@app.route('/api/v1/users')
def get_users_v1():
# Lógica v1
pass
@app.route('/api/v2/users')
def get_users_v2():
# Lógica v2 (mejorada)
pass
# Deprecar versiones antiguas después de tiempo2. Inventario de Endpoints
python
# Mantener registro de todos los endpoints
ENDPOINTS = {
'v1': {
'/users': {'deprecated': True, 'migration': '/v2/users'},
'/products': {'status': 'active'},
},
'v2': {
'/users': {'status': 'active'},
'/products': {'status': 'active'},
},
'v3': {
'/users': {'status': 'active'},
'/products': {'status': 'active'},
}
}
# Middleware para validar versión
@app.before_request
def validate_version():
path = request.path
match = re.match(r'/api/v(\d+)/', path)
if match:
version = f"v{match.group(1)}"
# Si versión deprecada
if version not in ENDPOINTS:
return {"error": f"API {version} is deprecated"}, 4103. Documentación Segura
python
# No exponer toda la documentación públicamente
@app.route('/api/docs')
def api_docs():
# Requiere autenticación
if not request.headers.get('Authorization'):
return {"error": "Unauthorized"}, 401
# Retornar solo endpoints permitidos para el usuario
user = get_current_user()
filtered_docs = filter_docs_by_role(docs, user.role)
return filtered_docs4. Removir Endpoints Antiguos
python
# Deshabilitar versiones antiguas después de fecha
from datetime import datetime
VERSION_SUPPORT = {
'v1': {'end_of_life': datetime(2024, 1, 1)},
'v2': {'end_of_life': datetime(2024, 6, 1)},
'v3': {'end_of_life': datetime(2025, 1, 1)},
}
@app.before_request
def check_version_support():
version = extract_version_from_path(request.path)
if version in VERSION_SUPPORT:
eol = VERSION_SUPPORT[version]['end_of_life']
if datetime.now() > eol:
return {
"error": f"API {version} is no longer supported",
"migrate_to": "v3"
}, 4105. Limitar Información en Documentación
python
# Swagger/OpenAPI - No exponer todos los detalles
SWAGGER_CONFIG = {
"swagger": "2.0",
"info": {
"title": "API",
"version": "3.0"
},
"host": "api.app.com",
"basePath": "/api/v3",
"schemes": ["https"],
"paths": {
"/users": {
"get": {
"summary": "List users",
"parameters": [...],
"responses": {...},
# No incluir ejemplos con datos reales
# No exponer endpoints internos
}
}
}
}Checklist
- [ ] Inventario de todas las versiones de API
- [ ] Endpoint registry/documentation actualizada
- [ ] Versiones antiguas deprecadas con timeline
- [ ] Documentación no expone endpoints internos
- [ ] No hay endpoints test/debug en producción
- [ ] Todos los hosts/dominios registrados
- [ ] Versionamiento explícito en URLs
- [ ] Migración path para endpoints deprecados
- [ ] EOL date para versiones antiguas