# ============================================================ # lab-net-captura — mirar el trafico y la resolucion de nombres # ------------------------------------------------------------ # Lo usan dos lecciones de la fase 02: # f02-tcpip leer la tabla de sockets y saber que escucha # f02-dns seguir una resolucion completa y ver donde se # puede envenenar # # Topologia (misma regla que el lab-00-base: solo el borde toca # el host, y solo por 127.0.0.1): # # host # └── 127.0.0.1:8091 ──► entrada ──┐ # │ cap_interna (internal: true) # ┌────────────────┼─────────────┬──────────┐ # ▼ ▼ ▼ ▼ # app db cliente sniffer # ▲ │ # └────── comparte el netns de app ────────┘ # # El sniffer NO es un contenedor mas en la red: comparte el # espacio de nombres de red de "app". Un bridge de Linux aprende # direcciones MAC y no reenvia el trafico unicast a los demas # puertos, asi que un tcpdump "al lado" no veria casi nada. Para # ver el trafico de un servicio hay que estar DENTRO de su pila # de red. Esa es tambien la razon por la que un atacante que # quiere capturar necesita antes ejecucion en la maquina. # # docker compose up -d --build levantar # docker compose ps ver que corre # docker compose down -v destruir, volumenes incluidos # ============================================================ name: lab-net-captura networks: # Unica red con salida. Solo la toca "entrada", que es lo que # publica el puerto en el host. cap_borde: driver: bridge # Sin salida a internet. Todo lo que se captura aqui es trafico # que has generado tu. cap_interna: driver: bridge internal: true services: # --- unico punto de entrada ------------------------------- entrada: image: nginx:1.27-alpine container_name: labnetcap-entrada ports: - "127.0.0.1:8091:80" volumes: - ./conf/entrada.conf:/etc/nginx/conf.d/default.conf:ro networks: - cap_borde - cap_interna depends_on: - app restart: unless-stopped # --- aplicacion objetivo ---------------------------------- # Escucha en el puerto 80 de su propia pila de red. Sin # "ports", asi que desde el host no existe. app: image: nginx:1.27-alpine container_name: labnetcap-app volumes: - ./sitio:/usr/share/nginx/html:ro networks: - cap_interna restart: unless-stopped # --- segundo protocolo ------------------------------------ # Postgres esta aqui para que la captura tenga algo que no sea # HTTP: otro puerto, otro protocolo, otra forma de abrir la # conexion. db: image: postgres:16-alpine container_name: labnetcap-db environment: POSTGRES_PASSWORD: laboratorio_local POSTGRES_USER: lab POSTGRES_DB: lab networks: - cap_interna restart: unless-stopped # --- puesto de trabajo ------------------------------------ # Desde aqui se generan las peticiones y las consultas de DNS. cliente: build: ./herramientas image: labnetcap-herramientas container_name: labnetcap-cliente command: ["sleep", "infinity"] networks: - cap_interna restart: unless-stopped # --- observador ------------------------------------------- # network_mode: "service:app" mete este contenedor en la MISMA # pila de red que app. Por eso ve su loopback, sus sockets y # todo su trafico. NET_RAW es lo que permite abrir un socket en # modo promiscuo; sin esa capability tcpdump no arranca. sniffer: build: ./herramientas image: labnetcap-herramientas container_name: labnetcap-sniffer command: ["sleep", "infinity"] cap_add: - NET_ADMIN - NET_RAW network_mode: "service:app" depends_on: - app restart: unless-stopped