P
'
t
i
t
e
C
h
a
t
t
e
 
spacer~ I LOVE MY GEEK BABYDOLL TEE Articles | Connexion
 
~La libpcap en Java

Précédent  
  Java  
  Suivant
 Présentation

La bibliothèque libpcap est très connue pour ses capacités d'interception des données sur un réseau. Notamment employée par tcpdump, elle se trouve au cour de nombreux outils de surveillance et d'analyse réseau.
 Sommaire


 Introduction

Il existe un certain paradoxe inhérent aux réseaux informatiques : savoir se protéger contre les attaques malveillantes nécessite l'utilisation et la connaissance d'outils pouvant servir à de mauvaises fins. La libcap doit certainement sont succès à cette simple constatation. Les administrateurs peuvent en effet l'exploiter pour créer de nouveaux utilitaires de maintenance et de surveillance tandis que les pirates lui réservent d'autres usages. Néanmoins, tout le monde lutte à armes égales dans ce jeu si répandu de nos jours. Écrite en C, cette bibliothèque se trouve disponible sur de nombreux systèmes, notamment Linux et Windows. Grâce à elle, les développeurs peuvent non seulement intercepter tout le trafic réseau visible par la machine mais également forger et émettre des paquets. Les seules limites connues sont celles de votre imagination. Bien que très simple d'emploi, certains programmeurs lui ont trouvé un grave défaut, à savoir son utilisation réservée au langage C. C'est pourquoi deux projets, tous les deux intitulés jpcap, existent pour apporter la puissance de cette bibliothèque à la plateforme Java. Il est évident que la portabilité et la, relative, simplicité du langage Java en font l'instrument idéal pour la gestion des réseaux. Vous pourrez ainsi dire adieu aux douloureuses compilations croisées et divers soucis liés au portage de vos applications sur différents systèmes d'exploitation. Nos jumelles Java offrent sensiblement les mêmes services et reposent toutes les deux sur libpcap. C'est bien sûr la technologie JNI qui a rendu possible leur implantation. Nous allons nous intéresser à la version de jpcap de Keita Fujii, publiée sous licence GPL. Particulièrement simple et légère, celle-ci possède l'avantage d'autoriser l'émission de paquets IP. La jpcap de SourceForge représente une implantation plus complexe, plus riche et plus active de libpcap. Elle est publiée sous licence Mozilla Public License et n'autorise pas l'émission de paquets. Certains d'entre vous sont peut-être déjà familiers de la notion de capture de paquets ou de trames. Des outils comme tcpdump ou Ethereal rendent de grands services pour la résolution de problèmes de configuration réseau particulièrement épineux. En simplifiant les choses grossièrement, nous pouvons voir une carte réseau comme un garde actif sur un réseau. Son rôle consiste à examiner chaque paquet et à le retirer du trafic s'il est destiné à la machine hôte. Le paquet obtenu est ensuite épluché, on en retire les différentes couches (Ethernet, IP, TCP.) pour faire enfin parvenir les informations qu'il contenait à l'application. Nous ne pouvons pas rentrer dans les détails du modèle ISO et des protocoles réseaux mais nous vous invitons à les découvrir avant de vous lancer dans la réalisation d'applications jpcap importantes. Puisqu'une carte voit passer tous les paquets, donc toute l'information, d'un réseau pour n'en sélectionner que quelques uns, il pourrait être intéressant de tous les examiner, sans perturber le bon fonctionnement de l'ensemble. C'est le rôle du mode "promiscuous" du matériel. Lorsque votre carte se trouve dans ce mode, elle sélectionnera les paquets destinés à votre machine ainsi que tous les autres, sans retirer ses derniers du trafic. Voilà donc comment administrateurs et pirates peuvent mener à bien une grande partie de leurs tâches. Vous l'aurez compris, la libpcap permet d'activer ce fameux mode et de récupérer ainsi toutes les données. Notre premier exemple d'exploitation de jpcap va consister en la réalisation d'un outil de détection de spoofing ARP.


 ARP ? Spoofing ?

L'acronyme ARP signifie Address Resolution Protocol et désigne un protocole d'adressage. Prenons un réseau composé de deux machines appelées Server et Thinthalion et d'un routeur (voir Schéma 1). Leurs adresses IP respectives sont 192.168.1.2, 192.168.1.3 et 192.168.1.1. Lorsque Thinthalion désire s'adresser à Server, tout le problème réside dans l'obtention de l'adresse MAC correspondante. En effet, sur un réseau Ethernet (nous laissons de côté les exotismes tels que Token Ring) les trames sont destinées à des adresses physiques et fixes, les adresses MAC. Pour ce faire, nous utilisons une requête ARP en demandant quelle est l'adresse MAC correspond à l'IP 192.168.1.2. Nous recevons ensuite une réponse ARP donnant cette association. Le listing 1 vous présente un tel dialogue, vu par tcpdump. Le protocole ARP s'avère bien plus complexe mais ces explications seront suffisantes pour comprendre notre programme. Vous trouverez néanmoins la RFC complète sur le CD-Rom accompagnant ce magazine. La technique de spoofing consiste tout simplement à faire passer une machine pour une autre. En effet, dans le cas d'un réseau composé d'un simple hub, toute machine est susceptible d'observer le trafic en exécutant tout simplement tcpdump. Lorsqu'un switch ou un routeur prend la place du hub, les choses se compliquent. Ces derniers ont en effet pour particularité de n'envoyer les paquets qu'à leur(s) seul(s) destinataire(s). La surveillance du réseau devient donc apparemment impossible. La seule solution envisageable serait donc d'exécuter tcpdump sur le routeur. Autrement dit, de faire passer sa propre machine pour le routeur. Voilà à quoi peut servir cette fameuse technique de spoofing ARP que nous allons essayer de détecter pour prévenir une utilisation abusive de notre réseau. Dans notre exemple, Server tourne sous Linux et va mettre en place le spoofing tandis que Thinthalion, sous Windows, essayera de le détecter. L'outil dsniff facilite énormément l'usurpation d'identité réseau. Celui-ci est en effet accompagné de l'application arpspoof qui nous permettra de faire croire à Thinthalion que nous sommes le routeur, et au routeur que nous sommes Thinthalion. Nous devrons bien évidemment activer la redirection de paquets pour que le trafic puisse continuer normalement. Sur la machine "pirate" nous commençons donc par exécuter la commande suivante :

# arpspoof -t 192.168.1.3 192.168.1.1
       
      
JextCopier dans Jext | Jext | Plugin Codegeek


Schéma 1. Configuration du réseau.

La cible marquée par l'option -t va alors recevoir un paquet ARP lui indiquant que notre adresse MAC correspond en fait à l'adresse IP 192.168.1.1. Pour que le dialogue puisse fonctionner nous devons bien évidemment faire l'inverse :

# arpspoof -t 192.168.1.1 192.168.1.3
       
      
JextCopier dans Jext
Dorénavant le routeur pensera que notre adresse MAC correspond à l'adresse IP 192.168.1.3. Il ne nous reste plus qu'à activer le redirection IP et exécuter la commande tcpdump pour examiner le trafic émis et reçu par Thinthalion :

# echo 1 > /proc/sys/net/ipv4/ip_forward
# tcpdump host 192.168.1.3
       
      
JextCopier dans Jext


Schéma 2. La configuration réseau après le spoof.

Comment pouvons-nous détecter une telle usurpation ? Nous devons dans un premier temps mettre en place le spoof puis faire appel à tcpdump (ou lire la RFC très attentivement) pour observer le dialogue ARP généré par la commande arpspoof. Nous pouvons aussi consulter les tables ARP des machines (commande arp sous Linux, arp -a sous Windows) pour afficher les correspondances IP/MAC connues du système. Le listing 2 présente la trace obtenue sur Thinthalion. La troisième ligne correspond à la demande ARP émise par l'hôte Windows pour connaître l'adresse MAC du routeur. Le spoof n'avait alors pas encore été effectué et nous recevons une réponse normale. Nous obtenons ensuite une nouvelle réponse ARP, coïncidant avec le lancement d'arpspoof, et nous constatons que l'adresse MAC du routeur est en fait celle de la machine Linux. Enfin lorsque arpspoof est interrompu, les adresses MAC d'origine sont rétablies ainsi que le prouve la dernière ligne. Notre programme va donc capturer tous les paquets réponses ARP et maintenir sa propre table de correspondances ARP. A chaque fois qu'une réponse ARP sera obtenue, nous pourrons en vérifier la cohérence par rapport aux informations que nous possédons déjà. Ainsi, si nous constatons que l'IP 192.168.1.1 apparaît sous deux adresses MAC différentes, nous pouvons légitimement suspecter un spoofing ARP. Bien évidemment, cette technique de détection n'est pas fiable à 100%, particulièrement dans le cas de réseaux DHCP. Néanmoins, le succès est garanti si l'on ne s'intéresse qu'aux IP des routeurs qui eux ne changent jamais d'adresses IP.


 Le détecteur anti-spoof

La classe utilisée par la capture dans notre programme s'intitule jpcap.Jpcap. L'activation du procédé de capture des données nécessite l'ouverture d'une interface réseau par l'entremise de la méthode openDevice(). Celle-ci nécessite 4 paramètres : le nom de l'interface, la taille maximale à capturer des paquets, l'activation du mode "promiscuous" et le timeout. Le listing 3 vous présente le code utilisé par notre programme ArpSpoofDetection. Nous utilisons une interface réseau arbitraire, la première de la liste retournée par la méthode getDeviceList(). Elle correspond généralement à la carte réseau active mais nous vous invitons à créer un menu de sélection de l'interface pour vos propres programmes. Enfin, il est évident que le mode "promiscuous" doit être activé. La taille des paquets n'a pas d'importance pour les paquets ARP (qui ont une taille fixe en environnement Ethernet/IP fermé). Notez que vous pouvez également ouvrir un fichier "dump" généré par tcpdump ou Ethereal avec openFile(). Le programme fonctionnera de la même manière mais lira les données dans un fichier et non sur le réseau. L'action de capture est initiée par l'invocation de la méthode loopPacket(). Celle-ci a pour particularité d'ignorer le paramètre timeout de openDevice(). Si vous désirez exploiter ce paramètre, vous devrez invoquer processPacket() à la place. L'une et l'autre attendent deux paramètres : le nombre de paquets à capturer (-1 signifie infiniment) et leur récepteur. Ce dernier désigne une implantation de l'interface jpcap.JpcapHandler dont l'unique méthode handlePacket(Packet packet) permet de manipuler les paquets capturés. Ces derniers peuvent être des instances des classes ARPPacket, DatalinkPacket, EthernetPacket, ICMPPacket, IPPacket, TCPPacket et UDPPacket. Le listing 4 montre la méthode utilisée pour vérifier que le paquet reçu est bien une réponse ARP. Nous avons ajouté deux vérifications supplémentaires qui garantissent que nous travaillons bien sur un réseau Ethernet/IP. Et voilà pour le travail de capture. Les quelques lignes de code de handlePacket() permettant la détection du spoof ne sont que de simples tests dans une HashMap que vous n'aurez aucun mal à comprendre. La seule subtilité réside dans l'obtention des représentations sous forme de chaînes de caractères des adresses MAC et IP. Pour la première nous construisons un paquet EthernetPacket fictif tandis que pour la seconde nous faisons appel aux services de la classe jpcap.IPAddress. Le listing 5 contient les quelques lignes de code nécessaires. ArpSpoofDetection filtre les paquets en vérifiant le type d'instance fournie en paramètre. Il s'agit d'une méthode certes très lisible mais peu efficace en termes de performances. La libpcap contient en interne un puissant système de filtrage, également utilisé par tcpdump et Ethereal. Nous pouvons l'utiliser en exécutant la méthode setFilter() de la classe jpcap.Jpcap. Ainsi, nous aurions pu écrire ceci avant le lancement de la capture :

dump.setFilter("arp");
       
      
JextCopier dans Jext | Jext | Plugin Codegeek
Dans ce cas, le test "instanceof" serait inutile. Néanmoins, il se révélerait toujours indispensable de vérifier le type ARP : requête ou réponse. Avant le lancement de l'application, n'oubliez pas de vider la table ARP du système d'exploitation (consultez la documentation de la commande arp) pour le forcer à émettre de nouveau les requêtes ARP. Ainsi, notre programme pourra recevoir les bonnes adresses MAC. Nous savons que cette bibliothèque ne se limite pas à la simple capture des paquets. Nous pouvons en effet en envoyer ou les sauvegarder dans un fichier au format libpcap, compréhensible par sendcap ou Ethereal. L'écriture des paquets reçus dans un fichier nécessite l'utilisation de la classe jpcap.JpcapWriter :

Jpcap dump = Jpcap.openDevice(.);
JpcapWriter writer = new JpcapWriter(dump, "arp.log");
// . capture des paquets
writer.writeDumpFile(packet);
// . fin de l'application
writer.closeDumpFile();
       
      
JextCopier dans Jext
Cette technique permet non seulement d'étudier les paquets plus facilement, que cela soit avec un banal éditeur hexadécimal ou avec le puissant Ethereal, mais également de pouvoir réinjecter ces paquets sur le réseau. Pour ce faire, vous devez initialiser jpcap à partir d'un fichier, puis envoyer chaque paquet capturé sur le réseau :

this.sender = new JpcapSender();
this.sender.openDevice(Jpcap.getDeviceList()[0]);
Jpcap dump = Jpcap.openFile("packets.log");
dump.loopPacket(-1, this);
// . quand on reçoit un paquet
this.sender.sendPacket(packet);
       
      
JextCopier dans Jext
Attention, ceci ne fonctionnera que pour des paquets de type IPPacket (et ses descendants). La possibilité d'injecter des données sur le réseau vous permet de créer des scénarios à partir de captures en direct ou à partir d'outils spécialisés (comme Packet Excalibur qui vous permet de forger graphiquement vos propres paquets). Nous vous conseillons fortement l'utilisation de tels scénarios car vous éviterez ainsi de fastidieuses manipulations. Cet exemple d'utilisation de la bibliothèque jpcap prouve sa simplicité et sa puissance. Toutefois, si quelques lignes de code suffisent pour réaliser votre programme, vous devrez impérativement effectuer de nombreuses observations et bien vous renseigner sur les protocoles réseaux au préalable.


 Listings

Listing 1

02:06:35.314781 arp who-has SERVER tell Thinthalion
02:06:35.314946 arp reply SERVER is-at 0:9:5b:1e:11:c2
       
      
JextCopier dans Jext | Jext | Plugin Codegeek
Listing 2

02:22:46.231005 arp who-has SERVER tell Thinthalion
02:22:46.231277 arp reply SERVER is-at 0:9:5b:1e:11:c2
02:22:46.303802 arp who-has 192.168.1.1 tell Thinthalion
02:22:46.304748 arp reply 192.168.1.1 is-at 0:30:ab:14:31:d5
02:23:12.770276 arp reply 192.168.1.1 is-at 0:9:5b:1e:11:c2
02:23:17.055248 arp reply 192.168.1.1 is-at 0:30:ab:14:31:d5
       
      
JextCopier dans Jext
Listing 3

public void antiSpoof()
{
  System.out.println("Using network interface " + Jpcap.getDeviceList()[0]);
  try
  {
    Jpcap dump = Jpcap.openDevice(Jpcap.getDeviceList()[0], 1024, true, 20);
    dump.loopPacket(-1, this);
  } catch (java.io.IOException ioe) {
    System.err.println("Capture des paquets impossible.");
  }
}
       
      
JextCopier dans Jext
Listing 4

public void handlePacket(Packet packet)
{
  if (packet instanceof ARPPacket)
  {
    ARPPacket arp = (ARPPacket) packet;
    if (arp.operation == ARPPacket.ARP_REPLY &&
        arp.hardtype  == ARPPacket.HARDTYPE_ETHER &&
        arp.prototype == ARPPacket.PROTOTYPE_IP)
    {
      // détection du spoof
    }
  }
}
       
      
JextCopier dans Jext

 Téléchargements

Vous pouvez télécharger l'exemple complet de notre article.



par Romain Guy
romain.guy@jext.org
http://www.jext.org
Dernière mise à jour : 14/10/2006


Précédent  
  Java  
  Suivant

 
#ProgX©2005 Mathieu GINOD - Romain GUY - Erik LOUISE