User Tools

Site Tools


secres:https-interception

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
secres:https-interception [2017/11/24 15:04] – [Interception HTTPS] orelsecres:https-interception [2024/03/18 15:06] (current) – external edit 127.0.0.1
Line 3: Line 3:
 Nous allons mettre en oeuvre le mécanisme d'interception HTTPS, qui consiste à faire in Man-in-the-Middle pour déchiffre le traffic HTTPS entre le client et le serveur ! Nous allons mettre en oeuvre le mécanisme d'interception HTTPS, qui consiste à faire in Man-in-the-Middle pour déchiffre le traffic HTTPS entre le client et le serveur !
  
-Le code et la documentation du projet sont ici : https://gitlab.inria.fr/esnard/https-interception 
  
 +Considérons le réseau suivant :
  
-=== Démo === 
  
-Considérons le réseau suivant :+  Client Web <-----> Proxy <--- (...) --> Server Web (https://nile.metal.fr)  
  
  
-  Client Web <-----> Proxy <--- (...) --> Server Web (https://nile.metal.fr)+=== Proxy SSL ===
  
-  +Voici le code de notre proxy SSL :
  
 <code python sslproxy.py> <code python sslproxy.py>
Line 20: Line 19:
 import ssl import ssl
 import sys import sys
-import OpenSSL 
 import time import time
 import datetime import datetime
Line 127: Line 125:
 main() main()
 </code> </code>
 +
 +=== Génération des faux certificats ===
 +
 +Commençons par générer un //fake CA// : 
 +
 +  $ certtool --generate-privkey --outfile fake-ca-key.pem
 +  $ certtool --generate-self-signed --load-privkey fake-ca-key.pem --outfile fake-ca-cert.pem
 +
 +Voici les réponses à donner strictement :
 +
 +  * La plupart des champs peuvent rester vides.
 +  * Common name: FAKECA
 +  * The certificate will expire in (days): 255  
 +  * Does the certificate belong to an authority? (y/N): y
 +  * Will the certificate be used to sign other certificates? (y/N): y
 +  * CRL signing: y
 +  * All other extensions: NO (required)
 +
 +Pour afficher le contenu de son certificat :
 +
 +  $ certtool --infile fake-ca-cert.pem -i
 +
 +Générons maintenant le //fake// certifcat de notre serveur. 
 +
 +   $ certtool --generate-privkey --outfile fake-server-key.pem
 +   $ certtool --generate-certificate --load-privkey fake-server-key.pem --outfile fake-server-cert.pem --load-ca-certificate fake-ca-cert.pem --load-ca-privkey fake-ca-key.pem
 +
 +Voici les réponses à donner strictement :
 +
 +  * La plupart des champs peuvent rester vides
 +  * CN=nile.metal.fr
 +  * DNSName=nile.metal.fr
 +  * IP address=10.0.0.2
 +  * The certificate will expire in (days): 255
 +  * Will the certificate be used for signing (required for TLS)? (y/N): y
 +  * Will the certificate be used for encryption (not required for TLS)? (y/N): y
 +
 +Vous pouvez également utiliser le script suivant pour générer automatiquent le //fake// certificat pour le serveur nile.metal.fr :
 +
 +  ./gen-fake-cert.py nile.metal.fr 443
 +
 +<code python gen-fake-cert.py>  
 +#!/usr/bin/python3
 +import socket
 +import ssl
 +import sys
 +import pprint
 +import OpenSSL  # deprecated ?
 +import time
 +import datetime
 +import os
 +import struct
 +
 +# this certificate must be trusted by the client victim!
 +FAKE_CA_CERT = "fake-ca-cert.pem"          
 +FAKE_CA_KEY = "fake-ca-key.pem"
 +
 +# a fake certificate for the server that is a copy of the actual certificate except it is signed by our fake CA
 +FAKE_SERVER_CERT = "fake-server-cert.pem"
 +FAKE_SERVER_KEY = "fake-server-key.pem"
 +
 +######### MISC #########
 +
 +def log_message(format, *args):
 +    sys.stderr.write("[%s] %s\n" % (datetime.datetime.now().strftime("%y-%m-%d %H:%M:%S"), format%args))
 +
 +######### Certificate Tools #########
 +
 +# cert input are assuming to be x509
 +
 +# save x509 cert file (PEM format)
 +def save_cert(cert, path):
 +    certfile = open(path, "wb")
 +    certfile.write(OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, cert))
 +    certfile.close()
 +
 +# save private key file (PEM format)
 +def save_key(key, path):
 +    keyfile = open(path, "wb")
 +    keyfile.write(OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, key))
 +    keyfile.close()
 +
 +def load_cert(path):
 +    certfile = open(path, 'rt')
 +    cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, certfile.read())
 +    certfile.close()
 +    return cert
 +
 +def load_key(path):
 +    keyfile = open(path, 'rt')
 +    key = OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, keyfile.read())
 +    keyfile.close()
 +    return key
 +
 +######### Generate Fake Certificate #########
 +
 +def generate_fake_cert(cert, cacert, cakey):
 +
 +    # get CN & SAN from x509 cert
 +    cn = cert.get_subject().CN
 +    ext = None
 +    for idx in range(cert.get_extension_count()):
 +        ext = cert.get_extension(idx)
 +        if(ext.get_short_name() == b'subjectAltName'): break
 +    # if DEBUG: print("  * SAN = ", ext.get_data()) # in raw format (one should decode it...)
 +
 +    # create a key pair
 +    fakekey = OpenSSL.crypto.PKey()
 +    fakekey.generate_key(OpenSSL.crypto.TYPE_RSA, 1024)
 +
 +    # create a new x509 cert
 +    fakecert = OpenSSL.crypto.X509()  # x509 format
 +    fakecert.get_subject().CN = cn
 +    fakecert.set_serial_number(int(time.time()))
 +    fakecert.gmtime_adj_notBefore( 0 )             # not valid before today
 +    fakecert.gmtime_adj_notAfter( 60*60*24*365*5 ) # not valid after 5 years
 +    fakecert.set_pubkey(fakekey)
 +    fakecert.set_version(0x2) # set certificate version to X509 v3 (0x2), required for X509 extensions
 +
 +    # add subjectAltName X509 extension (SAN)
 +    if ext: fakecert.add_extensions([ext])
 +
 +    # set issuer and CA signature
 +    fakecert.set_issuer(cacert.get_subject())
 +    fakecert.sign(cakey, 'sha1')
 +    fakecert.sign(cakey, 'sha256')
 +
 +    return (fakecert, fakekey)
 +
 +
 +######### Main Program  #########
 +
 +if len(sys.argv) != 3:
 +    sys.stderr.write("usage: sslproxy <server hostname> <server port>\n")
 +    sys.exit(1)
 +
 +SERVERHOST = sys.argv[1]
 +SERVERPORT = int(sys.argv[2])
 +serveraddr = (SERVERHOST, SERVERPORT) # the target server
 +
 +# load CA cert & CA key (x509)
 +fakecacert = load_cert(FAKE_CA_CERT)
 +fakecakey = load_key(FAKE_CA_KEY)
 +
 +sslservercert = ssl.get_server_certificate(serveraddr)
 +servercert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, sslservercert)
 +servercn = servercert.get_subject().CN
 +log_message('Get certificate: %s', servercn)
 +
 +fakeservercert, fakeserverkey = generate_fake_cert(servercert, fakecacert, fakecakey)
 +save_cert(fakeservercert, FAKE_SERVER_CERT)
 +save_key(fakeserverkey, FAKE_SERVER_KEY)
 +log_message('Save fake server certificate %s and key %s', FAKE_SERVER_CERT, FAKE_SERVER_KEY)
 +</code>
 +  
 +
 +=== Lancement du Proxy HTTPS ===
  
 Lancement du proxy : Lancement du proxy :
Line 134: Line 289:
   ./sslproxy.py nile.metal.fr 443 4444   ./sslproxy.py nile.metal.fr 443 4444
  
 +=== Mise en oeuvre avec un client ===
  
-Lancement du client :+Sur le client :
  
-  wget https://nile.metal.fr+  wget -4 --ca-certificate=fake-ca-cert.pem https://nile.metal.fr 
 + 
 +Pour ajouter le //fake// CA dans le store du client, il faut faire : 
 + 
 +  cp ca-cert.pem ca-cert.crt # renommage 
 +  cp ca-cert.crt /usr/share/ca-certificates/mycert/ 
 +  dpkg-reconfigure ca-certificates 
 +   
 +Puis, il suffit de faire : 
 +   
 +  wget -4 https://nile.metal.fr
      
 +
 +Video de démo par A. Guermouche : https://www.youtube.com/watch?v=KURaBFMn4xg
  
 ==== Documentation ==== ==== Documentation ====
 +
 +Le code et la documentation du projet (version antérieure) sont ici : https://gitlab.inria.fr/esnard/https-interception 
  
 About HTTPS interception: About HTTPS interception:
secres/https-interception.1511535888.txt.gz · Last modified: 2024/03/18 15:05 (external edit)