Déchiffrer une session SSL : méthodes et limitations

mars 04, 2007  |   Blog   |     |   Commentaires fermés sur Déchiffrer une session SSL : méthodes et limitations

Tout le monde connait l’analyseur réseau Ethereal et son successeur Wireshark. Une des nouveautés de la version 0.99.5 est le déchiffrement de flux SSL dans certaines conditions.

Cette fonctionnalité est très intéressante car elle permet enfin de pouvoir analyser le trafic SSL à l’aide d’un sniffer que ce soit sur un serveur (la plupart du temps HTTPs mais également LDAPS, POPS, SFTP, etc…) en production ou bien sûr un port de recopie d’un flux (grâce à la fonction de mirroring d’un switch ou bien encore l’usage d’un tap physique).

Au niveau du client, il existe d’autres possibilités en utilisant des proxies(tels que l’excellent outil WebScarab de l’OWASP) ou bien du tunneling SSL (avec stunnel par exemple).

Pour être tout à fait exhaustif, l’outil ssldump permettait déjà d’obtenir ce genre d’information, mais en shell. Son intégration à WireShark permet ainsi de suivre aisément et graphiquement les segments TCP, acknowledgements, retransmissions, etc…

Pour mettre en pratique cette fonctionnalité, nous allons déchiffrer le flux HTTPs d’un serveur de test. Tout d’abord créons le matériel crypto.

Nous générons une bi-clé RSA de 1024 bits. Pour rappel, on a « ed= 1 mod (p-1)(q-1) » avec p et q grands nombre premiers choisis aléatoirement . La valeur « pq » est la clef publique et « d » la clef privée. Bien que théoriquement libre, la valeur de « e » choisie par la plupart des implémentations est 3 , 5, 17 ou bien 65537.Notez la valeur de « e » donnée, du calcul RSA avec une passphrase vide :

# openssl genrsa -out server.key 1024
Generating RSA private key, 1024 bit long modulus
.......++++++
.++++++
e is 65537 (0x10001)
# openssl rsa -in server.key -out server.pem

Nous créons maintenant le CSR (Certficate Signing request) :

# openssl req -new -key server.key -out server.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [GB]:FR
State or Province Name (full name) [Berkshire]:Paris
Locality Name (eg, city) [Newbury]:75008
Organization Name (eg, company) [My Company Ltd]:RandCo
Organizational Unit Name (eg, section) []:IT
Common Name (eg, your name or your server's hostname) []:test.randco.fr
Email Address []:

Comme nous sommes dans un environnement de test, nous autosignons ce CSR pour obtenir le certificat :

# openssl x509 -req -in server.csr -signkey server.key -out server.crt
Signature ok
subject=/C=FR/ST=Paris/L=75008/O=RandCo/OU=IT/CN=test.randco.fr
Getting Private key

Nous obtenons ainsi une clé privée server.key et un certificat server.crt.

Configurons ensuite Apache. Nous ajoutons dans httpd.conf ceci:


DocumentRoot /usr/local/apache2/htdocs
ServerName test.randco.fr
SSLEngine on
SSLCertificateFile    /usr/local/apache2/etc/ssl.crt/server.crt
SSLCertificateKeyFile /usr/local/apache2/etc/ssl.key/server.pem

Cependant, SSL n’est pas supportée par la version du binaire httpd actuel :

# httpd -l | egrep -i "(ssl|so)"
mod_so.c

Etant donné que nous utilisons Apache2, nous devons donc juste le recompiler en activant l’option –enable-ssl (contrairement à Apache 1.3 pour lequel le module mod_ssl est distribué à part) :

# ./configure --enable-ssl
# make
# make install
# httpd -l | egrep -i "(ssl|so)"
mod_ssl.c
mod_so.c
# apachectl -k restart

Une fois que le flux HTTPs aura été capturé par Wireshark, regardons comment configurer le déchiffrement dans Wireshark.
Dans le menu Edit > Preferences > Protocols > SSL , remplir les champs comme suit :

  • RSA keys list : les champs séparés par une virgule sont l’adresse IP du server, port TCP, protocole applicatif sous-jacent , chemin vers la clé privée
  • SSL debug file : chemin vers l’indispensable fichier de debug

En appliquant un « SSL follow », on peut suivre la session et récupérer le contenu de la session en clair :

Pour tester à votre tour, voici la clé privée et le fichier de capture de la session HTTPs réalisée avec IE6.

Les limitations de ssldump et de la méthode demeurent cependant :

  • AES n’est supporté que dans la version CVS de ssldump (donc non intégrée à Wireshark)
  • tous les flux chiffrés avec des Cipher Suites mettant en oeuvre un échange de clé du type Diffie-Helmann ou RSA restent évidemment indéchiffrables (ceci en est d’ailleurs le but : ces algorithmes restent toutefois sensibles aux attaques Man in the Middle. C’est d’ailleurs la méthode choisie par Webscarab ou d’autres proxy tels que Spike Proxy ou Burp Proxy. Évidemment, ce genre de manipulation provoque une alerte SSL au niveau du client : « certificat invalide » )) !). La capture précédente était réalisée avec MS IE 6 (à jour de patches), le Cipher Suite négocié était TLS_RSA_WITH_RC4_128_MD5. Si on utilise d’autres outils (notamment Open Source tels que Firefox ou lwp-request, basé sur Perl) des Cipher Suites beaucoup plus forts seront négociés automatiquement :
# lwp-request -des https://localhost
200 OK
Connection: close
Server: Apache/2.0.53 (Unix) mod_ssl/2.0.53 OpenSSL/0.9.7a PHP/4.3.10 mod_perl/2                                   .0.1 Perl/v5.8.6
Content-Length: 2271
Content-Type: text/plain
Client-Peer: 127.0.0.1:443
Client-Response-Num: 1
Client-SSL-Cert-Issuer: /C=FR/ST=Paris/L=75008/O=RandCo/OU=IT/CN=test.randco.fr
Client-SSL-Cert-Subject: /C=FR/ST=Paris/L=75008/O=RandCo/OU=IT/CN=test.randco.fr
 Client-SSL-Cipher: DHE-RSA-AES256-SHA
Client-SSL-Warning: Peer certificate not verified

Ce qui donne via ssldump (version CVS) et le fichier de capture obtenu via :

# tcpdump -n tcp port 443 -i lo -w https2.cap -s 16436 &

(remarquez la taille des paquets à capturer inhabituellement grande : le MTU de l’interface de loopback est de 16436 octets !) :

# ./ssldump -r https2.cap  -k server.key
New TCP connection #1: 127.0.0.1(52260) <-> 127.0.0.1(443)
1 1  0.0004 (0.0004)  C>S SSLv2 compatible client hello
Version 3.1
cipher suites
TLS_DHE_RSA_WITH_AES_256_CBC_SHA
TLS_DHE_DSS_WITH_AES_256_CBC_SHA
TLS_RSA_WITH_AES_256_CBC_SHA
TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA
TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA
TLS_RSA_WITH_3DES_EDE_CBC_SHA
SSL2_CK_3DES
TLS_DHE_RSA_WITH_AES_128_CBC_SHA
TLS_DHE_DSS_WITH_AES_128_CBC_SHA
TLS_RSA_WITH_AES_128_CBC_SHA
SSL2_CK_RC2
TLS_DHE_DSS_WITH_RC4_128_SHA
TLS_RSA_WITH_RC4_128_SHA
TLS_RSA_WITH_RC4_128_MD5
SSL2_CK_RC4
SSL2_CK_RC464
TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA
TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA
TLS_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5
TLS_DHE_RSA_WITH_DES_CBC_SHA
TLS_DHE_DSS_WITH_DES_CBC_SHA
TLS_RSA_WITH_DES_CBC_SHA
SSL2_CK_DES
TLS_DHE_DSS_WITH_RC2_56_CBC_SHA
TLS_RSA_EXPORT1024_WITH_RC4_56_SHA
TLS_RSA_EXPORT1024_WITH_RC4_56_MD5
TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA
TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA
TLS_RSA_EXPORT_WITH_DES40_CBC_SHA
TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5
SSL2_CK_RC2_EXPORT40
TLS_RSA_EXPORT_WITH_RC4_40_MD5
SSL2_CK_RC4_EXPORT40
1 2  0.0205 (0.0201)  S>C  Handshake
ServerHello
Version 3.1
session_id[0]=

cipherSuite         TLS_DHE_RSA_WITH_AES_256_CBC_SHA 
ce qui veut donc dire TLS (SSL v3.1) avec échange de clé Diffie Helman, chiffrement par bloc AES 256 bits et algorithme de hashage SHA
compressionMethod NULL 1 3 0.0205 (0.0000) S>C Handshake Certificate 1 4 0.0205 (0.0000) S>C Handshake ServerKeyExchange 1 5 0.0205 (0.0000) S>C Handshake ServerHelloDone 1 6 0.0531 (0.0325) C>S Handshake ClientKeyExchange DiffieHellmanClientPublicValue[128]= 7d 96 7e c0 16 ff 1b 63 26 4d 5a 1a b6 0e 16 62 e9 8d dd d6 a0 45 07 d2 51 50 61 d9 26 14 3b 3f bd 77 c5 66 ba 99 26 7e dc 52 c5 1c f2 72 2c dc 24 17 1e 58 a8 45 0d 46 3e 42 da 45 ad 1a c2 e2 87 c3 b8 3b 0f cc 12 c6 6b 98 db 25 7f da 37 8d f7 02 06 95 64 54 94 ec 57 eb 82 e3 76 ab 80 2d a6 da a2 d8 b3 51 a8 29 65 9c 35 fb 81 91 6f 91 e7 ab a9 75 f4 55 b1 30 09 97 13 29 fb a0 a6 a4 1 7 0.0531 (0.0000) C>S ChangeCipherSpec 1 8 0.0531 (0.0000) C>S Handshake 1 9 0.0697 (0.0165) S>C ChangeCipherSpec 1 10 0.0697 (0.0000) S>C Handshake 1 11 0.0700 (0.0003) C>S application_data 1 12 0.0700 (0.0000) C>S application_data 1 13 0.0703 (0.0003) S>C application_data 1 14 0.0705 (0.0001) S>C application_data 1 0.0716 (0.0011) C>S TCP FIN 1 15 0.0717 (0.0001) S>C Alert

Pour rappel, la valeur publique de l’échange Diffie Helman est « A = g^a mod p » avec un générateur « g » et un nombre premier « p » fixés suivant le groupe DH sélectionné. Le nombre aléatoire « a » est seul connu de l’extremité qui publie A.
Grâce à la théorie du logarithme discret, on sait qu’ il est impossible (lire : long) connaissant « A », »p » et « g » de déterminer « a ». Or « a » (ou plus exactement « A^b mod p = B^a mod p ») est utilisé pour construire la clé de session qui chiffrera le flux avec l’algorithme de chiffrement sélectionné (stream cipher RC4 ou bien par bloc AES dans les cas de ce présent article).

Ceci explique que ssldump ne puisse obtenir la clé de session uniquement en observant le trafic et en connaissant la clef privée RSA si ce genre de Cipher Suite est utilisé.

Les commentaires sont fermés.