Herramientas de seguridad
Lo básico de OWASP ZAP contra tu Juice Shop local
Ejecuta el escaneo pasivo de ZAP contra Juice Shop en tu máquina, lee el informe y verifica una alerta a mano antes de confiar en ella.
Nmap lista los puertos abiertos de tu propia máquina. Revisa escaneos connect y SYN, detección de servicios y cómo ligar cada puerto a su proceso.
Nmap es un escáner de red. Lo apuntas a un host y te informa qué puertos responden, en qué estado está cada uno y, si lo pides, qué servicio y versión hay detrás de un puerto abierto. En tu propia máquina, eso lo convierte en una herramienta rápida de inventario. Obtienes la lista de lo que está escuchando y puedes compararla con lo que crees que tienes corriendo.
Trata la salida de Nmap como un inventario de partida. No es un hallazgo. Un puerto abierto solo te dice que un socket está escuchando. Si ese socket es un problema depende de qué proceso es su dueño, de quién puede alcanzarlo y de si debería existir. Este artículo termina con el paso que la mayoría se salta: relacionar cada puerto abierto con el proceso que está detrás.
La mayoría de las sorpresas en una máquina vienen de algo que nadie recuerda haber iniciado. Un servidor de desarrollo que quedó corriendo desde la semana pasada. Un contenedor que publicó un puerto en todas las interfaces. Un servicio en segundo plano que se instaló solo durante una actualización. No puedes evaluar lo que no has listado, y un inventario de puertos es la forma más barata de empezar. El mismo método sirve en una laptop, en una máquina virtual que tú construiste o en una red de cliente que tienes autorización para probar.
Lee esto antes de ejecutar cualquier escaneo. El libro de Nmap tiene un capítulo sobre temas legales, y su consejo central es sencillo: pide permiso antes de escanear una red que no controlas. Recuerda que algunos proveedores de internet prohíben el escaneo no autorizado en sus políticas de uso aceptable y pueden desconectar a quien las incumpla. En trabajo profesional, dice que la mejor forma de evitar problemas es obtener autorización por escrito de quienes representan la red objetivo, con el Statement of Work como lugar para registrarla. También señala que rara vez te molestan por escanear tu propia máquina o las redes que administras.
Para este artículo, la regla es:
Todos los comandos de este laboratorio apuntan a 127.0.0.1, la dirección de loopback. Los paquetes enviados ahí nunca salen de tu máquina. Por eso el laboratorio es seguro para practicar, y el alcance es fácil de definir: el único host involucrado es el tuyo.
Un puerto es un número que el sistema operativo usa para entregar tráfico entrante a un proceso. Si un programa le avisó al sistema que aceptará conexiones en el puerto TCP 3000, ese socket está escuchando. Un escaneo pregunta, para cada puerto, qué pasa cuando llega una sonda.
Nmap informa uno de varios estados. Los tres que más vas a ver son:
Estos estados describen la sonda, no el riesgo. Un puerto cerrado puede causarte problemas si un servicio del que dependes está caído. Un puerto filtrado puede ser un firewall haciendo su trabajo. Mantén el estado separado de lo que significa.
Nmap tiene varios tipos de escaneo. Dos de ellos importan para quien empieza.
Un escaneo connect le pide al sistema operativo que abra una conexión TCP completa a cada puerto. El sistema hace el handshake normal de tres pasos. Si la conexión funciona, el puerto está abierto, y Nmap la cierra. La guía de Nmap describe el connect como el predeterminado cuando el escaneo SYN no está disponible, porque no necesita privilegios para enviar paquetes sin procesar. Nmap usa la llamada connect del propio sistema en lugar de construir paquetes por su cuenta.
El costo es la visibilidad. Una conexión completa aparece en los registros del objetivo, lo cual está bien en tu laboratorio y merece pensarse en cualquier red que no es tuya.
Un escaneo SYN envía un paquete SYN, el mismo primer paso que usa una conexión real, y luego lee la respuesta. Un SYN/ACK significa que el puerto está escuchando. Un RST significa que no hay nada escuchando. Nmap no termina el handshake, y por eso a este escaneo se le llama a menudo half-open. La guía dice que el escaneo SYN es el predeterminado cuando Nmap tiene privilegios para enviar paquetes sin procesar, lo que normalmente significa permisos de root o de administrador.
En Windows, revisa en las notas de instalación de Nmap el soporte para paquetes sin procesar antes de depender de -sS. Este laboratorio usa -sT porque funciona sin privilegios elevados y aun así da los estados de puerto que necesitas.
Para quien empieza, la diferencia útil es qué deja cada escaneo. Un escaneo connect completa el handshake y aparece en los registros de ambos lados. Un escaneo SYN se detiene antes de que termine el handshake.
El estado del puerto te dice que algo escucha en el 8000. No te dice qué es ese algo. La opción -sV envía sondas a los puertos abiertos, compara las respuestas con la base de firmas de Nmap y reporta un nombre de servicio y una versión cuando la reconoce.
La intensidad va de 0, que envía las menos sondas, a 9, que prueba todas. Los niveles altos tardan más y generan más tráfico. Por defecto, la detección de versión omite el puerto TCP 9100, un puerto de impresora que puede reaccionar mal a las sondas. Usa la menor intensidad que responda tu pregunta, y ejecuta -sV solo contra sistemas que controlas.
Las cadenas de versión son evidencia, no prueba. Quien administra un servicio puede cambiar su banner, así que un número de versión es una afirmación que hay que contrastar con el propio software.
Nmap puede escribir los resultados en un archivo además de mostrarlos en pantalla. Los formatos que más vas a usar son:
-oN archivo: salida normal, legible para una persona.-oX archivo: XML, para herramientas que procesan resultados.-oG archivo: salida "grepable", una línea por host, para filtros rápidos en la terminal.Usa -oN para notas que vas a leer tú, y -oX cuando otra herramienta vaya a procesar el resultado. Guarda los archivos de escaneo junto a tus notas del laboratorio. Un escaneo de la semana pasada es un registro de lo que era verdad la semana pasada, no de hoy.
Necesitas Docker, Python 3, Nmap y una máquina donde los puertos 3000 y 8000 estén libres en 127.0.0.1. Si todavía no tienes una red de laboratorio, empieza por cómo crear una red Docker aislada para laboratorios. Cada paso de abajo se ejecuta en tu máquina. Los comandos son los del laboratorio. Cuando los ejecuté en mi Windows 11, muestro la salida que vi. Cuando no pude ejecutarlos, lo digo y explico qué buscar.
OWASP Juice Shop es una aplicación web deliberadamente vulnerable, hecha para practicar. Levántala con su puerto ligado solo a loopback:
docker run -d --name juice-local -p 127.0.0.1:3000:3000 bkimminich/juice-shopLa parte 127.0.0.1 importa. Sin ella, Docker publica el puerto en todas las interfaces, y cualquier dispositivo de tu red podría alcanzar una aplicación pensada solo para practicar.
Si el nombre ya está en uso, Docker se detiene con un error de conflicto. No borres ese contenedor hasta saber quién lo creó. Inspecciónalo primero:
docker inspect juice-local --format 'image={{.Config.Image}} ports={{json .NetworkSettings.Ports}} status={{.State.Status}}'Lo que observé en mi máquina:
image=bkimminich/juice-shop ports={"3000/tcp":[{"HostIp":"127.0.0.1","HostPort":"3000"}]} status=runningLevanté uno nuevo para esta ejecución y confirmé el mapeo con docker port juice-local, que mostró 3000/tcp -> 127.0.0.1:3000. Docker ya tenía la imagen en caché, así que no se descargó nada. Dale unos segundos a la aplicación para arrancar antes de abrirla en el navegador.
python3 -m http.server 8000 --bind 127.0.0.1 &En Windows, python3 puede no existir. En mi máquina no estaba en el PATH, así que ejecuté Python 3.12 con la ruta completa de instalación y los mismos argumentos. El & deja el servidor corriendo en segundo plano del shell actual. Pruébalo desde otra terminal:
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8000/index.txtEl archivo que pedí existía en la carpeta desde donde inicié el servidor, y la prueba devolvió 200. El log del servidor registró la solicitud:
127.0.0.1 - - [08/Nov/2026 06:20:25] "GET /index.txt HTTP/1.1" 200 -Antes de escanear, pregúntale al sistema operativo. Esta lista es tu referencia, y no depende de Nmap.
En Linux:
ss -tlnpEn Windows, en PowerShell:
Get-NetTCPConnection -State ListenEn mi máquina ejecuté una versión que además muestra el proceso dueño:
Get-NetTCPConnection -State Listen | Where-Object { $_.LocalPort -lt 10000 } | Sort-Object LocalPort | ForEach-Object { $p = Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue; '{0,-15} {1,6} {2,8} {3}' -f $_.LocalAddress, $_.LocalPort, $_.OwningProcess, $p.ProcessName }La salida en mi máquina, limitada a los puertos menores de 10000:
:: 135 2204 svchost
0.0.0.0 135 2204 svchost
192.168.0.100 139 4 System
172.23.112.1 139 4 System
:: 445 4 System
0.0.0.0 515 6084 svchost
:: 515 6084 svchost
127.0.0.1 1026 23620 com.docker.backend
127.0.0.1 3000 23620 com.docker.backend
:: 3311 11308 node
127.0.0.1 5000 43252 python
0.0.0.0 5040 10556 svchost
:: 7680 4604 svchost
127.0.0.1 8000 49736 python
127.0.0.1 8001 7976 python
127.0.0.1 8026 23620 com.docker.backendCuenta las líneas. Muchos de esos puertos pertenecen al propio Windows, no a algo que tú iniciaste. Es normal, y justamente por eso un inventario tiene que nombrar al dueño de cada puerto.
nmap -sT -p 1-10000 127.0.0.1No ejecuté este comando. Nmap no está instalado en la máquina que usé, y no lo instalé. Qué buscar cuando lo ejecutes: una tabla PORT STATE SERVICE. Cada línea marcada como open debe coincidir con una fila del paso 3. En este laboratorio, 3000/tcp y 8000/tcp deberían aparecer como abiertos. Nmap suele resumir los puertos cerrados en una sola línea, así que las líneas que hay que leer son las abiertas.
Como sustituto, escribí una verificación corta en loopback con la biblioteca estándar de Python. Abre una conexión TCP a cada puerto del 1 al 10000 en 127.0.0.1 e informa cuáles aceptan. Hace el mismo handshake que hace un escaneo connect, pero no es Nmap:
import socket
from concurrent.futures import ThreadPoolExecutor
HOST = "127.0.0.1"
def is_open(port: int) -> bool:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(0.3)
return s.connect_ex((HOST, port)) == 0
if __name__ == "__main__":
with ThreadPoolExecutor(max_workers=200) as ex:
results = list(ex.map(is_open, range(1, 10001)))
open_ports = [p for p, ok in zip(range(1, 10001), results) if ok]
print(f"open on {HOST} in 1-10000: {open_ports}")Salida en mi máquina:
open on 127.0.0.1 in 1-10000: [135, 445, 515, 1026, 3000, 3311, 5000, 5040, 7680, 8000, 8001, 8026]Cada puerto de esa lista también aparece en la tabla de listeners del paso 3. Las dos fuentes coinciden, y esa es la verificación que quieres antes de confiar en cualquiera de las dos.
nmap -sV -p 3000,8000 127.0.0.1 -oN localhost-scan.txtNo lo ejecuté aquí, por el mismo motivo que en el paso 4. Qué buscar: una columna VERSION junto a 3000 y 8000, y un archivo llamado localhost-scan.txt en la carpeta actual. El texto de versión que Nmap muestra para el puerto 3000 es una afirmación que hay que verificar. Abre la aplicación en el navegador o lee la documentación del propio software antes de anotar la versión en cualquier lugar.
Este paso convierte un escaneo en un inventario. Para cada puerto abierto necesitas el proceso que lo posee. En Linux, ss -tlnp muestra el nombre del proceso y el PID en la última columna. En Windows, toma el PID de OwningProcess y búscalo:
Get-Process -Id 23620 | Select-Object Id, ProcessNameHice eso para los puertos de la lista. Así resultaron ser los dueños en mi máquina:
| Puerto | Escuchando en | PID | Dueño | Qué es |
|---|---|---|---|---|
| 3000 | 127.0.0.1 | 23620 | com.docker.backend | Proxy de Docker Desktop para el contenedor juice-local, confirmado con docker port juice-local |
| 8000 | 127.0.0.1 | 49736 | python | El http.server del paso 2 |
| 3311 | todas las interfaces (::) |
11308 | node | Un proceso Node.js; tasklist /svc no muestra ningún servicio para él, así que es un programa que alguien inició |
| 515 | todas las interfaces | 6084 | svchost | El servicio de impresión LPD de Windows; tasklist /svc /fi "PID eq 6084" muestra LPDSVC |
Dos filas piden una decisión, y el escaneo por sí solo no puede tomarla. El proceso Node.js del 3311 escucha en todas las interfaces, así que, si es un servidor de desarrollo para trabajo local, otros dispositivos pueden alcanzarlo. El servicio LPD del 515 también escucha en todas las interfaces. Decidir si alguno de los dos debe seguir corriendo es tu decisión, y la corrección le corresponde al dueño del proceso, no al escáner. No detengas un servicio solo porque aparece en una lista.
La fila de Docker necesita una segunda verificación. El proceso de backend reenvía el puerto, así que el PID por sí solo no dice qué contenedor hay detrás. docker port juice-local dio el mapeo que esperaba:
3000/tcp -> 127.0.0.1:3000Los PID cambian. El servidor de Python tenía el PID 49668 en una lista anterior en esta máquina. Después de reiniciarlo para esta ejecución, la misma línea de comandos ocupó el puerto 8000 con el PID 49736. Lee el PID justo antes de actuar, y confirma la línea de comandos además del nombre.
docker rm -f juice-local
kill %1Ejecuta el primer comando solo en un contenedor que hayas creado para este laboratorio. kill %1 solo funciona en el shell que inició el job; desde otro shell, busca el PID como en el paso 6, revisa su línea de comandos y luego detenlo.
Escanear una dirección que no es tuya. Un rango privado como 192.168.x.x puede pertenecer a un router o a un dispositivo que administra otra persona. Escanea solo lo que tienes permiso escrito para escanear.
Leer "open" como "vulnerable". Un puerto abierto es un hecho sobre un listener. Solo se vuelve un hallazgo cuando sabes qué servicio es, por qué es alcanzable y si debería serlo.
Olvidar el -p. Sin un rango de puertos, Nmap escanea los 1.000 puertos más comunes de cada protocolo. El laboratorio usa -p 1-10000 a propósito, porque un servicio en un puerto poco común es justo lo que un inventario debe detectar.
Publicar sin la dirección. -p 3000:3000 publica en todas las interfaces. Mantén 127.0.0.1: delante cuando la aplicación sea solo para ti.
Confiar en una cadena de versión. -sV lee lo que el servicio dice de sí mismo. Verifica la versión contra el software antes de depender de ella.
Quedarse en el escaneo. El escaneo te da números de puerto. Encontrar el dueño de cada puerto es la parte que todavía tienes que hacer.
Anota los puertos que esperas antes de escanear y compáralos después. Es la forma más rápida de notar algo que no sabías que estaba corriendo.
Escanea dos veces: una con el servidor de Python corriendo y otra después de detenerlo. Guarda ambos archivos con -oN y compáralos. La diferencia es lo que cambiaste.
Lee en la guía de Nmap las secciones sobre -oX y -Pn. Cuando conozcas los formatos de salida, puedes llevar los resultados a un script y seguir sus cambios en el tiempo, siempre solo en tus propias máquinas.
El siguiente artículo de la serie pasa de los puertos a la capa web, con OWASP ZAP: primeros pasos contra Juice Shop ejecutado contra el mismo contenedor.
Herramientas de seguridad
Ejecuta el escaneo pasivo de ZAP contra Juice Shop en tu máquina, lee el informe y verifica una alerta a mano antes de confiar en ella.