HSC
Cabinet de consultants en sécurité informatique depuis 1989 - Spécialisé sur Unix, Windows, TCP/IP et Internet
Mode texte : accès au contenu de la page
Hervé Schauer Consultants
Vous êtes ici : Accueil > Ressources > Brèves > Introduction à la libnids
Accéder au : Site HSC des formations
Télécharger le catalogue des formations
Recherche :  
English version
   Services   
o Domaines de compétences
o Conseil & Expertise
o Prestations ISO 27001
o Audit & Évaluation
o Tests d'intrusion
o Tests de vulnérabilités (TSAR)
o Analyse Forensique
o Certification ARJEL
o Formations
o E-learning
   Conférences   
o Agenda
o Interventions passées
o Tutoriels
   Ressources   
o Index thématique
o Brèves
o Présentations
o Cours
o Articles
o Outils (téléchargement)
o Veille en vulnérabilité
   Société   
o Hervé Schauer
o Equipe
o Offres d'emploi
o Références
o Historique
o Partenariats
o Associations
   Presse et
 communication
 
 
o Newsletter HSC
o Bulletin juridique HSC
o Revue de presse
o Communiqués de presse
o Publications
   Contacts   
o Coordonnées
o Requêtes particulières
o Accès à nos locaux
o Hôtels proches de nos locaux
|>|Introduction à la libnids  

par Frédéric Lavécot (13/04/2001)



--[ Introduction ]---------------------------------------------------------

La libnids est une bibliothèque qui fournit des fonctionnalités aux systèmes
de détection d'intrusion (IDS : Intrusion Detection System) Réseau. 
Cette bibliothèque écoute le trafic réseau et permet de fournir une 
information pratique et utilisable aux systèmes de détection d'intrusion. 
Elle a été écrite pour émuler le comportement de la pile TCP/IP de 
Linux 2.0.36, certains fichiers provenant de celle-ci.

Les principaux avantages de la libnids (par rapport à la simple écoute du 
trafic d'un réseau) sont qu'elle permet :
a) de réassembler les sessions TCP et de suivre un flux de données UDP
b) de défragmenter les paquets IP

Toutes les informations de cet article viennent de la documentation de 
libnids, des exemples fournis avec la libnids et de l'inspection du code
source de programmes utilisant la libnids comme dsniff.

Les exemples de codes donnés sont des simplifications des exemples existants
dans la documentation de libnids.

Ce document a pour unique objectif de faire découvrir quelques-unes des 
possibilités qu'offre la libnids.

--[ Disclaimer ]-----------------------------------------------------------

Les exemples de programmes donnés sont destinés à montrer comment manipuler 
les structures de la libnids. Ces exemples ont été écrits rapidement et de 
manière simpliste (ce qui explique la qualité plus que limite du code ;-).
 

--[ libnids ]--------------------------------------------------------------

http://www.packetfactory.net/Projects/Libnids (quand ça résout)
http://www.avet.com.pl/libnids/libnids.html

Pour compiler et utiliser la libnids il vous faudra :
- la libpcap : ftp://ftp.ee.lbl.gov/ ou http://www.tcpdump.org/
- la libnet : http://www.packetfactory.net/projects/libnet/

--[ Fonctionnalités de la libnids et exemples ]----------------------------

Les structures et fonctions mises à disposition par la libnids sont 
déclarées dans le fichier nids.h qu'il faudra inclure dans l'application. 
Il faudra aussi lier cette application avec la libnids.

L'interfaçage avec la libnids se fait en spécifiant des fonctions de 
callback et en enregistrant ces fonctions auprès de la libnids.

Dans le cas du suivi d'une connexion TCP, la fonction de callback doit être
du type : void tcp_callback(struct tcp_stream *stream, void ** param)
Pour enregistrer cette fonction on utilise la fonction nids_register_tcp : 
nids_register_tcp (tcp_callback);

Une fonction nids_register_udp existe aussi et dans ce cas le premier 
paramètre de la fonction de callback est du type struct udp_stream *.

Une fonction nids_register_ip (qui permet de recevoir tous les paquets IP
corrects et défragmentés) existe aussi. La fonction de callback ne prend 
qu'un paramètre du type struct ip *.


La structure tuple4 sert à stocker l'adresse du client et du serveur et le 
port source du client et le port contacté sur le serveur. 

La structure tcp_stream permet de stocker les paramètres de connexion (dans
une variable de type tuple4), l'état logique de la connexion (Established,
Data, Closed, Reset) et les informations complémentaires sur la connexion
dans une structure half_stream.  

La structure half_stream stocke les informations qui permettent de décrire 
la connexion du coté client ou du coté serveur (comme les données dans les 
paquets, le nombre d'octets de données, ... ).
C'est notamment grâce à l'information count_new (qui compte le nombre d'octets
de données arrivés) que l'on sait si les données viennent du serveur ou du 
client.


A) Réassemblage d'une session TCP

Une des possibilités de la libnids est de pouvoir suivre les sessions TCP.

En effet, la libnids agissant comme une pile, elle nous permet de ne 
récupérer que les paquets valides (sommes de contrôle correctes) et les 
paquets défragmentés (si ceux-ci ont été fragmentés). 

Cela permet de se décharger de toute la partie gestion des paquets et permet 
de consacrer ses efforts à d'autres tâches.

Exemple 1 : Visualiser l'état des connexions en cours (avec une fois n'est 
pas coutume les commentaires en français)


#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <nids.h>

#define int_ntoa(x)     inet_ntoa(*((struct in_addr *)&x))

void tcp_callback (struct tcp_stream *a_tcp, void ** this_time_not_needed);
/* Fonction de callback pour gérer les sessions TCP*/

int
main ()
{
  if (!nids_init ())/* initialisation des fonctionnalités de la libnids */
    {               /* Quitter s'il y a une erreur                      */
      fprintf(stderr,"%s\n",nids_errbuf);
      exit(1);
    }
  nids_register_tcp (tcp_callback);
  nids_run ();
  return 0;
}

void
tcp_callback (struct tcp_stream *a_tcp, void ** this_time_not_needed)
{
  char buf[1024];

  if(a_tcp->addr.dest==8080)
/* On décide de surveiller le trafic sur le port 8080 */
/* 
   Pour cela le port destination (addr.dest) doit être égal à 8080 
*/

    {
      strcpy(buf,int_ntoa(a_tcp->addr.saddr));  strcat(buf,":");  
      sprintf (buf + strlen (buf), "%i ", a_tcp->addr.source);
      /* Oula la! mais c'est pas très très joli comme code !     */ 
      /* Où est-ce qu'on t'a appris à programmer comme ça ? ;-)  */

      if (a_tcp->nids_state == NIDS_JUST_EST)/* Une nouvelle session vient */
	                                     /* d'être établie             */
	{
	  strcat(buf,"-> ");
          strcat(buf,int_ntoa(a_tcp->addr.daddr));  strcat(buf,":"); 
          sprintf (buf + strlen (buf), "%i ", a_tcp->addr.dest);
	  fprintf (stderr, "%s established\n", buf);
          /* EUARK ! de plus en plus laid! */

	  a_tcp->client.collect++;/* Pour recevoir les autres paquets      */ 
	  a_tcp->server.collect++;/* provenant du client et du serveur,    */
                                  /* il est nécessaire d'incrémenter       */
                                  /* la valeur de ces champs               */
	  return; 
	}
      if (a_tcp->nids_state == NIDS_CLOSE)/* Fin normale d'une session */
	{      
	  strcat(buf,"<-> ");
          strcat(buf,int_ntoa(a_tcp->addr.daddr));  strcat(buf,":"); 
          sprintf (buf + strlen (buf), "%i ", a_tcp->addr.dest);
	  fprintf (stderr, "%s closing\n", buf);
	  return;
	}
      if (a_tcp->nids_state == NIDS_RESET)/* Paquet RST mettant fin */
	{                                 /* à la session           */
	  strcat(buf,"<-> ");
          strcat(buf,int_ntoa(a_tcp->addr.daddr));  strcat(buf,":"); 
          sprintf (buf + strlen (buf), "%i ", a_tcp->addr.dest);
	  fprintf (stderr, "%s reset\n", buf);
	  return;
	}
      
      if (a_tcp->nids_state == NIDS_DATA)/* Paquet de données */
	{
	  /* Des données viennent d'arriver, on veut savoir dans quelle */
          /* direction ces paquets vont.                                */ 
	  struct half_stream *hlf;
	  
	  if (a_tcp->client.count_new)
	    {/*Les données viennent du client */
	      strcat(buf,"<- ");
	      strcat(buf,int_ntoa(a_tcp->addr.daddr));  strcat(buf,":"); 
	      sprintf (buf + strlen (buf), "%i ", a_tcp->addr.dest);
	      hlf = &a_tcp->client; /*Stocker les données du client dans hlf*/
	    }
	  else
	    {
	      strcat(buf,"-> ");
	      strcat(buf,int_ntoa(a_tcp->addr.daddr));  strcat(buf,":"); 
	      sprintf (buf + strlen (buf), "%i ", a_tcp->addr.dest); 
	      hlf = &a_tcp->server;
	    }
	  
	  fprintf (stderr, "%s data %d bytes\n", buf, hlf->count_new);
	  return;
	}
    }
  return ;
}

Il s'agit d'un exemple basique : il reste beaucoup d'éléments dans les 
structures qui n'ont pas été mentionnés (une inspection de nids.h vous 
donnera une idée des autres possibilités). 
Notamment cet exemple ne retourne pas les paquets urgents.
Mais cette série de fonctions et de structures peut très bien être utilisée 
pour repérer des débordements de buffers (en détectant un suite de nop, en 
reconnaissant une signature comme le décodeur du shellcode du hellkit, ...) 
ou pour faire des analyses statistiques sur le trafic observé (taille des 
paquets de commandes et cetera).
 

B) Fragments et paquets erronés 

Pour récupérer tous les paquets IP reçus par la libnids (y compris les 
fragments, les paquets invalides et les paquets d'établissement de connexion),
il faut définir une fonction de callback du type : 
void ip_frag_func(struct ip * a_packet, int len)
et enregistrer cette fonction auprès de la libnids comme suit :
nids_register_ip_frag(ip_frag_func);


C) Compilation

Il faut inclure les bibliothèques : nids, pcap et lnet.
ex : gcc -Wall nids.c -o nids -lnids -lpcap -lnet



D) Conclusion

La libnids offre beaucoup de possibilités dont l'article ne donne qu'un tout 
petit aperçu. Un second article permettra de découvrir quelques-unes de ces 
autres fonctionnalités comme la détection de scans de ports ou la 
journalisation d'informations vers le démon syslogd.




Dernière modification le 30 mars 2006 à 19:22:41 CET - webmaster@hsc.fr
Mentions légales - Informations sur ce serveur - © 1989-2013 Hervé Schauer Consultants