Una aplicación puede funcionar correctamente en sus recorridos habituales y fallar cuando alguien cambia una petición. El trabajo de una prueba de penetración consiste en formular esas preguntas, comprobarlas de forma controlada y explicar qué consecuencias tienen los resultados.
En este artículo construiremos un primer laboratorio con OWASP Juice Shop, una aplicación deliberadamente vulnerable. Observaremos sus peticiones HTTP y comprobaremos si una cuenta puede leer el carrito de otra cuenta de prueba. El objetivo es aprender un método que produzca evidencia útil para corregir software.
Todo el ejercicio se realiza en tu equipo, con cuentas ficticias y una instancia propia. No necesitas probar una web pública ni utilizar la demo compartida de Juice Shop.
Qué es una prueba de penetración
Una prueba de penetración, o pentest, evalúa si una debilidad puede aprovecharse para vulnerar un control de seguridad y qué impacto permite demostrar dentro del alcance acordado. Combina conocimiento de la aplicación, observación y pruebas dirigidas.
No equivale a ejecutar una herramienta y exportar sus alertas. Tampoco exige llevar cada fallo hasta su consecuencia más dañina: una evidencia mínima puede bastar para confirmar el problema.
La introducción de OWASP Web Security Testing Guide sitúa el pentesting dentro de un programa más amplio que también incluye revisión de código y pruebas durante el desarrollo. Un pentest tiene límites de tiempo y cobertura; no encontrar fallos no demuestra que no existan.
Análisis de vulnerabilidades y pentesting
| Aspecto | Análisis de vulnerabilidades | Prueba de penetración |
|---|---|---|
| Foco | Identificar y valorar debilidades | Comprobar escenarios de abuso e impacto |
| Trabajo habitual | Inventario, configuración, versiones, herramientas y revisión manual | Hipótesis, peticiones controladas y validación de controles |
| Entrega | Debilidades detectadas, evidencia y prioridades | Hallazgos reproducibles con alcance e impacto demostrado |
Hay solapamientos. Un análisis de vulnerabilidades puede incluir validación manual y un pentest puede utilizar escáneres. La diferencia práctica está en la pregunta y la profundidad de la comprobación, no en dividir todo entre «automático» y «manual».
Una alerta sobre una dependencia desactualizada es un punto de partida. Demostrar que una cuenta puede leer datos privados de otra responde una pregunta concreta sobre el comportamiento de la aplicación.
Antes de enviar peticiones: alcance y autorización
En un trabajo profesional, deja por escrito quién autoriza la prueba, qué activos incluye, en qué fechas y con qué restricciones. Tener una cuenta, conocer una URL o trabajar para una organización no define por sí solo ese permiso.
Un acuerdo operativo debería identificar los sistemas incluidos y excluidos, las cuentas de prueba, las acciones admitidas, los límites de tráfico, el contacto para incidentes y las condiciones para detenerse. También debe definir cómo conservar y entregar la evidencia.
Para este laboratorio usaremos este alcance concreto:
| Elemento | Límite del ejercicio |
|---|---|
| Objetivo | Tu contenedor Juice Shop en http://127.0.0.1:3000 |
| Identidades | Dos cuentas ficticias creadas por ti |
| Acciones | Navegar, registrar cuentas, añadir productos propios y repetir lecturas HTTP |
| Fuera de alcance | Otras webs, otras máquinas, cuentas ajenas y servicios enlazados por la tienda |
| Exclusiones | Fuerza bruta, escaneos masivos, pagos y cambios sobre el carrito de la otra cuenta |
| Finalización | Guardar evidencia depurada y detener el contenedor |
Estas son reglas para nuestra práctica. La WSTG es una guía técnica; no sustituye el acuerdo de autorización ni convierte sus recomendaciones en obligaciones legales generales.
Una metodología que puedas repetir
Usaremos referencias de WSTG v4.2, la edición estable indicada por el proyecto OWASP. Los enlaces versionados permiten identificar qué documento seguimos aunque la guía continúe evolucionando.
El recorrido será:
No se pudo mostrar el diagrama. Puedes consultar su definición.
flowchart TD
A[Definir alcance y autorización] --> B[Reconocer funciones y peticiones]
B --> C[Establecer una respuesta de referencia]
C --> D[Probar una hipótesis dentro del alcance]
D --> E[Validar y conservar evidencia mínima]
E --> F[Documentar impacto y corrección]
F --> G[Repetir la prueba tras corregir]
Reconocimiento: comprender la aplicación
En este contexto, reconocer significa identificar funciones, roles, rutas y entradas. Navega primero como un usuario normal: registra una cuenta, busca un producto y abre el carrito.
Anota qué peticiones aparecen, qué parámetros identifican objetos y qué operaciones necesitan sesión. No confundas la ruta visible en una aplicación SPA con la petición que recibe el servidor: /#/basket es una ruta del cliente, mientras que los datos pueden llegar mediante otra URL.
WSTG-INFO-06: Identify Application Entry Points propone estudiar estos intercambios y sus entradas. Un mapa pequeño puede contener método, ruta, autenticación, parámetros y función observada.
Interceptación HTTP: observar antes de modificar
Un proxy de interceptación se coloca entre el navegador y la aplicación. Permite revisar solicitudes y respuestas y, cuando lo decides, detener una petición antes de enviarla.
La captura del historial y la interceptación con pausa son funciones distintas. Puedes navegar con la interceptación desactivada y seguir registrando el tráfico. Después eliges una petición concreta para repetirla y comparar respuestas.
En HTTP, revisaremos método, ruta, cabeceras y cuerpo. Si aparece Authorization: Bearer ..., ese valor es una credencial de la sesión: no debe terminar en capturas públicas o informes sin depurar.
Autenticación, sesión y autorización
La autenticación comprueba la identidad presentada. La sesión permite asociar peticiones posteriores con esa identidad. La autorización decide si puede realizar una operación sobre un recurso.
La WSTG dedica secciones diferentes a autenticación y gestión de sesiones. Algunas preguntas iniciales son:
- ¿Se rechaza una contraseña incorrecta?
- ¿Qué credencial se emite al iniciar sesión y dónde se envía después?
- ¿Una operación privada rechaza peticiones sin esa credencial?
- ¿Qué ocurre con una credencial anterior después de cerrar sesión o vencer su vigencia?
- ¿Una cuenta autenticada puede acceder a objetos de otra cuenta?
La comprobación del cierre de sesión requiere observar una respuesta nueva del servidor, no solo una pantalla guardada en caché. WSTG-SESS-06 desarrolla esa prueba. En este primer laboratorio nos centraremos en login, ausencia de token y acceso entre dos cuentas; no evaluaremos toda la recuperación de contraseñas, los tiempos de sesión o los mecanismos de bloqueo.
Si el token es un JWT, recuerda que decodificarlo no equivale a validarlo. Ver información en su payload no demuestra por sí solo una vulnerabilidad.
Burp Suite Community y ZAP: cuál usar para empezar
Ambas herramientas permiten observar tráfico web. Para este ejercicio basta con una de ellas.
| Necesidad | Burp Suite Community | ZAP |
|---|---|---|
| Proxy e historial HTTP | Incluidos | Incluidos |
| Repetir una petición manualmente | Repeater | Editor/reenvío de peticiones, según la interfaz instalada |
| Escaneo automático de vulnerabilidades | El scanner de Burp corresponde a Professional | Dispone de análisis pasivo y escaneo activo |
| Distribución | Edición gratuita con funciones limitadas | Gratuito y de código abierto |
| Uso en esta práctica | Navegación, historial y Repeater | Exploración manual y revisión del tráfico |
La comparación de funciones procede de PortSwigger y de la documentación de ZAP. ZAP, frecuentemente referido como OWASP ZAP, se presenta actualmente como un proyecto independiente de código abierto.
Para explicar el laboratorio seguiremos Burp Community. Es una elección didáctica: Repeater permite cambiar una sola parte de la petición y observar qué ocurre.
En ZAP, Safe Mode sirve para comenzar observando, pero impide interceptar y reenviar peticiones. Para esas acciones debes definir el contexto y el alcance local y utilizar Protected Mode. No selecciones ATTACK, que activa escaneos sobre nuevos nodos del alcance. Estas diferencias están documentadas en los modos de ZAP.
El análisis pasivo revisa mensajes que pasan por la herramienta; el activo envía peticiones de prueba. Una alerta pasiva necesita interpretación y validación: no es automáticamente un hallazgo confirmado.
Preparar OWASP Juice Shop en local
Necesitas Docker en funcionamiento, un navegador y Burp Suite Community o ZAP. Utiliza una instalación de Docker actualizada, con Engine 28 o superior. La documentación de Docker advierte de limitaciones en versiones anteriores al restringir puertos publicados a localhost.
Fijaremos Juice Shop v20.3.0, la versión utilizada en esta práctica, para que un cambio de latest no modifique el ejercicio sin aviso.
En una terminal Bash o Zsh:
docker pull bkimminich/juice-shop:v20.3.0
docker run --detach --rm \
--name uncodigo-juice-shop-lab \
--publish 127.0.0.1:3000:3000 \
bkimminich/juice-shop:v20.3.0La publicación explícita en 127.0.0.1 evita exponer ese puerto en todas las interfaces del equipo con la configuración habitual de Docker. No la sustituyas por 3000:3000. Tampoco añadas túneles públicos, montajes de carpetas personales o acceso al socket de Docker.
El contenedor no es una garantía de aislamiento absoluto. Aquí lo usamos como entorno desechable y limitado, siguiendo la instalación oficial de Juice Shop. No hacen falta servicios externos de IA, Web3 ni credenciales de proveedores para este ejercicio.
Comprueba la publicación y espera a que la aplicación responda:
docker port uncodigo-juice-shop-lab
curl --fail --silent --show-error \
--output /dev/null \
--write-out '%{http_code}\n' \
http://127.0.0.1:3000/El mapeo debe mostrar 3000/tcp -> 127.0.0.1:3000 y la comprobación HTTP debe terminar en 200. Si acabas de iniciarlo y aún no responde, consulta docker logs uncodigo-juice-shop-lab y vuelve a comprobar. Si el puerto o el nombre ya están ocupados, identifica el proceso o contenedor existente antes de continuar; no lo elimines a ciegas.
Puedes registrar también el digest de la imagen descargada para conservar una referencia más precisa que la etiqueta:
docker image inspect bkimminich/juice-shop:v20.3.0 \
--format '{{index .RepoDigests 0}}'Capturar el recorrido normal
Configurar el proxy
En Burp Community, inicia un proyecto temporal y abre Proxy → Intercept → Open Browser. Deja Intercept off durante la navegación inicial y visita únicamente http://127.0.0.1:3000.
En Target → Site map, añade ese origen al alcance mediante Add to scope y filtra el historial para mostrarlo. Comprueba que el alcance corresponde a HTTP, 127.0.0.1 y el puerto 3000. El filtro ayuda a organizar el trabajo; no debe tratarse como un cortafuegos que autoriza cualquier petición enviada desde Repeater.
Los pasos se basan en la documentación de PortSwigger sobre interceptación y alcance, adaptados a nuestra instancia local. No necesitas visitar los objetivos de sus tutoriales para seguir este artículo.
Si eliges ZAP, usa Quick Start → Manual Explore con la URL local y su navegador configurado. No pulses Automated Scan para esta práctica. El HTTP local evita tener que instalar una autoridad certificadora en tu navegador personal; no es una configuración para desplegar una aplicación real.
Crear dos cuentas y distinguir sus recursos
Usa únicamente datos ficticios. Los menús siguientes corresponden a la interfaz en inglés; puedes seleccionarla desde el control de idioma de Juice Shop.
- Cierra el aviso de bienvenida con Dismiss. Ve a Account → Login → Not yet a customer? para registrar a Bea con
[email protected]. - Elige una contraseña exclusiva de laboratorio y una respuesta ficticia a la pregunta de seguridad. No reutilices datos personales.
- Inicia sesión como Bea, añade un producto al carrito y abre Your Basket.
- En Proxy → HTTP history, localiza la lectura
GET /rest/basket/<id>. Anota el identificador y el producto del carrito de Bea. No presupongas un número fijo. - Cierra sesión. Registra a Ana con
[email protected], inicia sesión y añade un producto diferente a su carrito. - Abre el carrito de Ana y localiza su lectura equivalente. Conserva esta petición como referencia mientras Ana sigue autenticada.
El historial debe permitir relacionar la acción en pantalla con su petición HTTP. En esta versión, el inicio de sesión utiliza POST /rest/user/login y la lectura del carrito utiliza GET /rest/basket/<id>.
Para practicar la pausa de una petición, activa Intercept on, vuelve a abrir el carrito y observa la solicitud antes de pulsar Forward. Después vuelve a Intercept off. Si la página parece quedarse esperando, revisa si el proxy está reteniendo peticiones pendientes.
Probar una hipótesis de autorización
Nuestra hipótesis es: el servidor debería permitir a Ana leer su carrito, pero rechazar la lectura del carrito privado de Bea.
Esta prueba corresponde a WSTG-ATHZ-04: Testing for Insecure Direct Object References. Utilizamos dos cuentas propias para conocer los recursos sin enumerar identificadores de otros usuarios.
En Burp:
- Envía la lectura del carrito de Ana a Repeater mediante Send to Repeater.
- Comprueba que el destino sigue siendo
127.0.0.1:3000, sin TLS. Reenvía la petición sin cambios y confirma que devuelve el carrito de Ana. - Duplica la petición o conserva la respuesta original. Cambia solo el identificador de la ruta por el identificador del carrito de Bea que anotaste antes.
- Mantén la credencial de Ana en
Authorization. No copies el token de Bea: eso probaría otra cosa. - Envía una vez y compara el cuerpo con el carrito que observaste legítimamente como Bea.
La documentación de Repeater explica cómo conservar y reenviar estas peticiones. Verifica siempre el destino antes de enviarlas; los enlaces externos de la tienda quedan fuera del ejercicio.
En una respuesta no basta con mirar el 200: comprueba el identificador y los productos. Algunas aplicaciones devuelven errores de negocio dentro de respuestas HTTP exitosas; otras muestran solo el HTML de la SPA. Ninguno de esos casos demostraría por sí solo acceso al carrito de Bea.
Como control adicional, duplica la petición y retira la cabecera Authorization y cualquier cookie de autenticación. No cambies el destino ni pruebes otros identificadores.
Qué observamos en esta versión
Al verificar el laboratorio con Juice Shop v20.3.0 se obtuvo:
| Petición | Resultado observado |
|---|---|
| Ana lee su carrito con su token | 200, datos del carrito de Ana |
| Bea lee su carrito con su token | 200, datos del carrito de Bea |
| Ana solicita el carrito de Bea con el token de Ana | 200, datos del carrito de Bea |
| Petición al carrito sin token | 401 |
| Inicio de sesión con una contraseña incorrecta de prueba | 401 |
La navegación, el registro y los carritos se comprobaron en un navegador; las comparaciones HTTP se automatizaron contra la misma instancia local. Las instrucciones de la interfaz de Burp y ZAP se contrastaron con sus manuales oficiales; no son una afirmación de haber ejecutado ambas aplicaciones de escritorio.
El resultado confirma un fallo de autorización por objeto en el escenario probado. La aplicación exige autenticación, pero no impide esta lectura entre usuarios. No demuestra que se puedan modificar carritos ajenos, acceder a todos los datos o controlar el servidor: esas afirmaciones exigirían otras pruebas y otro alcance.
Juice Shop incluye deliberadamente el reto View Basket, descrito en su guía de controles de acceso. Aquí se utiliza como ejercicio, no como un descubrimiento nuevo sobre un sistema de producción.
Si obtienes una respuesta diferente, conserva la evidencia y revisa versión, cuenta activa, token, ruta e identificador. No cambies arbitrariamente de objetivo para conseguir el resultado del artículo.
Convertir evidencia en un hallazgo útil
Un hallazgo debe permitir que otra persona entienda el problema, lo reproduzca dentro del alcance y compruebe la corrección. La sección Reporting de WSTG ofrece una estructura adaptable para comunicar resultados técnicos y sus consecuencias.
Para nuestro laboratorio, una ficha breve sería:
| Campo | Contenido del hallazgo |
|---|---|
| Identificador | LAB-01 |
| Título | Una cuenta autenticada puede leer el carrito de otra cuenta |
| Entorno | Juice Shop v20.3.0, instancia local propia |
| Precondiciones | Dos cuentas de prueba con carritos distintos y sesión válida de Ana |
| Reproducción | Capturar la lectura de Ana y sustituir solo la referencia al carrito por la de Bea |
| Resultado esperado | Denegación sin exponer los datos del carrito de Bea |
| Resultado observado | Respuesta 200 con el carrito y el producto de Bea |
| Impacto demostrado | Lectura no autorizada de contenido de otro carrito del laboratorio |
| Corrección propuesta | Autorizar en el servidor la relación entre usuario autenticado y carrito solicitado |
| Verificación posterior | Ana conserva acceso a su carrito; el acceso al de Bea se rechaza |
Adjunta las peticiones y respuestas mínimas que respaldan la comparación, con tokens y contraseñas ocultos. Indica la versión, el momento de la prueba y sus limitaciones. No conviertas un informe en un volcado completo del proxy.
La severidad depende del contexto, la exposición y la sensibilidad de los datos. En este laboratorio no asignaremos un valor CVSS ni afirmaremos un impacto económico que no hemos evaluado. En un encargo real, utiliza el criterio acordado y explica por qué corresponde esa prioridad.
La corrección no consiste en ocultar el ID ni en cambiarlo por uno difícil de adivinar. Hay que comprobar quién puede actuar sobre el objeto, como explicamos en RBAC, ABAC y autorización por recurso. Esa comprobación debe integrarse junto con los demás controles de una API REST.
Cerrar y limpiar el laboratorio
Cuando termines, detén únicamente el contenedor de esta práctica:
docker stop uncodigo-juice-shop-labComo lo iniciamos con --rm, Docker elimina el contenedor al detenerlo. No hemos montado volúmenes para conservar sus datos. La imagen descargada permanece disponible por si quieres repetir el laboratorio.
Cierra el navegador de pruebas y elimina sus datos locales si vas a empezar de nuevo. Conserva solo la evidencia depurada que necesites y descarta los historiales con credenciales de laboratorio. No uses comandos de limpieza global como docker system prune: podrían afectar a otros proyectos.
Aprender a comprobar, explicar y corregir
Una buena primera práctica termina con algo más útil que una captura de una alerta: una hipótesis, una comparación reproducible y una explicación de lo que realmente ocurrió.
En este caso, el login rechazó una contraseña incorrecta y el endpoint rechazó una petición sin token. Aun así, una cuenta válida pudo leer el carrito de otra. Seguir ese hilo desde la interfaz hasta el informe permite conectar el pentesting con decisiones concretas de desarrollo y con una prueba que deberá pasar después de corregir el control.
Referencias
- OWASP Web Security Testing Guide — proyecto y versiones.
- WSTG v4.2 — Introduction.
- WSTG-INFO-06 — Identify Application Entry Points.
- WSTG v4.2 — Authentication Testing y Session Management Testing.
- WSTG-ATHZ-04 — Testing for Insecure Direct Object References.
- WSTG-SESS-06 — Testing for Logout Functionality.
- WSTG v4.2 — Reporting.
- Juice Shop — instalación oficial, versión v20.3.0 y Broken Access Control.
- PortSwigger — funciones de Community Edition, Burp Proxy, alcance y Repeater.
- ZAP — Quick Start, modos y análisis pasivo.
- Docker — publicación y mapeo de puertos.
