• Aucun résultat trouvé

Analyse des virus furtifs

6.3.11 Contrôle de modèle

Le contrôle de modèle consiste à faire la comparaison entre deux valeurs d’un paramètre qui est représentatif du modèle statistique du système sous-jacent. La distribution d’un système sain DSys et la distribution d’un système corrompu DStealth sont discriminées par utilisation d’un tel estimateur.

E. Filiol propose dans [Fil07c, Fil07a] une formalisation du problème de détection des programmes furtifs dans le cadre de la théorie de l’information. Il exploite le parallèle qui peut être fait entre les techniques de furtivités et les techniques stéganographiques pour définir la sécurité d’un système furtif contre une attaque passive :

5Advanced Configuration and Power Interface, successeur deAPM(Advanced Power Management) 6Peripheral Component Interconnected

Définition 6.3.1 (Sécurité d’un système furtif [Fil07a]) Un système furtif est dit ε-sûr vis-à-vis des attaques passives si et seulement si :

dKL(pDSys||pDStealth) =

X

y

pDSys(y) log

pDSys(y)

pDStealth(y)

≤ ε.

Remarquons que l’utilisation de la distance de Kullback-Leibler entre les deux distributions permet de capturer toutes les dépendances entre les deux distributions, pas seulement par exemple une dépendance du second ordre, telle que capturée par la covariance. Elle définit l’entropie relative entre les deux distributions.

Lorsque ε est nul, le système furtif est dit parfaitement (ou inconditionnellement) sûr. Cela implique que la détection du système furtif est impossible, i.e. que même avec des ressources illimitées en temps et en espace de calcul, il est impossible de distinguer les distributions DStealth et DSys et donc de détecter le système furtif. Il est peu probable que les méthodes classiques de furtivités puissent appartenir à cette classe de système, sans avoir recours à des mécanismes cryptographiques ou stéganographiques adaptés.

Lorsque l’adversaire est un algorithme déterministe s’exécutant en temps polynômial, le système furtif est dit non- sûr.

Remarquons que cette définition ne s’applique qu’au contexte d’attaques passives, c’est-à-dire au cas où le système d’extraction d’information et plus généralement l’ensemble des composants du moteur de détection ne modifient pas le système analysé (l’analyse ne doit en particulier pas modifier les paramètres caractérisant la distribution DSys). Si l’on considère les méthodes d’analyse actives (l’analyse modifie la distribution DSys et éventuellement la distribution DStealth), nous devons modifier en conséquence la définition d’un système furtif (en remplaçant les mesures de probabilités PX par des mesures de probabilités PX|Y, où X désigne la v.a. régie par la loi mesurée sur

le système et Y désigne la v.a. correspondant aux modifications induites par la présence de l’outil d’analyse sur le système).

Les méthodes de contrôle de modèle telles que celles proposées dans PatchFinder [Rut05a] pour détecter les hooks d’API ou dans [Lau08] pour détecter la présence d’un hyperviseur de machine virtuelle s’appuient sur un moteur de détection actif. Ces méthodes de détection peuvent donc être contournées en manipulant l’environnement d’exé- cution du moteur de détection et en simulant les tests statistiques. Pour éviter cet ecueil, la fonction de détection doit s’exécuter depuis l’extérieur du système, de manière à avoir une distribution DSys qui ne peut pas être simulée par le programme furtif, puisqu’il ne peut pas y accéder.

J’étudie dans la suite de cette section une approche générique pour spécifier une méthode de détection qui tente de décider si un système donné, observé depuis l’extérieur (par utilisation de méthodes forensiques) est corrompu par une infection informatique furtive. J’illustre cette approche par la transposition des techniques de détection décrites dans [Rut05a] et [Lau08] dans le contexte d’une analyse passive.

PatchFinder [Rut05a] tente de détecter les hooks d’API en comparant le nombre d’instructions exécutées durant l’invocation de plusieurs fonctions d’API avec une référence saine. L’estimateur choisi par ce test statistique de détection est donc le nombre moyen m d’instructions exécutées durant l’invocation d’une fonction d’API donnée. Cet estimateur décrit D1.

Notons xs(t) le nombre d’instructions CPU exécutées durant l’appel système s sur le système sain et x0s(t) le

nombre d’instructions CPU exécutées durant le même appel système s sur un système inconnu.

Le principe de PatchFinder repose sur la comparaison de ces deux valeurs. Si la différence est trop élevée, le système est considéré comme étant compromis par un rootkit. Voyons comment cette approche peut être transposée dans un contexte extérieur à la matrice (analyse passive) : nous définissons les hypothèses nulles et alternatives :



H0: l’appel système s n’est pas hooké

H1: l’appel système s est hooké

Pour t allant de 1 à n, nous exécutons un code en mémoire virtuelle qui appelle s. Ensuite, nous calculons le nombre moyen d’instructions CPU m.

Nous notons m0le nombre moyen d’instructions exécutées durant l’invocation de la fonction d’API s sur le système

sain et m le même calcul sur le système inconnu.

En choisissant l’estimateur m, nous pouvons définir un test bilatéral comme suit : 

H0: m = m0

H1: m 6= m0

En effet, si un hook est installé sur le système pour la fonction s, le nombre moyen d’instructions CPU m est soit plus élevé que m0(si le hook instrumente la fonction s en ajoutant des fonctionnalités) ou moins élevé que m0(dans

le cas où le hook inhibe la fonction s).

Étant donné un taux de faux positifs acceptable [Fil07c, FJ07], si |m − m0| est supérieur à un seuil de déci-

sion fixé, nous considérons que la fonction s est hookée (et donc que le système cible est corrompu).

En analysant le système depuis l’extérieur, nos mesures sont effectuées de manière complètement furtive. La fonction de détection est donc plus difficile à contourner. Notre échantillonnage peut être effectué en exécutant le code qui appelle s depuis une zone mémoire aléatoire. En prenant n mesures, nous sommes capables d’estimer la distribution de la loi de probabilité sous l’hypothèse nulle H0plus précisément, et donc de détecter (avec un taux de faux positifs

contrôlé) toute variation suspecte vis-à-vis de cette loi.

C. Lauradoux propose dans [Lau08] une méthode de détection des rootkits VMBR (i.e. fondés sur l’utilisation d’un hyperviseur de machine virtuelle). Il propose un estimateur permettant de capturer une dépendance d’ordre 2 (covariance) en mesurant les écarts à la régularité du temps d’exécution d’un morceau de code. Il mène ses expéri- mentations en modifiant l’algorithme d’ordonnancement sous Linux. Je propose de reproduire ces expérimentations sous Windows. Considérons le morceau de code suivant :

int i=sampling_size; _asm {

rdtsc

mov dword ptr [start], eax mov dword ptr [start+4], edx }; while(i>0) { i--; _asm { rdtsc

mov dword ptr [end], eax mov dword ptr [end+4], edx };

data[i]=end-start; start=end;

}

Notons N la taille de notre échantillon (sampling_size dans le morceau de code). Ce programme récupère une séquence de mesures Xi = ti− ti−1, i = 1, . . . , N calculées à partir des valeurs ti, i = 0, . . . , N du registre TSC

(Time Stamp Counter). Il a observé que le spectre d’autocorrelation :

{cov(k) = 1 N N −k X i=1 (Xi− X)(Xi+k− X) | k = 1, . . . , K}.

Fig. 6.2 – Spectre d’auto-corrélation

grandes variations sont provoquées par les interruptions. Effectuons à présent la mesure en masquant les interrup- tions (le morceau de code précédent est balisé par les instructions _asm cli et _asm sti). Nous obtenons le spectre d’autocorrélation représenté sur la figure6.3. Remarquons que (en mode protégé) le code doit s’exécuter en mode noyau (les instructions _asm cli et _asm sti sont privilégiées. Windows NT positionne l’IOPL à 0 donc seules les applications s’exécutant en mode noyau peuvent exécuter les instructions cli/sti). Nous pouvons observer que lorsque nous ignorons les interruptions, l’autocorrélogramme montre des phénomènes quasi-périodiques. À l’in- verse, lorsque les interruptions sont prises en compte, l’autocorrélogramme n’indique pas de corrélations particulières

Si nous effectuons les mêmes mesures dans un hyperviseur de VM (ici VMWare), nous obtenons les spectres d’auto- corrélation représentés sur les figures6.4et 6.5respectivement (la figure6.5représente l’exécution du morceau de code lorsque les interruptions sont masquées). Nous pouvons observer, en comparant les figures 6.3 et 6.5, que nous ne retrouvons pas les mêmes corrélations. Lorsque nous modifions le mode d’exécution sur la machine virtuelle (changement d’algorithme d’ordonnancement ou désactivation des interruptions), cela n’affecte pas l’exécution des processus sur le système hôte. Le spectre d’autocorrélation nous permet donc de détecter une activité anormale. Nous pouvons observer en outre que lorsque les interruptions sont masquées dans une VM, le processus stochastique (Xi) apparaît comme un bruit blanc : l’autocorrelation est (presque) nulle partout sauf à l’origine. Ce n’est pas du

tout le cas lorsque les interruptions sont masquées sur le système hôte.

Définition 6.3.2 Un processus stochastique (Xi) est qualifié de bruit blanc si :

– E[Xi] = 0

– E[X2 i] = σ2

– ∀i 6= j, E[XiXj] = 0

Nous pouvons donc conjecturer que cette méthode de détection peut être modélisée par un test statistique de blan- cheur, tel que le test du Portemanteau.

Fig. 6.3 – Spectre d’auto-corrélation avec masquage des interruptions

rence réside dans l’accès au registre TSC. Si ce registre de 64 bits ne peut pas être modifié par un rootkit, les registres eax et edx contenant le résultat de l’exécution de l’instruction rdtsc peuvent être modifiés/filtrés par un hyperviseur. La lecture directe du regsitre CPU depuis l’extérieur de la matrice permet d’éluder ce problème. Comme pour l’estimateur de PatchFinder, il est possible de randomiser les contrôles et de les itérer pour améliorer la précision de l’estimation.

Je pense que l’utilisation d’un CPU logiciel permet d’appliquer de manière sûre les méthodes de détection de rootkit par contrôle de modèle. Les algorithmes de détection connus se transposent sans difficulté dans ce contexte. Une telle approche pourrait être mise en oeuvre par un composant matériel spécialisé. Des systèmes de détec- tion matériels, comme Copilot [PJFMA04], ont été proposés mais ils sont aujourd’hui fondés exclusivement sur le contrôle d’intégrité et n’utilisent pas suffisamment l’omniscience du point de vue matériel. L’analyse des canaux cachés (temps, stockage) induis par la présence d’un rootkit sur le système peut pourtant être menée de manière fiable depuis l’extérieur de la matrice et fournit des méthodes de détection plus génériques que l’exploitation d’un problème structurel du jeu d’instruction CPU, susceptible d’être corrigé (masquage du temps, par exemple, dans les CPU Intel IVT et AMD Pacifica).

6.4

Evaluation