Mitmproxy

De Wiki doc


Mitmproxy est un mandataire (proxy) destiné au débogage, tests, notamment de pénétrations ainsi qu'aux évaluations des mesures de protections d'un système d'information. Il est extrêmement utile pour comprendre le fonctionnement d'un programme officiant au travers de sessions HTTPS puisqu'il permet de réunir les éléments nécessaires à l'inspection des trames chiffrées par TLS.

Il peut, en outre, servir à espionner la navigation HTTPS des utilisateurs d'un réseau à accès limité (obligeant l'accès au WAN par l'intermédiaire d'un mandataire). À l'issue de la lecture de ce document, vous devriez être sensibilisé à ne jamais réaliser d'opérations personnelles sur ce genre de réseau (connexion à un Webmail ou à tout portail nécessitant un identifiant personnel par exemple).

Cette documentation explique brièvement comment se servir de l'outil pour enregistrer les clés de sessions TLS et présente un cas pratique avec le déchiffrement d'un docker pull. Les trames capturées via Tcpdump pourront alors être examinées par un outil graphique comme Wireshark.

Mise en œuvre

Installation

Installation de l'outil

apt install --no-install-recommends mitmproxy

Le fait de lancer mitmproxy créé automatiquement le répertoire ~/.mitmproxy contenant les éléments secrets utilisés dans une transaction TLS. Il est alors possible d'importer le certificat serveur dans la base local du client à espionner ou générer son propre certificat via OpenSSL.

Afin d'agrémenter la démonstration, la seconde solution sera utilisée. Outre l'aspect didactique, générer votre propre certificat est indispensable lorsque l'interception concerne la communication d'une application exigeante en terme de vérification (ce pourquoi Docker est utilisé en guise d'exemple). Il est en effet nécessaire dans ce cas d'ajouter des noms alternatifs dans la section subjectAltName du certificat X.509 afin de spécifier les adresses signées par celui-ci.

Configuration des clés

Création du répertoire d'accueil des éléments secrets

mkdir -p ~/.mitmproxy/certs

Génération desdits éléments

# Génération de la clé privée de l'autorité de certification (AC)
openssl genrsa -out ~/.mitmproxy/certs/ca.key 2048
# Génération du couple de clés du serveur mandataire
openssl req -new -x509 -days 365 -key ~/.mitmproxy/certs/ca.key -subj "/C=CN/ST=GD/L=SZ/O=Acme, Inc./CN=Acme Root CA" -out ~/.mitmproxy/certs/ca.crt
# Création d'un fichier de demande de certificat auprès de l'AC
openssl req -newkey rsa:2048 -nodes -keyout ~/.mitmproxy/certs/serveur.key -subj "/C=CN/ST=GD/L=SZ/O=Acme, Inc./CN=*" -out ~/.mitmproxy/certs/serveur.csr
# Génération d'un certificat signé par l'AC et intégrant la liste des domaines à certifier
openssl x509 -req -extfile <(printf "subjectAltName=DNS:*.ycharbi.fr,DNS:*.docker.io,DNS:*.cloudflare.docker.com,IP:127.0.0.1") -days 365 -in ~/.mitmproxy/certs/serveur.csr -CA ~/.mitmproxy/certs/ca.crt -CAkey ~/.mitmproxy/certs/ca.key -CAcreateserial -out ~/.mitmproxy/certs/serveur.crt

# Chaînage du certificat avec la clé associée pour mitmproxy
cat ~/.mitmproxy/certs/serveur.crt ~/.mitmproxy/certs/serveur.key > ~/.mitmproxy/certs/cert.pem

Le point d'intérêt principal de ces opérations et qui devra être personnalisé en fonction du cas à traiter est la sous-commande printf "subjectAltName=DNS:*.ycharbi.fr,DNS:*.docker.io,DNS:*.cloudflare.docker.com,IP:127.0.0.1" présente à la ligne numéro 8. Utilisez les domaines que vous voulez voir validé par TLS lors de la poignée de main entre une application cliente et votre mandataire.

Tests de fonctionnement

Afin de tester notre préparation, nous pouvons lancer mitmproxy de la façon suivante :

SSLKEYLOGFILE="/tmp/clés_tls_mitm.txt" mitmproxy --certs *=~/.mitmproxy/certs/cert.pem

où :

  • SSLKEYLOGFILE=  : emplacement du fichier contenant les clés négociées lors des différentes sessions TLS
  • --certs *=  : emplacement du certificat chaîné serveur pour signer le domaine spécifié dans la commande (ici * pour tout les domaines). Il peut y avoir plusieurs fois ce paramètre pour mettre autant de certificats que de domaines au besoin

Les clients HTTP communs peuvent êtres utilisés pour tester le fonctionnement de la solution

curl --proxy 127.0.0.1:8080 --cacert ~/.mitmproxy/certs/cert.pem https://doc.ycharbi.fr/index.php/Mitmproxy
wget -e https_proxy=127.0.0.1:8080 --ca-certificate ~/.mitmproxy/certs/cert.pem https://doc.ycharbi.fr/index.php/Mitmproxy

L'exploitation du fichier de clés est expliqué dans le cas pratique de la section suivante.

Cas pratique

Comme énoncé en introduction, nous allons utiliser notre outil pour analyser les requêtes effectuées par un docker pull. Cet outil étant particulièrement chiant avec HTTPS (comme la majorité des applications écrites en Golang), la mise en œuvre de notre capture représente un bon exercice.

Pour que cela fonctionne, il faut :

  • un certificat avec les bons domaines renseignés dans le champ subjectAltName (fait dans l'étape préparatoire)
  • ajouter ce certificat dans la configuration du registre d'image Docker dont l'adresse sera remplacée par celle de notre mandataire (la commande de tirage de l'image reste identique)
  • configurer Docker pour utiliser notre mandataire
  • ajouter ce même certificat dans la base interne du système client
  • rafraîchir la configuration de Systemd et relancer le démon Docker

Installation des paquets

Installation de Docker et de Tcpdump

apt install --no-install-recommends docker.io tcpdump

Le premier servira d'application TLS cliente et le second capturera le trafic chiffré. Celui-ci sera par la suite déchiffré par Wireshark à l'aide des clés enregistrées par Mitmproxy pendant la communication.

Configuration de l'environnement

Ajout du certificat du mandataire comme celui d'un registre d'images

mkdir -p /etc/docker/certs.d/127.0.0.1:8080
cp ~/.mitmproxy/certs/serveur.crt /etc/docker/certs.d/127.0.0.1:8080/ca.crt

Configuration du mandataire pour les requêtes au dépôt distant

mkdir -p /etc/systemd/system/docker.service.d
cat << '_EOF_' > /etc/systemd/system/docker.service.d/http-proxy.conf
[Service]
Environment="HTTPS_PROXY=https://127.0.0.1:8080"
_EOF_

Ajout du certificat dans la base interne du système

cp ~/.mitmproxy/certs/serveur.crt /usr/local/share/ca-certificates/
update-ca-certificates

Rechargement de la configuration de Systemd et du démon Docker

systemctl daemon-reload
systemctl restart docker.service

ASTUCE

Il est possible d'afficher les variables d'environnements passées à l'exécutable de Docker par le service Systemd via la commande systemctl show --property=Environment docker afin de valider la bonne prise en compte de notre paramètre. Un docker search alpine vous indiquera rapidement si votre installation est correcte. En cas de fonctionnement, le mandataire affichera la session et la commande renverra son résultat habituel. En cas d'erreur, une indication sur l'origine du problème rencontré par le client sera renvoyée dans la console.

Tests de fonctionnement

Nous aurons besoin de trois consoles pour réaliser les opérations qui vont suivre. Un multiplexeur de terminal comme Tmux peut s'avérer bien utile dans de pareils circonstances. La commande tmux new -A -s toto peut être utilisée pour initier un tel environnement (totalement facultatif).

Première console

Exécuter le mandataire

SSLKEYLOGFILE="/tmp/clés_tls_mitm.txt" mitmproxy --certs *=~/.mitmproxy/certs/cert.pem

Deuxième console

Exécuter l'enregistreur de trames

tcpdump -ni any -w /tmp/tls.pcap port not 22

Troisième console

Tirer une image du registre distant

docker pull alpine

Si tout est bon, votre image a été récupérée par docker, tcpdump a enregistré l'échange chiffré et mitmproxy a journalisé les sessions en plus d'avoir enregistré les clés TLS de celles-ci. Il ne reste plus qu'à quitter les programmes des deux premières consoles pour en envoyer les fichiers de capture et de clés à une machine graphique possédant wireshark pour déchiffrement et analyse.

scp /tmp/tls.pcap /tmp/clés_tls_mitm.txt ycharbi@\[2001:db8::1\]:/tmp/

Sur la machine graphique

Ouvrir le fichier de capture /tmp/tls.pcap avec Wireshark et ajouter le fichier de clés /tmp/clés_tls_mitm.txt dans les paramètres du protocole TLS : <ctrl>+<maj>+<p> > Protocols > TLS > (Pre)-Master-Sercret log filename > Parcourir... > /tmp/clés_tls_mitm.txt > OK.

Les paquets TLS se déchiffrent instantanément, laissant apparaître les paquets HTTP qu'ils masquaient. Vous pouvez ainsi observer les URL que le client Docker requêtes pour récupérer ses images.

Sources