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 > Suite de la découverte de 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
|>|Suite de la découverte de la libnids  

par Frédéric Lavécot (06/09/2001)



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

Cette brève propose d'explorer quelques-unes des possibilités de la 
libnids qui n'ont pas été abordées dans le précédent article :

Nous allons voire : 

- void nids_killtcp(struct tcp_stream * a_tcp) 
  une fonction qui permet de tuer une session tcp.

- les paramètres qui permettent de configurer la journalisation des 
informations via le démon syslogd et la détection de scans de ports.

--[ nids_killtcp() ]--------------------------------------------------------

Permet de mettre fin à une session TCP. 

Exemple : pour éviter qu'un pirate puisse utiliser une backdoor qu'il
a installé sur une machine, nous allons tuer toutes les connexions qui ne 
correspondent pas aux services attendu.
Attention ce programme ne détecte pas les communications dans les canaux 
cachés mais juste les connexions qui ne correspondent pas à un service 
habituel.
(Oui je sais, c'est le rôle du filtrage d'empêcher de telles connexions mais 
c'est juste un exemple d'accord ?)

Exemple : prenons le cas d'un serveur web (port 80) et qui est administré 
par ssh (port 22).
Nous allons surveiller toutes les connexions sur un port différent de 80 ou 22
et terminer ces éventuelles connexions grâce à tcpkill.

La fonction tcpkill utilise la libnet pour envoyer un paquet RST au serveur
et au client tuant ainsi la connexion des deux côtés. 
La libnet est une bibliothèque qui permet de générer facilement des paquets 
sans se soucier de la plate-forme sur laquelle on dévellope. 

--[ code ]-- 

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define __BSD_SOURCE
#define __FAVOR_BSD
#include <netinet/in_systm.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <syslog.h>
#include <stdlib.h>
#include <varargs.h>
#include <arpa/inet.h>

#include "nids.h"


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

char rule[1024];
char host[16];
int i_port[255]; /* 255 services ouvert ca devrait être suffisant non ? :) */
int k;

/* Houlala comment y'a trop de variables globales dans ce programme */
/* Moi a ta place j'aurais trop honte                               */

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

int check_rule(struct tcp_stream *a_tcp);
/* Fonction de call-back de la libnids */

void read_rule(void);
/* Vérifier la règle spécifiée en entrée */

void usage(char *p);

int
main (int argc, char **argv)
{
  
  if(argc==3)
    {
      if(strncmp(argv[1],"-h",2)==0)
	{
	  usage(argv[0]);
	  return 0;
	}
      else
	if(strncmp(argv[1],"-r",2)==0)
	  {
	    strncpy(rule,argv[2],1023);
	    rule[1023]='\0';
	  }
	else
	   {
	     usage(argv[0]);
	     return 0;
	   }
    }
  else
    {
      usage(argv[0]);
      return 0;
    }


  
  nids_params.scan_num_hosts=0;
  /* Eviter de journaliser les alertes sur les scans de ports */

  read_rule();
  /* Vérifier si la règle spécifiée en entrée est valide */
  
  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];
  int i;
  
  if (a_tcp->nids_state == NIDS_JUST_EST)/* Une nouvelle session vient */
                                         /* d'être établie             */
      {
	i=check_rule(a_tcp); /* Y'a t'il une corrrespondance avec la règle */
	                     /* spécifié en entrée                         */
	if(i==0)
	  {
	    snprintf(buf,108,"WARNING %s : %i established a successful connection to %s on port %i\n",int_ntoa(a_tcp->addr.saddr),a_tcp->addr.source,host,a_tcp->addr.dest); 
	    buf[108]='\0';
	    printf(buf);
	    syslog(LOG_WARNING,buf);

	    nids_killtcp(a_tcp); 

	    return;
      }
  }
  return;
}

int check_rule(struct tcp_stream *a_tcp)
{
  int l=0;

  /* L'adresse doit être la même mais pas le port destination différent */
  if(inet_addr(host)==a_tcp->addr.daddr)
    {
      for(l=0;l<=k;l++)
	{
	  if(a_tcp->addr.dest==i_port[l])
	    return 1;
	}
      /* L'adresse est la même mais le port dest ne correspond */
      /* pas à un service attendu                              */      
      return 0;
    }
  
  return 1;
}

void read_rule(void)
{
  char a_port[6];
  int i=0,j=0;

  k=0;
  
  while(rule[i]!=':')
    {
      if(i==16) 
	{
	  printf("Host address seems to be more than 16 characters / or someone forgot a ':'\n");
	  exit;
	}
      host[i]=rule[i];
      i++;
      host[i]='\0';
    }
  
  i++;
  while(rule[i]!='\0')
    {
      if(rule[i]==',')
	{
	  a_port[j]='\0';
	  j=0;
	  i++;
	  i_port[k]=(int)(strtod(a_port,NULL));
	  k++;
	}
      a_port[j]=rule[i];
      i++;j++;
    }
  a_port[j]='\0';
  j=0;
  i++;
  i_port[k]=(int)(strtod(a_port,NULL));
  k++;
}


void usage(char *p)
{
  printf("Usage: %s [-h] -r\n",p);
  printf("-r : host:p1,p2,p3,...\nWhere host is an address written in the Internet standard '.` notation\nAnd p1,p2,p3 the ports rithfully opened on that machine\nWanring : TCP only for the moment\n");  
}



--[ aperçu ]-- 

# ./nids -r 192.168.1.84:22,80

WARNING 192.168.1.86 : 4708 established a successful connection to 192.168.1.84 on port 443


extrait du syslog :

Apr 30 15:42:26 avalon libnids: WARNING 192.168.1.86 : 4708 established a successful connection to 192.168.1.84 on port 443


Extrait de la connexion ayant servi à générer l'alerte :

$telnet 192.168.1.84 443
Trying 192.168.1.84...
Connected to 192.168.1.84.
Escape character is '^]'.
Connection closed by foreign host.


Le port 443 est ouvert, pas filtré mais inaccessible !


--[ Journalisation au travers de syslog ]-----------------------------------

Par défaut la libnids est paramètré pour surveiller un certains nombres 
d'évènements et informer l'administrateur au travers de la journalisation 
syslog.

Les évènements journalisés sont définis dans char *nids_warnings[] dans le 
fichier libnids.c et sont :

Oversized IP packet 
-> paquet IP surdimensionné : contient plus de données qu'indiqué dans 
l'en-tête

Invalid IP fragment list: fragment over size
-> Paquet IP invalide : fragment contenant plus de données que prévus

Overlapping IP fragments
-> fragments IP qui se recouvrent

Invalid IP header
-> en-tête IP non valide

Source routed IP frame
-> Paquet source routé

Max number of TCP streams reached
-> Le nombre maximum de connexions TCP pouvant être suivit vient d'être atteint

Invalid TCP header
-> en-tête TCP non valide

Too much data in TCP receive queue
-> trop de données dans la file de réception des données TCP

Invalid TCP flags
-> Drapeaux TCP non valides



La libnids peut aussi journaliser le scan de ports. Il est possible de 
paramétrer les alertes grâces aux variables :

- scan_num_hosts : taille de la table de hachage utilisé pour stocker les 
informations sur les scans de ports. Par cette valeur vaut défaut 256. Pour 
annuler le recueil d'informations sur le scan de ports, placer cette valeur à 
0.

- scan_num_ports : nombre de ports scannés depuis la même source déclenchant 
une alerte. Par défaut cette valeur vaut 10.

- scan_delay : délais maximal, en millisecondes, entre le scan de deux ports 
pour que la libnids déclenche une alarme.

Ces variables peuvent être modifiées grâce à l'utilisation de la variable 
globale nids_params. Il s'agit en fait d'une structure comportant beaucoup 
plus de champs (ceux ci étant décrits dans le document API livré avec la 
libnids). 

Attention ces champs doivent être initialisés avant d'appeler les fonctions 
d'initialisation de la libnids (voire exemple dans le programme plus haut).

--[ Conclusion ]------------------------------------------------------------

Pour aller plus loin dans l'expérimentation des possibilités offertes par la
libnids ou même la détection d'intrusion, il existe des incontournables :

dsniff : http://www.monkey.org/~dugsong/dsniff/
Redoutable !

scanlogd : http://www.openwall.com/scanlogd/
Programme de détection de scans TCP. Exemple de programme utilisant libnids,
ainsi que libpcap et les raw socket Linux



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