• Aucun résultat trouvé

Ce chapitre a été l’occasion de décrire ce qu’est un IDS et d’identifier ses principaux compo- sants que sont : le senseur (sensor, probe, sniffer), le moniteur (monitor), le résolveur (resolver) et le contrôleur (controller). Chacun d’eux joue un rôle important même s’il n’est pas rare de trouver certains composants combinés en un seul module sur certains systèmes. Néanmoins, ils conservent d’une manière ou d’une autre leurs rôles et leurs fonctions. Ces composants, en plus de leur rôle peuvent servir à catégoriser les IDS.

Ainsi, la sonde dont la fonction principale est la collecte de données, permet d’identifier l’IDS comme un NIDS ou un HIDS respectivement s’il reçoit des données provenant du réseau ou provenant des opérations générées par le noyau du système hôte. La position d’un senseur

influence fortement sur le type, la qualité et la quantité de données qu’il reçoit ; de ce fait le choix de son positionnement se fait de manière réfléchie et doit répondre le plus souvent aux critères de sécurité établis en amont.

Le contrôleur ou module d’analyse est le noyau du système. Ce titre lui est dû car il s’occupe du traitement de détection des intrusions sur la trace reçue. Autour de lui gravite deux élé- ments essentiels : La trace, étant le résultat de la collecte de données des capteurs, et la base de connaissances utilisée pour identifier une intrusion d’une opération inoffensive.Le module d’analyse pour mener à bien sa tâche, use de divers mécanismes et outils ; entre autres le choix d’une approche de détection. À ce titre, nous identifions trois approches courantes dans le monde des IDS : La détection par anomalies, la détection à base de signatures, et la détection à base de politiques de sécurité. La principale remarque que nous soulignons sur ces trois méthodes de détection est le caractère complémentaire de leurs propriétés. Il en résulte notre opinion selon laquelle la combinaison de ces méthodes est une solution efficace ; l’essentiel étant de trouver l’équilibre entre leur usage. Enfin, la stratégie utilisées peut être un critère pour catégoriser les IDS.

Le module d’alerte assure la réponse que propose le système lorsqu’une intrusion est détectée. Cette réponse peut être réactive ou passive ; passive dans le sens où l’action prise se limite à l’observation et la collecte des données provenant de l’intrusion et réactive dans le sens où le système peut agir en allant chercher de l’information directement depuis la source de l’intrusion, en altérant la base de connaissances afin de s’adapter à l’intrusion, ou en lançant automatiquement certaines actions défensives.

Pour finir, le module de contrôle offre une interface permettant de manipuler et de configurer l’IDS. Les divers composants d’un IDS n’étant pas toujours situés au même endroit, ce module permet d’uniformiser la configuration des éléments qui composent l’IDS, de paramétrer cer- taines options des senseurs telles que la fréquence d’envoi des données collectées (heartbeats) et les filtres à appliquer sur les données collectées.

On constate, grâce à la description de Snort et Prelude, la présence de ces quatre composants propres aux IDS ; c’était aussi l’occasion d’introduire la notion de langage utilisé pour décrire comment identifier les tentatives d’intrusions. Le chapitre suivant va s’accentuer sur ce dernier point en présentant quelques logiques temporelles et en présentant les langages proposés par trois différents IDS.

Chapitre 2

Langages de description

Ce chapitre se concentre essentiellement sur les langages de description de signatures utilisés par les systèmes de détection d’intrusions et leurs relations avec les méthodes formelles. En plus d’être un élément du module d’analyse de l’IDS, le langage de description utilisé est d’une grande importance, car il caractérise la capacité du système de détection à décrire tous les types de menaces. Afin de produire un meilleur langage de description qui couvre tous nos besoins, plusieurs techniques ont été explorées. Dans ce chapitre nous mettrons l’accent sur l’usage des méthodes formelles comme outil pour décrire les signatures des menaces.

En fonction de la manière dont la description est faite, on peut classer les langages de descrip- tion de menaces. Nous distinguons deux types de langage :

– Langages déclaratifs : Ils permettent de décrire une menace de manière déclarative. Cela consiste à trouver ce qui identifie l’attaque sans indiquer la procédure pour le faire. – Langages impératifs : un langage est dit impératif s’il spécifie la manière de procéder

pour trouver l’attaque. Ainsi, la signature donnée est similaire à un algorithme à suivre pour trouver la menace.

Un langage déclaratif est l’option la plus souhaitée, car offrant l’intérêt d’alléger l’écriture de nouvelles règles en permettant de ne décrire que le comportement que l’on souhaite identifier. Le fait de spécifier comment doit se faire la détection (langage impératif) impose plus de rigueur dans la description des menaces, de plus il faudra prendre en compte les variantes de comportements qui peuvent subsister d’un système à un autre ; ce qui complexifie la tâche de rédaction de règles et l’aspect générique de ces dernières. À l’opposé des langages impératifs, les langages déclaratifs permettent de se focaliser sur les propriétés que l’on souhaite exprimer, faisant abstraction de tout mécanisme en rapport avec leurs processus de détection ; cette tâche étant assignée au moteur de détection. En réduisant de cette manière l’empreinte qu’a celui qui rédige une propriété sur la détection de cette dernière, on bénéficie implicitement :

d’écriture des règles ;

– d’un comportement uniforme du processus de la détection, étant donné que les mêmes mécanismes de détection sont appliqués à tout le monde.

Au cours de ce chapitre, nous proposons une description des méthodes formelles et énonçons les raisons qui en font un outil intéressant pour la définition d’un langage de description de menaces. Puis, nous présenterons une introduction de quelques logiques temporelles afin de montrer un usage concret des méthodes formelles. Cette présentation des logiques temporelles offre aussi un bon contexte pour expliquer les concepts de base inhérents à la détection d’intru- sions. Elle sert aussi à illustrer le caractère évolutif des langages de description de menaces et les raisons à l’origine de ce phénomène. Enfin, nous porterons notre attention sur trois exemples réels de langages utilisés par des IDS. Cette transition de la théorie à la pratique nous donnera l’opportunité de voir le contraste entre ces deux mondes, mais sera aussi l’occasion de faire un comparatif entre trois langages utilisés par les IDS.

2.1

Méthodes formelles

Les méthodes formelles sont des techniques permettant de raisonner rigoureusement à l’aide de logique mathématique sur des programmes informatiques ou du matériel électronique, afin de démontrer leur validité par rapport à certaines spécifications [50]. Cette approche mathéma- tique est utilisée dans le domaine des systèmes de détection d’intrusions à cause des nombreux avantages offerts.

Les méthodes formelles servent entre autres à définir un langage de description pour nos signatures et proposer une méthode de contrôle des données collectées. Pour ce faire, nous devons d’abord définir la représentation des données collectées (la trace). Cette dernière est un élément essentiel car la validation d’une signature se fait en fonction de sa présence dans la trace.

La manière la plus usuelle de représenter la trace est sous la forme d’une chaîne. Cela se justifie par le fait que la trace est une succession d’événements où chaque nœud décrit un événement du système à un moment donné avec les valeurs de ses composants. Pour un NIDS, chaque nœud représente un paquet réseau collecté à un moment précis et la chaîne est ordonnée suivant l’ordre d’apparition des paquets.

Avantages Les avantages inhérents aux méthodes formelles justifient amplement leur utilisa- tion pour définir des langages de détection d’intrusions. Nous identifions trois de ces avantages ci dessous :

Élimine l’ambiguïté : le plus évident de ces avantages demeure qu’on élimine l’ambiguïté qui peut exister en exprimant nos propriétés en langage naturel. Cette caractéristique des

mathématiques réduit les risques de mauvaise compréhension des propriétés qui sont le plus souvent exprimées dans un langage naturel. Les méthodes formelles sont aussi utiles pour s’assurer du respect des propriétés exprimées. Pour faire cette vérification, nous disposons généralement de deux options : tester tous les cas de figure ou bien de manière symbolique tester le respect des propriétés à l’aide d’une logique. La première solution, difficile à mettre en œuvre, nécessite beaucoup de temps et il n’est pas évident de pouvoir répertorier tous les cas à tester. La seconde approche semble beaucoup plus réaliste. Une fois les propriétés exprimées avec une logique mathématique, nous disposons de plusieurs méthodes de vérification qui vont de la preuve automatique au model cheking [17] (voir la section2.2). À noter que dans ce document nous privilégions la vérification de modèles. Langage déclaratif : en proposant un langage déclaratif, on facilite grandement la rédaction de nouvelles règles. Avec l’aide des méthodes formelles, le langage de description de signatures s’accompagne d’une syntaxe et d’une sémantique qui permettent de décrire des règles et de proposer un mécanisme permettant de les interpréter de la bonne manière. Ainsi, on dispose d’un langage déclaratif qui allège l’écriture de règles tout en permettant de ne pas se soucier des mécanismes à mettre en œuvre pour interpréter et valider l’expression exprimée.

Validation de propriétés Pour finir, on peut appuyer ce choix en soulignant que les mé- thodes formelles représentent un choix judicieux, car elles se prêtent bien à ce type de problème. La notion de vérification de propriétés et de certitude par rapport au respect des propriétés fait partie intégrante de la définition même de la notion de méthode for- melle [50]. Le mécanisme de trace et son aspect temporel n’entrent pas en contradiction avec la logique proposée et s’y expriment avec facilité et clarté.

Contraintes Toutefois, cette solution n’est pas sans contrainte et on en note deux princi- pales :

– la dualité expressivité et complexité du langage ; – le caractère bas niveau des langages produits.

L’objectif visé en proposant un nouveau langage est de le rendre plus expressif tout en le gar- dant le plus simple possible. Cependant, on se rend vite compte que ces deux caractéristiques sont comme les deux bouts d’une même corde. Elles sont fortement liées, et chercher à amé- liorer l’une implique le risque de dégrader l’autre. Étant donné qu’un langage simple, mais qui ne permet pas d’exprimer nos propriétés, demeure inutile, nous pouvons en conclure que l’ex- pressivité du langage est une nécessité première tant que sa complexité demeure raisonnable. L’évolution des variantes de LTL [44] l’illustre bien. À chaque nouvelle variante, le langage améliore son expressivité, mais perd un peu plus de sa lisibilité. Le défi demeure de trouver le juste milieu. Aussi, certains peuvent juger les langages produits comme étant de bas niveau ; les trouvant peu efficaces, sinon lourds pour définir des comportements plus élaborés. Cette

remarque est juste dans le sens où les options proposées sont atomiques et qu’il est nécessaire de décrire plusieurs éléments afin de définir une règle plus complexe. Par exemple, pour décrire une ouverture de session dans le cas d’un NIDS, on devra donner toutes les étapes de réception et d’envoi de paquets qui permettent d’aboutir à l’ouverture d’une session. Il en découle que la règle est longue et parfois répétitive si un même comportement apparaît dans plusieurs autres scénarios. Mais, on peut contourner cela en proposant une librairie de macros offrant du coup la possibilité de définir, de partager et d’utiliser des portions de règles et de comportements plus élaborés. De ce fait, la rédaction de scénarios complexes se trouve grandement allégée.

Défis La première interrogation qu’on est en droit de se poser est la suivante : peut-on exprimer toutes les propriétés avec une logique mathématique ? Cette question remet en cause les limites de l’expressivité des langages produits avec les méthodes formelles. Nous avons précédemment énoncé avec les variantes de LTL, ce besoin de rendre toujours plus expressif le langage dont nous disposons. Le fait de chercher à l’améliorer est en soi un argument qui montre que nous n’arrivons pas encore à exprimer toutes les propriétés.

Avec le langage naturel, certaines propriétés peuvent sembler ambiguës. Par exemple, un utili- sateur a droit à un nombre raisonnable d’erreurs pour saisir son identifiant. De plus, un paquet réseau attendu peut-être perdu ou altéré. Afin de prendre en compte cette gestion des impré- vues et des valeurs imprécises, on a recours le plus souvent à la notion de seuil. Cependant, il est probable que le seuil ne soit pas le même d’un cas à un autre et le définir à l’aide de statistiques n’est pas gage de certitude. Ceci fait qu’une fois définie, la valeur attribuée à un seuil est sujette à critique étant donné le caractère flou ou aléatoire de certaines propriétés. Une fois son attaque connue, le pirate en utilise une variante qui a plus de chances de tromper l’IDS. Conscient de cela, on arrive à la conclusion que proposer une nouvelle règle pour chaque nouvelle variante est une solution ardue à mettre en œuvre. L’une des solutions plausibles pour lutter contre ce phénomène serait de pouvoir définir des règles évolutives. Par règle évolutive on entend une règle non figée, capable de s’adapter aux changements mineurs apportés par la variante de l’attaque afin d’identifier plusieurs variantes d’une même attaque ; une règle qui reconnaît le comportement ou la structure générale d’une attaque et qui est capable de l’identifier sous diverses formes et artifices. Avec la notion de variantes d’attaques, on peut se retrouver rapidement avec une grande base de données de règles à satisfaire. De ce fait, il est préférable de privilégier l’écriture de règles qui couvrent plusieurs cas de figure. Par exemple, cela peut se faire en permettant l’usage d’opérateurs de combinaison d’événements [11] pour la description des scénarios d’attaques. Une autre alternative serait de combiner les parties communes des règles et ainsi former une sorte d’arbre ou de graphe de règles ayant plusieurs points d’entrées et plusieurs points terminaux. On retrouve cette dernière approche dans la gestion des règles Snort (voir l’organisation des règles Snort à la figure1.6). Remarquez qu’il est indispensable d’automatiser ce processus afin de simplifier la rédaction de nouvelles règles.

La gestion de la cohérence de la base de règles a elle aussi son lot de défis. En effet, il faudra s’assurer que les règles ne s’opposent pas, qu’elles ne se répètent pas, qu’une règle ne bloque pas la progression d’une autre en supprimant par exemple un événement que ce dernier attendait, etc. La gestion des conflits entre les règles doit aussi être faite de manière automatique si l’on souhaite que la rédaction de nouvelles règles se fasse sans contraintes.

Enfin, il faut trouver des solutions pour automatiser l’apprentissage des nouveaux compor- tements et la création automatique de nouvelles règles. Permettre à l’IDS d’apprendre de nouveaux comportements permettra de mieux lutter contre les variantes d’attaques. Il faut automatiser la recherche et l’édition de nouvelles variantes de règles après la détection d’une attaque. Pour ce faire, on peut se baser sur les similitudes avec les signatures connues. Pour les variantes d’attaques, la recherche de variantes peut se faire en comparant la trace avec les signatures dont nous disposons déjà afin de trouver des similitudes. Par exemple, une signa- ture respectée à soixante-quinze pour cent (75%) peut impliquer la présence d’une variante. Il faudra souligner qu’avec une stratégie de ce type, il existe un risque non négligeable de faux positifs.

2.1.1 Vérification de modèles (Model checking )

Les méthodes formelles offrent deux usages majeurs : la spécification et la vérification. La spécification permet de définir un langage de description de menaces et la vérification offre la possibilité d’effectuer de manière exhaustive des vérifications sur le respect de certaines propriétés. En ce qui concerne la vérification de propriétés, on peut identifier deux catégories : une qui utilise une sémantique statique et une qui utilise une sémantique dynamique [17]. L’usage d’une sémantique statique permet de vérifier des propriétés sur un système avant son exécution. Principalement utilisée pour l’analyse statique de programmes, elle permet de s’assurer du bon typage des expressions et de l’usage correct des opérateurs ; et aussi de valider des propriétés sur tous les chemins d’exécution possible d’un programme. Pour ce faire, un programme est traduit en un ensemble de règles ; puis les propriétés à vérifier sont appliquées à cet ensemble de règles afin d’examiner si elles demeurent valides.

En contre partie, le fait que la vérification se fasse sans l’exécution du système implique qu’on ne dispose pas de valeurs à associer aux variables. La vérification se fait de manière symbolique, idéal pour la validation de typage d’expressions et de programmes. Par exemple, pour une fonction qui fait une division de deux valeurs données, on peut s’assurer que les valeurs qu’elle reçoit sont toujours des entiers en faisant valider cette propriété et ainsi avoir la certitude qu’elle ne recevra pas un autre type comme paramètre. Cet exemple permet aussi de montrer que l’usage exclusif de l’analyse statique n’est pas une solution parfaite. Pour s’assurer de l’absence d’une division par zéro, on est obligé d’avoir une exécution dynamique de la fonction afin de s’assurer que la valeur du diviseur est différente de zéro. La propriété à

faire valider par le système devra s’exprimer de la sorte : si la fonction de division est invoquée, alors le dénominateur utilisé est différent de zero. Nous verrons dans les sections à venir qu’une expression du type σ(i) ⊧ (p ÷ r) → (r ≠ 0) peut nous permettre d’exprimer des propriétés de ce type.

Cette vérification des propriétés porte le nom de vérification de modèles (model checking) [17]. Le model checking permet de vérifier si un modèle σ, pour un état i défini, respecte une propriété φ énoncée (σ(i) ⊧ φ) et vice versa selon le sens de lecture. La notation σ(i) ⊧ φ est utilisée. Le mécanisme de vérification utilisé est trivial. Il consiste à parcourir chaque état ou transition du modèle et de vérifier si la propriété φ y est toujours valide. Cette vérification se termine une fois tous les états du modèle validés.

La combinaison des vérifications statiques et dynamiques permet un résultat optimal. Les expressions énoncées sont validées de manière statique, puis dynamiquement on vérifie si les propriétés qu’elles représentent sont respectées par le modèle.

L’usage du model checking donne la certitude du respect de nos propriétés si elles sont conformes au modèle. Par contre, la vérification étant faite sur un modèle dynamique, elle représente une exécution, un chemin possible parmi un ensemble de possibilités. Alors, la va- lidité des propriétés n’est vraie que pour cette exécution. À cause de cela, il est nécessaire d’effectuer les mêmes vérifications à chaque nouvelle exécution ; contrairement à une analyse statique qui elle reste valide tant que le modèle ne subit pas de changement.

Documents relatifs