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 sur 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 possiblités en utilisant des proxy (tels que l’excellent outil WebScarab de l’OWASP) on 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éeons le matériel crypto :

Nous générons un bi-clé RSA de 1024 bits (notez la valeur de « e »1 , 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 (0×10001)
# openssl rsa -in server.key -out server.pem

Nous créeons 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écuperer 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 Suite mettant en oeuvre un échange de clé du type Diffie-Helmann ou RSA restent évidemment indéchiffrables ( ceci en est d’ailleurs le but2 !). 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 Suite 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 traffic et en connaissant la clef privée RSA si ce genre de Cipher Suite est utilisé.


  1. 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. [back]
  2. 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. Evidement, ce genre de manipulation provoque une alerte SSL au niveau du client : « certificat invalide » [back]

Post to Twitter

About SR

Expert Réseau et Sécurité. Vous pouvez me contacter sur sreytan.(at).randco.fr
This entry was posted in and tagged . Bookmark the permalink.

2 Responses to Déchiffrer une session SSL : méthodes et limitations

  1. Pingback: RandCo » Blog Archive » Certificats SSL Wildcard

  2. SR says:

    Pour exporter en pkcs12 :

    #openssl pkcs12 -export -inkey server.key -in server.crt -out certif.p12 -name « Mon certificat »
    Enter Export Password:
    Verifying – Enter Export Password:
    #

Laisser un commentaire