NOPE LinkedIn

Catégories:
Docker

Utiliser TcpDump avec Docker

A partir de Docker

Construction de l’image Docker

Construction de l’image Docker en utilisant le Here Document

docker build -t tcpdump - <<EOF 
FROM ubuntu 
RUN apt-get update && apt-get install -y tcpdump 
CMD tcpdump -i eth0 
EOF

Ce qui nous créé une images avec la commane tcpdump

# docker images
REPOSITORY                           TAG             IMAGE ID       CREATED         SIZE
tcpdump                              latest          9cc11b561802   7 seconds ago   123MB

Utilisation de l’image Tcpdump

L’idée est de pouvoir analyser la communication entre plusieurs containers, par exemple le traffic entre les gateways wireguard. Il est possible de lancer un container qui s’accroche au réseau d’un autre container avec l’option --network=container:<container_name>

# docker ps
1CONTAINER ID   IMAGE                                       COMMAND            CREATED          STATUS          PORTS     NAMES
254343975be23   masipcat/wireguard-go:latest                "/entrypoint.sh"   15 minutes ago   Up 15 minutes             GW_CL1
3b9d22ebbc6c2   masipcat/wireguard-go:latest                "/entrypoint.sh"   15 minutes ago   Up 15 minutes             GW_CL2
407f1e4236644   lscr.io/linuxserver/openssh-server:latest   "/init"            15 minutes ago   Up 15 minutes             server_1
589958c26c546   lscr.io/linuxserver/openssh-server:latest   "/init"            15 minutes ago   Up 15 minutes             server_3
65ddec96e70aa   masipcat/wireguard-go:latest                "/entrypoint.sh"   15 minutes ago   Up 15 minutes             GW_PRES
70c91a8bf2fea   lscr.io/linuxserver/openssh-server:latest   "/init"            15 minutes ago   Up 15 minutes             server_2

On lance le container TCPDUMP sur le réseau cible

docker run --tty --rm --net=container:GW_PRES tcpdump

On obtient ceci:

tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
18:37:31.969196 IP GW_PRES.51820 > GW_CL1.ext_net.51820: UDP, length 32
18:37:32.634443 IP GW_CL2.ext_net.51820 > GW_PRES.51820: UDP, length 32
18:37:36.969316 IP GW_PRES.51820 > GW_CL1.ext_net.51820: UDP, length 32
18:37:36.969439 IP GW_CL1.ext_net.51820 > GW_PRES.51820: UDP, length 32
18:37:37.634630 IP GW_CL2.ext_net.51820 > GW_PRES.51820: UDP, length 32
18:37:41.969612 IP GW_PRES.51820 > GW_CL1.ext_net.51820: UDP, length 32
18:37:41.969626 IP GW_CL1.ext_net.51820 > GW_PRES.51820: UDP, length 32
18:37:41.992623 ARP, Request who-has GW_CL1.ext_net tell GW_PRES, length 28
18:37:41.992922 ARP, Request who-has GW_PRES tell GW_CL1.ext_net, length 28
18:37:41.992926 ARP, Reply GW_PRES is-at 02:42:0a:0a:00:05 (oui Unknown), length 28
18:37:41.992932 ARP, Reply GW_CL1.ext_net is-at 02:42:0a:14:00:05 (oui Unknown), length 28
18:37:42.634807 IP GW_PRES.51820 > GW_CL2.ext_net.51820: UDP, length 32
18:37:42.634824 IP GW_CL2.ext_net.51820 > GW_PRES.51820: UDP, length 32

On voit que la commande attachée à notre container espion sur l’interface eth0 de notre container GW_PRES

# docker exec -it GW_PRES ifconfig -a

On voit s’aperçoit que notre container possède plusieurs interfaces réseaux

eth0      Link encap:Ethernet  HWaddr 02:42:0A:0A:00:05
          inet addr:10.10.0.5  Bcast:10.255.255.255  Mask:255.0.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:1231 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1246 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:86390 (84.3 KiB)  TX bytes:87484 (85.4 KiB)

eth1      Link encap:Ethernet  HWaddr 02:42:C0:A8:0A:01
          inet addr:192.168.10.1  Bcast:192.168.10.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:17 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:1318 (1.2 KiB)  TX bytes:0 (0.0 B)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:4 errors:0 dropped:0 overruns:0 frame:0
          TX packets:4 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1
          RX bytes:372 (372.0 B)  TX bytes:372 (372.0 B)

wg0       Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
          inet addr:10.10.0.5  P-t-P:10.10.0.5  Mask:255.255.255.255
          UP POINTOPOINT RUNNING NOARP MULTICAST  MTU:1420  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:500
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

On veut s’avoir ce qui se passe sur le réseau interne de ce container.

# docker run --tty --net=container:GW_PRES tcpdump tcpdump -i eth1
  • Le premier Tcpdump est le nom de l’image docker
  • Le second Tcpdump est la commande a exécuter dans le container en bypassant la commande CMD par défaut avec les options suivantes:
    • -N - N’inclue pas le domaine, ici ipsec_int_h1
    • -i eth1 - utilise l’interface eth1 du container (réseau interne)
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), snapshot length 262144 bytes
19:15:49.540999 IP GW_PRES > server_1: ICMP echo request, id 19712, seq 0, length 64
19:15:49.541042 IP server_1 > GW_PRES: ICMP echo reply, id 19712, seq 0, length 64
19:15:50.541181 IP GW_PRES > server_1: ICMP echo request, id 19712, seq 1, length 64
19:15:50.541209 IP server_1 > GW_PRES: ICMP echo reply, id 19712, seq 1, length 64
19:15:51.541343 IP GW_PRES > server_1: ICMP echo request, id 19712, seq 2, length 64
19:15:51.541372 IP server_1 > GW_PRES: ICMP echo reply, id 19712, seq 2, length 64
19:15:52.541590 IP GW_PRES > server_1: ICMP echo request, id 19712, seq 3, length 64
19:15:52.541620 IP server_1 > GW_PRES: ICMP echo reply, id 19712, seq 3, length 64
19:15:54.724558 ARP, Request who-has server_1 tell GW_PRES, length 28
19:15:54.724574 ARP, Request who-has GW_PRES tell server_1, length 28
19:15:54.724578 ARP, Reply GW_PRES is-at 02:42:c0:a8:0a:01 (oui Unknown), length 28
19:15:54.724583 ARP, Reply server_1 is-at 02:42:c0:a8:0a:64 (oui Unknown), length 28

On peut trés bien décider de regrder ce qui se passe sur l’interface wg0, tunnel ipsec wireguard

docker run --tty --net=container:GW_PRES tcpdump tcpdump -N -i wg0
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on wg0, link-type RAW (Raw IP), snapshot length 262144 bytes
19:17:46.913521 IP GW_PRES > 192.168.20.100: ICMP echo request, id 20224, seq 0, length 64
19:17:47.913906 IP GW_PRES > 192.168.20.100: ICMP echo request, id 20224, seq 1, length 64
19:17:48.914043 IP GW_PRES > 192.168.20.100: ICMP echo request, id 20224, seq 2, length 64
19:17:49.914173 IP GW_PRES > 192.168.20.100: ICMP echo request, id 20224, seq 3, length 64
19:17:50.914309 IP GW_PRES > 192.168.20.100: ICMP echo request, id 20224, seq 4, length 64
19:17:51.914359 IP GW_PRES > 192.168.20.100: ICMP echo request, id 20224, seq 5, length 64
19:17:56.260821 IP GW_PRES > 192.168.30.100: ICMP echo request, id 20480, seq 0, length 64
19:17:57.260964 IP GW_PRES > 192.168.30.100: ICMP echo request, id 20480, seq 1, length 64
19:17:58.261191 IP GW_PRES > 192.168.30.100: ICMP echo request, id 20480, seq 2, length 64
19:17:59.261326 IP GW_PRES > 192.168.30.100: ICMP echo request, id 20480, seq 3, length 64
19:18:00.261391 IP GW_PRES > 192.168.30.100: ICMP echo request, id 20480, seq 4, length 64
19:18:01.261620 IP GW_PRES > 192.168.30.100: ICMP echo request, id 20480, seq 5, length 64

Sur l’hôte docker

# iptables --list -t nat
# Warning: iptables-legacy tables present, use iptables-legacy to see them
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
DOCKER     all  --  anywhere             anywhere             ADDRTYPE match dst-type LOCAL

Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

DOCKER     all  --  anywhere            !127.0.0.0/8          ADDRTYPE match dst-type LOCAL

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  --  10.0.0.0/8           anywhere
MASQUERADE  all  --  172.17.0.0/16        anywhere

Chain DOCKER (2 references)
target     prot opt source               destination
RETURN     all  --  anywhere             anywhere
RETURN     all  --  anywhere             anywhere

A partir du serveur Docker

Utilisation de la commande TCPDUMP sur l’hôte docker

Tout d’abord, on récupére le pid du conteneur qui nous intéresse. On peux soit utiliser son CONTAINER_ID, soit son DOCKER_NAME

docker inspect --format "{{ .State.Pid }}" "$CONTAINER_ID"

On se positionne dans le même espace de noms réseau

nsenter -n -t "$PID"

Il ne reste plus qu’a lancer tcpdump. Pour sortir de l’espace de nom, un ‘Ctrl+d’

Références: