PATTERN MATCHING ET DETECTION D'INTRUSION


Présentation du problème

Le développement des réseaux et de l'Internet rend les problèmes de sécurité, de confidentialité, de disponibilité et d'intégrité excessivement préoccupants . Il s'avère primordial de pouvoir détecter une tentative d'attaque à distance afin de prendre les dispositions nécessaires . Beaucoup de ces attaques consistent en des utilisations détournées de la suite de protocoles TCP/IP, le "langage universel" des machines communicantes. Des dispositifs tels que les firewalls ( pare-feu ) permettent de limiter la portée de ces attaques mais il existe de multiples façons de contourner ces lignes de défense; sans parler des problèmes de failles logicielles qu'un attaquant avisé pourra exploiter à son avantage. Bien souvent, il est nécessaire d'analyser les fichiers de log produits par les sniffers ( "mouchards" ) pour détecter les attaques . Pour des réseaux à forte fréquentation, cette tâche peut s'avérer extrêmement fastidieuse voire impossible pour un opérateur humain . Cependant, en raison de la structure des attaques sur TCP/IP, il est possible de dégager des "signatures" caractérisant très précisément ces attaques, permettant l'utilisation d'outils de recherche de motifs dans les fichiers de log.

Il faut tout de même être conscient du fait que les outils de recherche de motifs ne peuvent pas être utilisés "tels quels" : en effet, les logs représentent des fichiers de très grande taille et de nombreuses signatures différentes sont envisageables selon ce que l'on veut détecter . Il faut donc pouvoir s'assurer que les outils de recherche sont bien optimisés pour cette tâche en termes d'utilisation des resources telles que la mémoire; voire leur adjoindre des fonctionnalités complémentaires s'ils ne suffisent pas . Enfin, l'efficacité d'un système de détection d'intrusion, de façon générale, dépend de sa configurabilité ( ie possibilité de définir de nouvelles spécifications d'attaques et de les rajouter ), de sa robustesse ( ie sa résistance aux "plantages" ) et de la faible quantité de "faux-positifs" ( fausses alertes ) et de "faux-négatifs" ( attaques non détectées ) qu'il génère .


Etat de l'art

Qu'est ce que la détection d'intrusion ?

D'après la définition mentionnée dans la FAQ IDS, la détection d'intrusion consiste en un processus de découverte et d'analyse de comportement hostile dirigé contre un réseau. Actuellement deux types de systèmes de détection d'intrusion existent et ont des champs d'action complémentaires : les systèmes orientés réseau ( ou Network based Intrusion Detection software, soit NIDS ) et les systèmes orientés poste ( Host based IDS, ou HIDS ) .

Les systèmes orientés poste ont pour rôle de déterminer si un ordinateur donné est en train d'être attaqué ou si celui-ci a déjà été attaqué, résultant en une compromission de la sécurité et de l'intégrité du système . La surveillance après attaque se fait généralement par analyse des fichiers présents sur la machine . Les principaux produits sur le marché considérés comme des HIDS sont Tripwire ( logiciel comparant les sommes de contrôle - checksums - des fichiers sensibles avec les valeurs calculées pour un état "sain" ), les logiciels d'anti-virus, les logs système come syslog ...

Les système orientés réseau s'occupent de surveiller le trafic sur le réseau en confrontant les paquets détectés à un ensemble de signatures ou de règles . Si les règles sont violées ou si une signature s'applique, le NIDS enregistre l'événement comme une attaque . Les principaux produits utilisés par la communauté informatique sont Snort, Real Secure de ISS, et Network Flight Recorder .

Les systèmes de détection d'intrusion comportent des éléments communs ( modèle CIDF, Common Intrusion Detection Framework ):


modèle CIDF et interactions entre composants d'un système de détection d'attaques contre les scripts CGI

Approches comportementales

La détection d'intrusion a pour but de relever un comportement hostile . Il faut donc initialement définir ce qu'on entend par "comportement hostile" . Deux grandes approches existent pour conceptualiser ceci : la détection par anomalie ( anomaly detection ) et la détection par mauvaise utilisation ( misuse detection ) .

Développements actuels en détection d'intrusion

Pour implémenter ces approches, différentes méthodes sont actuellement développées et utilisées :

Pour ce projet, nous avons choisi d'utiliser l'approche par détection de mauvaise utilisation . Ce choix se justifie par le fait que les attaques sur les protocoles TCP/IP sont bien connues et conceptuellement assez simples. La méthode choisie est proche de celle de langage par spécification . Dans l'avenir, il est possible que le projet évolue de façon à se placer en position "hybride", utilisant plusieurs aspects de méthodes différentes .


les attaques sur TCP/IP : généralités

Présentation rapide de TCP/IP

La suite de protocoles Transmission Control Protocol/Internet Protocol tient lieu de standard mondial pour les communications sur les réseaux entre machines . Le modèle sous-jacent est un modèle de communication en couches, présentée de la plus "haute" à la plus "basse" :

(dessin de la structure en couches)
structure en couche : exemple du navigateur web

Dans le cadre de ce projet, nous nous intéresserons donc aux attaques dont le champ d'action ou le médium se trouve dans la couche Transport ou la couche Réseau. Beaucoup d'attaques portent également sur la couche applicative, mais elles sont très différentes de celles décrites ici .

La structure en couches de TCP/IP induit le concept d'encapsulation de paquets : chaque couche de la source est supposée envoyer des données à la couche correspondante de la destination . Ces données se présentent sous la forme de paquets, chacun comprenant les données utiles précédées par un en-tête ( l'en-tête fournit des informations à la couche tandis que les données peuvent être entrées par l'utilisateur, comme une requête HTTP par exemple ) . Or les couches ne peuvent discuter directement, puisqu'elles sont empilées . Ainsi, la couche application de la source doit d'abord passer son paquet à la couche Transport, qui utilisera celui-ci en tant que données utiles et y rajoutera son propre en-tête, et ainsi de suite jusqu'à la couche physique . On obtient une sorte de "poupée russe" qui sera dépilée par la machine faisant office de destination : les informations contenues dans les en-têtes respectifs sont analysées et les données sont passées à la couche supérieure pour traitement ultérieur; d'où la notion d'encapsulation . A priori les informations contenues dans un en-tête d'une couche donnée ne sont pas redondantes avec celle de l'en-tête d'une autre couche, si bien que chaque couche reste indépendante l'une de l'autre . Cette propriété offre des possibilités d'attaques comme nous le verrons par la suite .

TCP/IP comprend trois protocoles principaux : TCP et UDP, qui se situent au niveau de la couche transport; et ICMP ( Internet Control Message Protocol ) qui se situe au niveau IP . UDP est un protocole sans connexion et sans garantie d'arrivée des paquets . Il en résulte une plus grande rapidité mais avec sans garantie que toutes les données arrivent comme prévu. Ce protocole est donc plus adapté aux transmissions à courte distance, comme dans les intranets par exemple . Par opposition, TCP est un protocole orienté connexion, cette connexion établie entre la source et la destination permettant d'assurer que toutes les données ont bien été transmises . La connexion TCP est établie lors du handshake TCP où les machines s'échangent leurs numéros d'acquittement initiaux respectifs . Par la suite, chaque paquet TCP contient ces deux numéros d'acquittement ( et un "flag" Acknowledge ), incrémentés selon la taille des données envoyées, ce qui permet de déterminer exactement où en est le transfert de données : chaque paquet qui n'a pas été "acquitté" est réémis par sa source. TCP assure de cette façon que tous les paquets envoyés sont reçus . ICMP est un protocole de "debugging" des réseaux : il est utilisé par les routeurs pour informer une source d'un problème de communication avec une machine distante, ou bien pour vérifier qu'une machine est atteignable sur le réseau ( le fameux "ping" ) . Le traffic ICMP peut être broadcasté ( ie être destiné à toutes les machines d'un réseau en même temps ), ce qui peut être utilisé dans une optique d'attaque .

les différents types d'attaque

Lorsque l'on crée un outil, on n'a pas forcément conscience que celui-ci peut quelquefois être utilisé à des fins très différentes de celles prévues au départ. Ainsi, de même qu'un marteau sert initialement à enfoncer des clous mais peut également être utilisé pour provoquer des dommages physiques sur une personne, il existe des utilisations détournées de TCP/IP permettant de mener des "attaques" contre des machines ou des réseaux entiers . Nous nous intéresserons ici aux attaques que l'on peut mener via ou sur les couches Transport et IP . Ces attaques sont de trois types:


Descriptions et signatures des principales attaques

La notation s'inspire des expressions régulières ... ainsi {a,b} veut dire "soit a, soit b" et [ a - b] " n'importe quel élément entre a et b". && et || sont respectivement le ET et OU logiques.

Pour les signatures exactes, consulter le fichier signaturs.pl dans le repertoire logre.

Explicitons tout d'abord le format de sortie des " sniffers " ( convention TCPdump ) :

-TCP

Timestamp src.sport > dst.dport : flags data-seqno ack window urgent options

où flags est un sous-ensemble non-vide de FLAG = { S ( SYN ), F ( FIN ), P (PUSH ), R ( RST ) , . ( NOFLAG : pas de flag activé )}

data-seqno est de la forme Start-SN :End-SN( End-SN - Start-SN )

ack Vaut soit ACK ack-num ou est vide (¤). Idem pour urgent : URG ou vide (¤).

La principale option qui nous intéresse est l'option de fragmentation : (frag ID :size@offset{+, ¤}) ( le + indique que le paquet n'est pas complet )

L'en-tête TCP contient des champs "réservés" pour une éventuelle mise à niveau du protocole . Si les bits correspondants sont activés, le sniffeur renvoie un message d'erreur ( le paquet TCP est non valide ) .

-UDP

timestamp src.sport > dst.dport : udp data

-ICMP

timestamp src > dst : icmp : message

Les champs laissés par défaut ou omis peuvent prendre n'importe quelle valeur. On omettra en particulier le champ timestamp pour les attaques ponctuelles.

Attaques ponctuelles

Les attaques dites "ponctuelles" sont celles détectables sans problème sur une seule ligne du fichier de log . La plupart de ces attaques consistent en un seul paquet très particulier ( au sens où il est aisément identifiable ), les autres sont basées sur la répétition ( en vue d'une inondation ) d'un paquet anormal, ce qui rend par conséquent leur détection possible sur un seul paquet. On trouve une bonne description des paquets anormaux les plus communs dans l'article de Karen Frederick.

TCP :

-LAND

L'attaque consiste à envoyer un paquet où la source et la destination sont les mêmes : certains systèmes d'exploitation ne savent pas gérer ce type de paquets et on assiste à un "plantage".

src.sport > src.dport

-BROADCAST TCP

tcp est un protocole orienté connexion, un broadcast n'a pas lieu d'être.

src.sport > [ 0 - 255 ].[ 0 - 255 ].[0 - 255 ].{0,255}.dport

-ATTAQUES SUR PORTS

tentative d'atteindre des ports interdits ou suspects : 0, ports typiques utilisés par les chevaux de troie ... Cette signature est parmi les plus vulnérables ( voir "les limites du modèles" )

src.sport > dst.{0, 31337, ...} ( une liste de ports se trouve ici, une autre est accesible dans le répertoire logre)

- WinNUKE

Cette attaque provoque un écran bleu sur les machines windows : le système ne sait pas gérer les paquets "urgents" destinés au port netBIOS sous certaines conditions.

src.sport > dst.139 : flags data-seqno ack Window URG

- CRAFTED PACKETS

Ces paquets sont construits de toutes pièces, en s'éloignant délibérément des spécifications décrites dans les RFC. Les réactions des OS devant de tels paquets sont donc souvent imprévisibles . Dans le meilleur des cas, ces paquets sont ignorés, sinon ils constituent un outil de choix pour le scanning car il ne sont pas mentionnés dans les logs du système ( seul un sniffer peut les détecter ).

Src.sport > dst.dport : S && Flag data-seqno ack window urg

Où Flag est un sous-ensemble non vide de { F ( FIN ), P (PUSH ), R ( RST ) }

(cas particulier : XMAS PACKETS -> Flag = { F ( FIN ), P (PUSH ), R ( RST ) } et urg = URG et ack = ACK ack-num)

Src.sport > dst.dport : S data-seqno ack window URG

src.spot > dst.dport : . data-seqno ¤ window ¤ ( paquet NULL )

- SYN FRAG

les paquets de synchronisation de connexion ne devraient jamais être fagmentés, vu leur taille . De façon générale, tout paquet fragmenté au niveau de l'en-tête ( size < 20 octets ) est hautement suspect. Il peut s'agir d'un moyen d'échapper aux règles d'accès des firewalls qui ne font pas de reconstruction des paquets en transit : le paquet que voit passer le firewall est destiné à un port autorisé par la liste de contrôle d'accès ( ACL ), mais lorsque la machine de destination reconstruira le paquet, le port originel peut être "chevauché" par les données d'un paquet, et donc être remplacé ( voir attaque "teardrop"). Plus simplement, la fragmentation peut servir à duper les IDS effectuant un simple pattern matching sur les paquets, à la recherche d'une signature donnée . La fragmentation permet ainsi de "diluer" dans la masse l'attaque, ou encore de la "brouiller" et la rendre indétectable par pattern matching simple ( voir l'article de Hoglund pour des exemples )

Src.sport > dst.dport : S data-seqno ack window (frag ID :size@offset{+, ¤})

( placer dessin ici )

- SYN + DATA

Il peut s'agir d'une tentative d'échapper à la détection : il n'est pas prévu dans les RFC que des données circulent lors du handshake. Certains IDS ne s'occupant pas des paquets contenant des données, ces paquets anormaux passent à travers les filtres .

Src.sport > dst.dport : S Start-SN : !Start-SN

(ie End-SN différent de Start-SN)

UDP :

- ECHO-CHARGEN :

Cette attaque revient à établir une boucle infernale faisant converser indéfiniment les ports echo (service renvoyant les caractères qu'on lui présente en entrée) et chargen ( service générateur de caractères aléatoires ). Ce genre de traffic étant hautement inhabituel, l'attaque est détectable avec un seul paquet, même si elle s'apparente à une attaque par flooding donc temporelle .

(Src.7 > dst.19 || src.19 > dst.7 ) : udp

- FRAGGLE-AMPLI

L'attaque fraggle ( de même que l'attaque smurf, voir plus bas ) permet à tout un chacun d'utiliser de grosses ressources pour frapper la victime, sans pour autant les posséder . L'idée sous-jacente est d'envoyer une requête quelconque au nom de la victime auprès d'un réseau choisi qui servira "d'amplificateur" . Ainsi, la victime recevra les réponses (non sollicitées ) d'un réseau entier, ce qui peut représenter un grand nombre de paquets à traiter d'un seul coup, entrainant ainsi un Déni de Service . Bien entendu, les paquets d'initiation de l'attaque étant "maquillés" dès le départ, il est fort improbable que l'attaquant soit retrouvé .

Src.sport > [0- 255].[0 - 255].[0 - 255].{0,255}.{19,7} : udp

Ici src est la victime ... et le réseau visé va faire office d'amplificateur d'attaque . Dans notre cas , la signature peut être allégée en indiquant simplement l'adresse broadcast du réseau protégé.

- FRAGGLE-VICTIME

idem, mais cette fois-ci dst est la victime .

Src.{19,7} > dst.dport : udp

Ce pattern sera détecté n = m * r fois, où r est la taille du réseau amplificateur et m le nombre de requêtes envoyé par l'attaquant . On voit bien ici comment le réseau amplificateur permet d'accroitre linéairement l'ampleur de l'attaque.

ICMP :

- WINFREEZE

Cette attaque consiste à envoyer des informations de reroutage erronnées à la victime, notamment en lui faisant "croire" que la victime est elle-même la prochaine étape sur la route vers la destination voulue . Ainsi, lorsque la victime souhaite contacter cette destination, une boucle se crée avec les conséquences attendues : un Déni de Service .

Src > dst : icmp : redirect IP to host dst

- SMURF-AMPLI

Il s'agit d'une attaque de type Fraggle, version ICMP .

src > [ 0 - 255 ].[ 0 - 255 ].[0 - 255].{0,255}:icmp: echo request


Attaques temporelles

Sous cette désignation, sont regroupées toutes les attaques dont la trace dans les fichiers de log est répartie sur plusieurs lignes ( ie paquets ) parce que les paquets qui composent ces attaques, pris individuellement, sont plus ou moins inoffensifs : les attaques temporelles à proprement parler ( scans, balayages et flooding ), pour lesquelles existent un seuil de tolérance ( nombre de connexions maximum autorisé avant de considérer qu'il s'agit d'une attaque ); et les attaques par fragmentation ( attaques impliquant un seul paquet mais découpé en plusieurs morceaux, telles que Teardrop et Ping of Death ).

Les Scans

Lorsque l'on cherche à attaquer un ennemi, on passe d'abord un certain temps à chercher ses faiblesses pour les exploiter. Les scans ont exactement ce but, puisqu'ils permettent de déterminer d'une part la topologie d'un réseau ( rôle des sweeps ou "balayages" ) et d'autre part quels sont les services actifs sur une machine donnée, les versions de leurs implémentation ( par exemple Sendmail 8.9.3, etc .. ) , voire quel est son système d'exploitation ( port scanning ): il suffira ensuite de se renseigner sur les vulnérabilités des implémentations des services recensés ou du système d'exploitation concerné, puis d'exploiter ces failles tout seul ou à l'aide d'un programme prêt à l'emploi ( si ce programme existe, il se trouve ou ). Le scan fait donc office de reconnaissance du terrain avant l'assaut.

scan "basique"

L'attaquant envoie des paquets SYN vers les ports qui l'intéressent en vue d'établir une connexion complète (le traditionnel handshake ) .


le 3-way handshake de TCP

Dès que le handshake est fini, la connexion est établie, indiquant évidemment qu'un service tourne sur le port visé . L'attaquant est alors libre de clore la connexion, en général sans échange de données . Ce type de scan basique au possible, réalisable à la main avec un client telnet, est cependant des plus mauvais sur le plan de la furtivité, puisque la connexion sera enregistrée dans les logs ( le handshake étant complété ). Or d'un point de vue tactique, il est crucial que la reconnaissance soit furtive : d'abord pour ne pas alarmer la cible et ainsi la prévenir d'une attaque future, et ensuite parce que les traces du scan font remonter à une adresse IP possédée par l'attaquant, permettant une éventuelle identification ( l'attaquant devant récupérer les résultats du scan d'une façon ou d'une autre, l'adresse source utilisée dans le scan n'est pas maquillée et pointe vers une machine détenue - légalement ou non ! - par l'attaquant ).

Techniques furtives

Pour plus de furtivité, il est nécessaire de faire appel à des techniques plus élaborées, ayant souvent recours à des paquets construits directement par le logiciel de scanning et non plus par le système d'exploitation ( ce qui nécessite, pour pouvoir lancer ce scan, les droits "root" sur la machine ... condition de plus en plus facile à remplir avec le développement des stations personnelles sous linux ) . Les descriptions suivantes sont inspirées du manuel de nmap:

TCP SYN scan ( option -sS avec nmap ):

Cette commande fait référence à la technique de scan "mi-ouvert" (half open), car le handshake est entamé mais n'est pas completé. Un paquet avec le flag SYN est envoyé vers la cible, comme lors d'une connexion normale, si ce n'est que le paquet a été "forgé" par le programme et non par le système d'exploitation. Si le port est ouvert chez la cible, celle-ci répond avec un paquet SYN/ACK ( 2e partie du handshake ) . Le système d'exploitation de la machine de l'attaquant détecte ce paquet, considéré comme non sollicité ( puisque la demande de connexion par SYN n'est pas passée par l'OS ), et y répond par un paquet RST, fermant ainsi la connexion avant qu'elle n'ai été établie . Si le port est fermé ( donc inutilisé ), la cible répond par un paquet RST . L' avantage de ce type de scan est qu'il ne sera pas la plupart du temps détecté par la cible ( au sens où la connexion ne sera pas recensée ).

TCP stealth scan ( options -sX, -sF, ou -sN):

Ces scans sont encore plus furtifs et consistent en un "mapping inversé", ie on va détecter les ports fermés pour en déduire ceux ouverts. D'après la RFC 793 décrivant TCP, voici les comportements attendus de la part d'une implémentation TCP, pour un port fermé :

L'idée est donc d'envoyer des paquets sans flag RST, et sans ouvrir de connexion, et d'attendre les réponses des ports fermés , pour finalement établir une carte des ports ouverts par déduction . D'où les techniques "FIN scan" ( paquets FIN faisant office de sonde ), "XMAS scan" ( flags FIN, URG, PSH ) et "NULL scan" ( aucun flag activé ) . La furtivité est meilleure puisque aucune connexion n'est réalisée . Ce scan peut aussi permettre de repérer le système d'exploitation de la cible selon la réponse produite ( elle dépend de l'implémentation TCP de l'OS : par exemple ces scans ne marchent pas sur des cibles Windows NT/95 ).

UDP scan:

Il est possible d'utiliser UDP pour scanner les ports, afin de contourner les IDS surveillant le trafic TCP uniquement. Cependant les résultats obtenus sont beaucoup plus aléatoires, UDP étant un protocole sans connexion, ce qui ne garantit pas qu'un paquet lors du scan atteigne toujours la machine cible .

FTP bounce attack:

on utilise ici le fonctionnalité de proxy des serveurs ftp : selon la rfc 959, les serveurs doivnt permettre d'envoyer des fichiers vers n'importe quelle destination sur internet . Ceci laisse le champ libre pour tous types d'attaques, l'attaquant se faisant passer pour le site ftp utilisé pour le rebond .

Lorsqu'on veut évaluer la difficulté de détecter un scan, on est confronté à un paradoxe . En effet les scans peuvent être à la fois très faciles et très difficiles à repérer : la détection par signature permet de repérer les scans les plus "bruyants", où une centaine de ports est contactée en moins de 30 secondes. Les scans ayant recours aux techniques furtives décrites plus haut ne sont pas relevés par syslog puisqu'il n'y a pas de connexion établie, mais sont facilement repérables à l'aide d'un sniffeur puisque les paquets sont anormaux . Pourtant, les désavantagse majeurs de la détection par seuil sont:

La difficulté est donc de trouver un bon compromis au niveau du seuil afin de limiter le nombre de ces "faux négatifs". Malheureusement, on peut être sûr que les scans non détectés proviennent des adversaires les plus dangereux : ceux qui connaissent les failles des systèmes de détection .

les signatures des attaques

Ici la difficulté, d'un point de vue algorithmique, est qu'il faudrait faire appel à des "meta-patterns" pour modéliser ces attaques. Voici quelques exemples :

- PORT SCAN ( déterminer les services présents sur une machine )

Time1 src.sport1 >dest.dport1 && ( 0 ou plusieurs entrées quelconques ) &&

... && ( 0 ou plusieurs entrées quelconques ) &&

Timen src.sportn > dest.dportn

Avec Timen - Time1 < 1000 ms et dport1 != ... != dportn . n correspond au nombre maximal de ports "scannables" avant de considérer qu'il s'agit d'une attaque.

- MITNICK ATTACK (TCP) ( camouflage d'IP )

PORT SCAN sur dport &&

Time1 src1.sport1 > dest.dport : S && ( 0 ou plusieurs entrées quelconques ) &&

Time2 src2.sport2 > dest.dport : flags data-seqno ACK

La signature décrit ici "l'attaque historique" menée par Kevin Mitnick contre le réseau de Tsutomu Shimomura, du point de vue de la machine attaquée ( dest ). Dans ce cas particulier, il existait une " relation de confiance " ( . rhosts ) entre src1 et dest.On préférera la signature "TCP HIJACK" pour une détection plus générale des détournements de connexion.

- STICK ( désactivation à distance de certains NIDS par déni de service )

Time1 src.sport1 >dest.dport R && ( 0 ou plusieurs entrées quelconques ) &&

... && ( 0 ou plusieurs entrées quelconques ) &&

Timen src.sportn > dest.dport R

Timen - Time1 < 1000 ms.

Contrairement aux attaques ponctuelles et assimilées, la détection dans les logs des attaques temporelles devrait obligatoirement se faire en analysant plusieurs lignes ( comme on l'a vu plus haut, certaines attaques ponctuelles qui sont en fait du flooding sont facilement détectables en raison du port utilisé, etc ... ). Pour éviter d'utiliser des motifs trop lourds, une alternative intéressante est de faire appel à une structure réactive : chaque fois que nous rencontrons un paquet qui pourrait faire partie d'une attaque, la structure évolue jusqu'à atteindre un niveau critique déclenchant une alerte . Concrètement, ce niveau critique peut être un seuil de caractérisation de flood ou de scan, ou bien une taille totale pour un paquet fragmenté ... Nous associons donc à chaque type d'attaque un objet la décrivant, et une instance sera créée à chaque fois qu'une attaque est potentiellement en cours, faisant office de "mémoire" . Ces objets héritent des classes suivantes, construites pour refléter la structure des logs TCPdump ( j'ai omis les constructeurs ) :

classe ICMP  {
	string icmp_type;
	}

classe TCP {
	list of strings flags;
	// flags est un sous-ensemble de { SYN,FIN,PSH,URG,ACK,RST } ou bien vide
	list of ints data-seqno;
	// data-seqno = { Start-SN ;End-SN ]
	int acknum;
	// si le flag ACK n'est pas activé, acknum = -1
	}
classe TCP_FRAG héritant de TCP {
	int fragID;
	int size;
	int offset;
	boolean more;
	// indique si le bit "More Fragments" est activé
	}

Dans l'optique d'une utilisation pour la détection d'intrusion par signatures, je ne définis pas de super-classe PAQUET ou UDP . En effet, les objets que j'utiliserai peuvent contenir des listes d'IP ou de ports . J'ai donc fait ce choix par cohérence et souci de ne pas surcharger les structures ...

Nous avons désormais des classes décrivant la plupart des paquets qu'on aura à filtrer . A partir de là, on peut définir des classes caractérisant les attaques temporelles . Par convention, ces objets sont stockés dans des tables indexées par la caractéristique principale de l'attaque ( cible ou attaquant ) comme par exemple attaque_sur_IP[adresse_attaquant]. Ainsi:

- PING SWEEP (icmp):

Cette "attaque" de reconnaissance consiste à bombarder un réseau de requêtes "ping", afin d'obtenir une carte des adresses actives sur le réseau ciblé .

classe PINGSWEEP  héritant de ICMP{
	string src;
	// à la construction, icmp_type = "echo request"
	time heure_de_debut;
	time heure_en_cours;
	int compteur;
	list of strings victims;
	// victims sert à stocker les IPs des machines "pingées"
	
	function new ...
	function alerte ...
	}

Timei src > dsti : icmp : echo request ==>
si !(pingsweep[src]) {
	pingsweep[src] = new PINGSWEEP // heure_de_debut = Timei et heure_en_cours= Timei;
}
si !( desti est dans pingsweep[src].victims ) { 
	pingsweep[src].compteur =+1;
	pingsweep[src].heure_en_cours = Timei;
	ajouter desti à pingsweep[src].victims;
}
si ( pingsweep[src].compteur > pingsweep_max && pingsweep[src].heure_en_cours - pingsweep[src].heure_de_début < 1000 ms ) {
	Alerte !
}
// pingsweep_max est une variable de seuil à définir

- TCP HIJACK

Cette attaque désigne un détournement de connexion selon la méthode présentée précédemment, à l'aide des "sequence numbers" / "acknowledge numbers" . Notons que dans ce cas, il est nécessaire de connaitre le trafic dans les deux sens . Jusqu'à présent, il était possible de caractériser une attaque par la seule activité de l'agresseur . Ici, pour déterminer si une attaque est en cours, il faut d'abord vérifier si le numéro de séquence a été volé .

classe HIJACK héritant de TCP {
	string victime;
	string spoof;
	time heure_de_debut;
	time heure_en_cours;
}	

Timei src.sport > dst.dport : flags Start-SNi:End-SNi(End-SNi - Start-SNi) ACK ack-numi ==>
si ( !hijack[src.sport] ) {
	// src : machine à protéger, on pourrait donc éventuellement filtrer les machines pour lesquelles on crée cet objet
	hijack[src.sport] = new HIJACK;
	// hijack.victime = src.sport, hijack.spoof = dst.dport, hijack.acknum = ack-numi,
 	//hijack.data-seqno[1] = End-SNi, hijack.data-seqno[0] = Start-SNi, hijack.heure_de_debut = Timei;
}
si ( hijack[src.sport] ) {
	hijack.acknum = ack-numi;
	hijack.data-seqno[1] = End-SNi;
	hijak.heure_de_debut = Timei;
	//mise à jour des paramètres cruciaux
}
si ( hijack[dst.dport] ) {
	// src est l'attaquant potentiel, ce coup-ci
	si ( hijack.spoof != src.sport && Start-SNi == hijack.acknum && ack-numi == hijack.dta-seqno[1] ) {
		hijack.heure_en_cours = Timei;
		Alerte !
		// les 3 conditions du spoofing sont réunies
	} 
}

Cette signature est peut-être moins évidente à saisir que les autres : supposons que nous avons ce paquet :

Timei victime.sport > spoof.dport : flags Start-SNi:End-SNi(End-SNi - Start-SNi) ACK ack-numi

victime envoie un paquet à la machine spoof, qui peut potentiellement servir de masque à un attaquant . Le paquet normalement attendu si la machine spoof existe bien et a effectivement sollicité le paquet précédent est de la forme :

Timej spoof.sport > victim.dport : flags ack-numi:End-SNj(End-SNj - ack-numi) ACK End-SNj

Par contre, en cas de détournement de connexion avéré, nous verrions passer un paquet de cette sorte :

Timej attaquant.sport > victim.dport : flags ack-numi:End-SNj(End-SNj - ack-numi) ACK End-SNj

Où attaquant est une machine différente de spoof . Cependant, pour confirmer le détournement de connexion, il faut vérifier les numéros de séquence et d'acquittement, formant un doublet unique caractérisant l'avancement d'une connexion ( en effet, un même port d'une machine peut être accédé par plusieurs machines en même temps, comme le port http par exemple ) tout comme le quadruplet {src,sport,dst,dport} caractérise de façon unique une connexion . Si une machine usurpe un tel doublet, c'est qu'elle tente de détourner la connexion.

L'attaque par détournement de connexion amène une dernière considération : Au vu de la signature définie à l'instant, il suffirait à attaquant de se présenter avec l'adresse de spoof lorsqu'il envoie ses paquets pour devenir indétectable ( l'utilisateur sur attaquant peut construire complètement ses paquets s'il est root sur cette machine ), puisqu' à l'observation le traffic à l'air tout à fait normal. Le seul désavantage pour le méchant est qu'il n'aura pas la possibilité de récupérer la réponse à son paquet - à moins d'évoluer en réseau shared, mais il existe de nombreuses attaques où il n'est pas nécessaire d'obtenir de réponse de la machine attaquée ( effacement de fichier, etc ... ) . En fait, ce détournement est absolument indétectable avec l'approche qu'on a choisie ( analyse des logs sur une seule machine ). Le seul moyen de détecter ce genre d'attaque serait de confronter les logs de spoof et ceux de victime, pour mettre en évidence la désynchronisation de la connexion au moment où attaquant s'est immiscé. Ces attaques restent cependant improbables hors des sous-réseaux; on ne les verra donc probablement pas si on effectue l'analyse de logs au niveau d'un point de sortie du réseau ( routeur, firewall ... )

- SYN FLOOD ( tcp )

Lorsque le port d'une machine est sollicité pour une connexion TCP, la machine garde une trace de ce contact dans la queue de connexion ( connection stack ). Ainsi, lorsque le paquet d'acquittement revient ( la 3e partie du handshake ), la machine sait que tout va bien . La trace est maintenue dans la queue un certain temps qui dépend des systèmes d'exploitations, et si l'acquittement n'est pas arrivé avant cette limite temporelle la connexion est considérée comme perdue et la trace est retirée de la queue . Or cette queue a bien évidemment une capacité limitée . L'idée est donc de "bourrer" cette queue de requêtes de connexions provenant de machines en réalité inexistantes ( pour éviter qu'un paquet d'acquittement ou qu'un paquet de fin de connexion ne soit renvoyé à la victime ), si bien que toute connexion légitime ne pourra être stockée dans la queue et donc aboutir .De l'extérieur, le port de la victime semble inactif . Ici deux patterns agissent conjointement:

classe SYNFLOOD {
	time heure_de_debut;
	time heure_en_cours;
	string dst;
	int dport;
	list of strings attackers;
	// contient les adresses IP des éventuels attaquants
}

Juste avant que la file d'attente soit engorgée ( à paramétrer avec synflood_max[dport], qui dépendra du port visé ), l'alerte est donnée . Il faut pouvoir tenir compte du temps, afin de ne plus tenir compte des connexions qui ont été automatiquement désactivées par Timeout . D'autre part, on parvient à détecter une attaque que le pattern matching simple ne pouvait pas relever ( nécessité d'un retour en arrière ) : le détournement du 3-way handshake de TCP " à la Mitnick " .

- PORT SCAN

Le scanning de port sert à déterminer les services présents sur une machine. On en a fait une large présentation plus haut .

classe PORTSCAN héritant de TCP_FRAG{
	// pour l'instant, pas de détection de scans par UDP, viendra plus tard ...
	string dest;
	string src;
	string type;
	list of int ports;
	// ports scannés
	int compteur;
}

Time1 src.sporti > dest.dporti : flags data-seqno ack window urg options
si !(portscan[dest]) {
	if ( flags == SYN ) {
		portscan[dest] = new PORTSCAN // heure_de_debut = Timei et heure_en_cours= Timei;
		portscan(src).type = "SYN scan";
	}
	else if ( flags == FIN ) {
		portscan[dest] = new PORTSCAN // heure_de_debut = Timei et heure_en_cours= Timei;
		portscan(dest).type = "FIN scan";
	}
	else if ( flags == "" && ack == ¤ && urg == ¤ ) {
		portscan[dest] = new PORTSCAN // heure_de_debut = Timei et heure_en_cours= Timei;
		portscan(dest).type = "NULL scan";
	}
	else if ( flags == "FIN,PUSH" && urg == "URG" ) {
		portscan[dest] = new PORTSCAN // heure_de_debut = Timei et heure_en_cours= Timei;
		portscan(dest).type = "XMAS scan";
	}
	if ( sporti == 20 ) {
		portscan[dest].type .= " via FTP bouncing";	
	}
	if ( options contient  (frag ID :size@offset{+, ¤}) ) {
		// paquet fragmentés pour tromper les IDS
		portscan[dest].type .= " avec fragmentation";
	}
}
si ( dporti n'est pas dans portscan[dest].ports ) {
	ajouter dporti à portscan[dest].ports;
	portscan[dest].compteur =+1;
}
si ( portscan[dest].compteur > scan_max ) { 
	// scan_max = 10 parait être un seuil correct ( surtout si on ne tient pas compte du temps )
	// à confirmer avec l'expérience ...
	Alerte !
}

- STICK

Stick est une tentative de désactivation à distance des systèmes de détection d'intrusion orientés réseau . L'attaque consiste à envoyer un très grand nombre de paquets RST ( fin de connexion brutale ), ce qui a pour effet de surcharger de travail le NIDS. Ceci aura éventuellement pour effet de provoquer un déni-de-service contre le système de détection d'intrusion, laissant le réseau protégé sans surveillance.

classe STICK héritant de TCP {
	string dest;
	string src;
	time heure_de_debut;
	time heure_de_fin;
	int compteur;
}	


Timei src.sporti > dest.dport : R =>
si !(stick[dest.dport]) {
	stick[dest.dport] = new STICK
	// heure_de_debut = Timei et heure_en_cours= Timei;
}
stick[dest.dport].compteur =+1;
si ( stick[dest.dport].compteur > stick_max ) {
	//stick_max = 10 ? plus de 10 paquets RST pour clore une connexion de façon abrupte, c'est louche !
	Alerte !
}

- SMURF-VICTIME ( icmp )

principe identique à fraggle-victime.

classe SMURF_VICTIME héritant de ICMP {
	string dest;
	list of string attackers;
	// stocke les IP des machines amplificatrices
	time heure_de_debut;
	time heure_en_cours;
	int compteur;
}

timei srci > dst : icmp : echo reply ==>
si !(smurf-victim[dst]) {
	smurf-victim[dst] = new SMURF_VICTIME; 
	// heure_de_debut = Timei et heure_en_cours= Timei;
}
ajouter srci à smurf-victim[dst].attackers;
smurf-victim[dst].compteur =+1;
si ( smurf-victim[dst].compteur > smurf_max ) {
	Alerte !
}

Attaques par fragmentation

Le concept de fragmentation

La fragmentation a lieu lorqu'un datagramme IP en transit doit paser par un réseau dont la taille maximale de transmission ( MTU ) est plus petite que la taille du datagramme (en clair, il y a engorgement ). Par exemple, la MTU d'Ethernet est de 1500 octets; donc un datagramme de taille supérieure à 1500 octets devra être fragmenté pour voyager sur Ethernet. Les fragments se comportent exactement comme des paquets normaux, si ce n'est qu'ils sont réassemblés par la machine destinataire . Pour se faire, chaque fragment contient les informations suivantes :

Toutes ces informations se situent dans l'en-tête IP, cet en-tête étant lui-même suivi par un fragment encapsulé .

La fragmentation est un outil de choix pour mener des attaques pour les raisons suivantes :

attaques basées sur la fragmentation et leurs signatures

Les traces de paquets fragmentés sont un peu différentes de celles des paquets normaux dans les logs TCPdump, et reflètent l'absence d'informations fournies par l'en-tête TCP . Dans ces conditions, les fragments ne contenant pas l'en-tête ont ce format générique :

Timestamp src > dst : (frag ID :size@offset{+, ¤})

Les attaques suivantes fonctionneront donc avec 2 signatures : une première pour détecter le fragment contenant l'entête, et la suivante pour repérer les informations caractéristiques de l'attaque par fragmentation proprement dite .

- TEARDROP (TCP)

L'attaque exploite le chevauchement de paquets fragmentés.

Ici, une difficulté supplémentaire est à prendre en compte : les paquets n'arrivent pas forcément dans le bon ordre, ie dans l'ordre des offsets . Pour un paquet fragmenté normal, et pour toute valeur de i, nous savons que offset_i + size_i = somme( size_j, j = 1 ... i ). Par conséquent, une attaque teardrop est telle qu'il existe une valeur de i pour laquelle offset_i + size_i < somme( size_j, j = 1 ... i ) .

classe TEARDROP héritant de TCP_FRAG {
	string dst;
	int dport;
	string src;
	int sport;
	int ID;
	// ID number du paquet fragmenté
	int offset_max;
	// le plus grand offset reçu en cours
	int taille_theorique;
	// egal à offset + size du dernier fragment reçu
	int taille_reelle;
	// somme des size_i reçus
}

Timei SRC.SPORT > DST.DPORT : flags data-seqno ack window (frag ID :size_i@offset_i{+,¤}) ==>
si !( teardrop[ID] ) {
	teardrop[ID] = new TEARDROP;
}
	teardrop[ID].dst = DST;
	// etc ...
et
Timei SRC > DST : (frag ID :size_i@offset_i{+,¤}) ==>
si ( offset_i  == max ( offset_i, teardrop[ID].offset_max) ) {
	teardrop[ID].offset_max = offset_i ;
	teardrop[ID].taille_theorique = offset_i + size_i;
}
teardrop[ID].taille_reelle =+ size_i;
si ( teardrop[ID].taille_theorique < teardrop[ID].taille_reelle ) {
	Alerte ! 
	//la condition ci-dessus n'est pas nécessaire mais elle est suffisante 
	//( elle devient nécessaire lorsque tous les fragments sont arrivés). A défaut de trouver mieux ...
}

- PING OF DEATH (icmp)

L'envoie d'une requête ping trop grosse ( de taille supérieure à 65 ko ) provoque un plantage de la machine cible, et donc un déni-de-service .

classe POD héritant de ICMP {
	string src;
	string dst;
	int ID;
	int total_size;
}

Timei src > dst : icmp : echo request (frag ID :size_i@offset_i{+,¤})  ==>
si !(pod[ID]) {
	pod[ID] = new POD;
}
et
Timei SRC > DST : (frag ID:size_final@offset_final¤) ==>
// si pod[ID] existe
pod[ID].total_size = offset_final + size_final;
si (  pod[ID].total_size > 65 k ) {
	Alerte !
}

La taille du paquet Ping est connue grace au dernier paquet de la fragmentation ( celui ne contenant pas de + ), il suffit donc de repérer celui-ci, et de tester la taille du paquet . Une fois ce test effectué, on peut détruire l'objet pod associé dans la table .

Sur Teardrop, l'inconvénient est qu'on n'a pas de moyen de détruire l'objet une fois que le paquet complet a été reçu, puisque les paquets fragmentés arrivent dans le désordre. Ces attaques restent assez rares, ce qui devrait limiter le nombre d'objets correspondants créés.


Test des signatures - Résultats préliminaires

Afin de tester l'efficacité des signatures présentées dans ce rapport, un ensemble de scripts appelé LOGre ( pour faire référence aux fichiers de log qu'il manipule et aux expressions régulières qu'il utilise intensément ) a été mis en point en Perl . Ce langage a été choisi en raison de sa grande portabilité et de la puissance de ses outils de test d'expressions régulières .

présentation de LOGre

LOGre est un ensemble de scripts écrits en perl, dont la fonction principale est de tester les signatures présentées dans ce rapport . L'ensemble comprend trois parties :

Améliorer encore la recherche : quelques optimisations possibles

Il est notamment possible d'exploiter ce qui a été fait dans le domaine de la recherche de motifs pour essayer d'accélérer la recherche de paquets suspects :

Classer les signatures

Le temps d'exécution est une ressource cruciale dans notre problème, où d'énormes quantités de données doivent être manipulées . Il s'avèrerait donc intéressant de pouvoir classer les signatures principales en une structure permettant de gagner du temps à l'exécution : certaines signatures présentant des similitudes, il peut être fructueux d'essayer de les "factoriser" en les rassemblant dans une structure d'arbre similaire à un arbre de recherche ( TRIE ) . Cet arbre peut être défini une fois pour toutes au démarrage du système de détection d'intrusion, et changé uniquement quand une nouvelle signature doit être rajoutée . De cette façon, chaque paquet est confronté à une signature ayant au plus la taille de la plus longue signature qu'on aura défini. Le gain en vitesse de traitement est donc théoriquement significatif par rapport à l'approche "naïve" consistant à comparer un paquet avec chaque signature, séquentiellement . Il est même encore possible d'améliorer le stockage en termes d'espace occupé en optant pour une structure de DAWG ( Directed Acyclic Word Graph ), qui est une forme de TRIE sur lequel on a appliqué un algorithme de minimisation . D'après l'article Kucherov/Rusinowitch, le DAWG peut se construire en temps O( |S| ) où S est l'ensemble des signatures, et le rajout d'une signature s se fait en temps O( |s| ).

Une fonction de comptage plus réaliste

tenir compte de "l'age" des paquets ...

Gérer les tables d'objets

Les attaques temporelles tels que le scanning ou l'inondation nécessitent de tenir compte des paquets "suspects" que l'on rencontre lors de l'analyse et d'en garder une trace ( notamment le nombre de fois que ces paquets sont relevés ), comme on l'a vu précédemment . Afin d'éviter l'engorgement de la mémoire de stockage, il faudrait donc régulièrement purger les tables de stockage évoquées plus haut . On peut procéder comme suit : chaque table possède une taille maximale . Lorsque cette taille est atteinte, on efface de la table les entrées pour lesquelles le compteur a la plus faible valeur . On gagne ainsi de la place en détruisant les références à des paquets ne faisant vraisembablement pas partie d'une attaque en cours ( sauf si on a affaire à un attaquant particulièrement vicieux et prêt à "délayer" un scan sur de très grandes durées de temps, mais dans ce cas il faut admettre qu'une telle attaque est de toutes façons quasiment indétectable ) .


Les limites de la détection d'intrusion

Le modèle que nous avons choisi d'étudier est nécessairement limité par le fait qu'il ne surveille que les attaques portant sur les couches Transport et IP . Or un grand nombre d'attaques existe pour la couche Applicative . Cependant, et de façon générale, la détection d'intrusion présente des limites et des problèmes et peut quelquefois se montrer impuissante dans certains cas.

les covert channels ... ou la stéganographie appliquée aux protocoles

La solution retenue ici ne permet pas de contrer les attaques par "covert channels" de type Loki ... ie les logiciels qui permettent d'utiliser un canal a priori inoffensif pour faire transiter de l'info : par exemple loki fait communiquer le client et le serveur via des paquets icmp echo, AckCmd passe les firewalls en n'utilisant que des paquets ack ... . Ce genre de problème nécessite en fait de "sniffer" plus en profondeur et demande l'application d'une batterie de tests cryptanalytiques sur les paquets ( comme par exemple des tests statistiques sur les SN ), assez lourds en ressources de calcul . A l'heure actuelle, aucune solution n'existe contre ce danger potentiel, puisque même l'interception en profondeur peut être neutralisée par l'usage de la cryptographie pour camoufler les données en transit.

les chevaux de troie

Le même problème apparait lorsqu'on cherche à se prémunir des "trojan horses". Les "trojans" sont des applications s'apparentant aux virus dans la mesure où ceux ci sont installés souvent à l'insu de l'utilisateur . Une fois en place, toute personne sachant contacter le trojan peut prendre le contrôle de l'ordinateur infecté comme si il en était l'utilisateur actuel ( certains logiciels poussent même le zèle jusqu'à permettre d'afficher l'écran de l'utilisateur piraté .. ) . Une façon de détecter les trojans est donc de vérifier que les ports de communication habituellement ouverts par un trojan ne sont pas actifs sur la machine. Malheureusement, les trojans les plus récents sont hautement configurables, et peuvent donc être activés sur n'importe quel port . Ce genre de signature n'est donc plus efficace .

La seule méthode à peu près efficace pour détecter ce genre d'attaque repose sur le fait qu'un serveur doit être nécessairement installé sur la machine infectée pour que le covert channel ou le trojan soit mis en place : ainsi, une analyse rigoureuse des changements sur le disque dur d'une machine associée à l'observation éventuelle de trafic inexpliqué peut permettre de découvrir un covert channel ou un trojan en activité . Pour plus de détails et des idées sur les covert channels, voir l'article de C. Rowland.

Détection de mauvaise utilisation contre détection d'anomalie : signatures contre apprentissage

Un des gros désavantages de la détection par signatures d'attaques est son manque de flexibilité et par conséquent sa vulnérabilité aux mutations : d'une part, il faut pour pouvoir définir une signature avoir déjà été confronté à l'attaque considérée . D'autre part, certaines de ces signatures se basent sur des caractéristiques "volatiles" d'un outil, comme par exemple le port qu'un certain troyan ouvre par défaut, la valeur de ISN choisie par tel autre outil de pirate, etc ... Souvent ces logiciels sont soit hautement configurables, soit "open-source" donc librement modifiables . Les caractéristiques retenues pour définir la signature sont donc fragiles, et les signatures extrêmement sensibles aux mutations . Un exemple actuel est l'outil ADMutate, qui permet de camoufler une attaque au niveau applicatif afin de la rendre non détectable par les systèmes de détection d'intrusion conventionnels utilisant des signatures . Contre ce genre de problème, une parade consiste à définir ce qu'est l'état de "compromission", c'est-à-dire l'état attendu d'une machine pendant ou après une attaque . On peut alors essayer de détecter quand la machine entre dans cet état : on ne saura pas comment la machine a été attaquée si l'attaque était de type inconnu, mais on se sera quand même aperçu que quelque chose a eu lieu. Bien sûr, la difficulté majeure dans cette parade est de définir ce fameux état de "compromission". On pourrait donc penser qu'une approche par apprentissage serait une bonne alternative . Cependant, il n'en est rien : outre une convergence plutôt longue vers un modèle comportemental "normal", rien n'empêche un pirate se sachant surveillé de "rééduquer" un tel système en faisant évoluer progressivement son modèle de convergence vers un comportement tout à fait anormal pour l'analyste, mais "normal" d'un point de vue statistique . On retrouve un problème similaire dans l'approche par signatures des attaques temporelles, la signature comprenant fréquemment une valeur de seuil : si l'attaquant a du temps devant lui, il peut s'arranger pour délayer ses attaques dans le "bruit" en prenant garde à ne pas générer une activité dépassant les seuils fixés ( surtout vrai pour les scans de ports, par exemple : si on fixe le seuil de détection à 30 ports scannés, il suffit d'en scanner 29 ou moins de façon assez espacée pour ne pas être détecté ) . C'est un problème assez difficile à résoudre, dans la mesure où la difficulté réside dans la définition d'une attaque temporelle en général ( et d'un scanning de ports en particulier ) . Une solution possible serait d'associer une "probabilité d'attaque" qui tendrait vers 1 quand le seuil fixé est atteint ( par exemple, le rapport min (ports contactés, seuil ) / seuil ) . L'analyste humain déciderait alors lui-même si l'activité relevée est une attaque ou non . Cependant, avec cette approche, on peut passer à côté d'attaques temporelles "distribuées", par exemple .

Problèmes de ressources et vulnérabilité aux Dénis-de-Service

Outre la taille des fichiers de log ( de l'ordre du Go ), la détection d'intrusion est excessivement gourmande en ressources : par exemple le pattern SynFlood crée un objet par connexion TCP. Au pire, nous pouvons donc avoir O( R * 65000 ) objets synflood créés en même temps, où R est le nombre de machines surveillées et 65000 le nombre approximatif de ports TCP existants . Ces objets disparaissent lorsque le handshake est complet pour toutes les connexions en cours sur les ports considérés . Il faudrait donc tenir compte du temps de "time out" des machines, en cas de handshake laissé en suspens. Les objets générés par teardrop ne sont pas détruits, car il n'est pas possible de connaitre à l'avance le nombre de fragments que l'on va recevoir . La rareté de ces attaques en comparaison avec les syn flood et les scans compense ce défaut. Le pattern HijackTCP "surveille" virtuellement tout le traffic TCP . L'optimisation par "nettoyage" des tables à intervalles temporels réguliers peut donc être très utile .

On voit donc que la détection d'intrusion est un exercice périlleux pour les ressources en espace . Un attaquant un peu malin peut chercher à en profiter, en essayant de provoquer un déni-de-service au niveau du système de détection d'intrusion, ou au pire au niveau du système d'exploitation de la machine supportant l' IDS. Une fois l'IDS désactivé, l'attaquant a le champ libre pour tenter tout ce qui lui plait . Ainsi, l'attaque "STICK" est une tentative de déni-de-service contre les IDS ( en particulier contre ISS RealSecure ) : l' attaquant espère ainsi surcharger de travail l'IDS, au point de le désactiver ou au moins de le rendre moins efficace .

Problème fondamental de la détection d'intrusion orientée réseau

La détection d'intrusion orientée réseau présente un problème fondamental : comment être certain que ce que le générateur d'événements va capturer est bien la même chose que ce qui va atteindre les machines du réseau à surveiller ?Une différence notable provient déjà du fait que le système de détection d'intrusion se trouve rarement sur la machine qu'il est en train de protéger . Il existe aussi des limitations due aux performances : les vitesses de transmission sont parfois telles qu'elles dépassent largement la vitesse d'écriture des disques durs les plus rapides du marché, ou même la vitesse de traitement des processeurs . Il n'est donc pas rare qu'un "sniffeur" ait un taux de perte de paquets non nul, si bien que des paquets non reçus par l'IDS seront peut-être reçus par la machine destinataire . D'autre part, un système de détection d'intrusion ne faisant pas de reconstruction de paquets fragmentés aura forcément un aperçu de ce qui passe sur le réseau différent de ce qui sera réellement reçu par les machines surveillées . Comme on l'a évoqué précédemment, un tel système de détection d'intrusion passerait à côté des attaques de type Teardrop, du chevauchement des en-têtes ( pour modifier l'IP source, le port de destination, ect... au dernier moment ), ou encore des attaques au niveau applicatif qui seraient fragmentées pour leurrer le moteur d'analyse par pattern matching de l'IDS. Il se peut aussi que la différence de temps entre le moment où l'IDS reçoit un paquet et celui où la machine destinataire reçoit ce paquet soit cruciale : il peut par exemple se passer quelque chose sur la machine destinataire, faisant que ce paquet sera rejeté, alors que l'IDS l'aura analysé et fera l'hypothèse que ce paquet a bien été reçu et traité par sa destination . Dans l'autre sens, il se peut aussi qu'une différence de systèmes d'exploitation entre la machine supportant l'IDS et la machine surveillée fasse que certains paquets rejetés par le système de détection d'intrusion soient acceptés par la destination ( c'est par exemple le cas des paquets UDP avec une somme de contrôle erronée, rejetés par la plupart des systèmes d'exploitation, sauf les plus anciens ) . Ce problème peut engendrer deux types de faux négatifs chez un système de détection d'intrusion :

Les problèmes d'insertion et d'évasion, en pratique, restent cependant difficiles à exploiter pour un attaquant . En effet, de telles attaques exploitent les spécificités des systèmes d'exploitation et du système de détection d'intrusion, et demandent donc de connaitre parfaitement la composition du réseau que l'on souhaite attaquer . Toutefois, bien que difficilement utilisable, le risque existe .


Conclusion


Sources:

Etat de l'art:


signatures et attaques:

Fragmentation, furtivité et failles des IDS:

Covert channels:

Aspects algorithmiques:

Logiciels:

m'écrire: huin@loria.fr