Un vaccin contre Conficker.C
Par Sylvain SARMEJEANNE, vendredi 20 mars 2009 à 14:01 :: General :: #289 :: rss
En Biologie, utiliser un vaccin consiste à inoculer une version rendue inoffensive d'un agent infectieux, de sorte qu'au moment de l'infection réelle, le corps soit déjà prêt à réagir de manière efficace et ne tombe ainsi pas malade. Nous allons appliquer ce principe au virus, cette fois-ci informatique, Conficker.C et à ses mutexes. Après avoir précédemment montré qu'il était possible de désinfecter un système sans autre outil qu'un simple script VBS, nous allons ainsi présenter une méthode pour bloquer les effets néfastes du ver sur un système pourtant non patché, sans antivirus, et ayant les partages administratifs activés.
Pour observer les mutexes créés par Conficker.C, nous allons utiliser notre plugin winobj.py pour le framework Volatility. Dans une sandbox, dumpons la RAM, exécutons le ver, et dumpons la RAM à nouveau. Winobj.py nous permet de parcourir l'Object Manager de Windows, et en particulier les objets de type Mutant (équivalent des mutexes au niveau noyau) présents dans \BaseNamedObjects :
$ ./volatility winobj -f ramdump_avant -d \\BaseNamedObjects -o Mutant > mutex_avant $ ./volatility winobj -f ramdump_apres -d \\BaseNamedObjects -o Mutant > mutex_apres
Observons les différences :
$ diff mutex_avant mutex_apres 11a11 > \BaseNamedObjects\612924626-99\ Mutant 80d1c658 18a18 > \BaseNamedObjects\612924626-7\ Mutant 80d7d6a8 19a20 > \BaseNamedObjects\lmgdvhkzvzqxej\ Mutant 80d52390 21a23 > \BaseNamedObjects\xafjljtmlfuwo\ Mutant 80d06700
Conficker.C crée donc 4 mutexes :
- deux mutexes ne contenant que des lettres
- deux mutexes de la forme chiffres-99 et chiffres-7 respectivement
Analysons maintenant la logique du ver pour mieux comprendre le rôle de ces mutexes. Le nom des deux premiers est généré à partir du PID courant récupéré via GetCurrentProcessId ; inutile donc de creuser dans cette voie, ces mutexes ne peuvent pas nous être utiles :

En observant la suite du déroulement de l'exécution, on remarque la présence d'un ExitProcess situé peu après la création du mutex 612924626-99 (NB : le mutex 612924626-7 est créé juste avant) ; cette fois-ci, il s'agit probablement d'une bonne piste :

Juste après la demande de création de ce mutex, la fonction RtlGetLastWin32Error est appelée pour récupérer le code d'erreur, stocké dans une variable. Un peu plus bas, cette variable est comparée à 0xb7, correspondant au code d'erreur ERROR_ALREADY_EXISTS. En cas d'égalité (en clair si le mutex existe déjà ), le ver se termine immédiatement :

Reste maintenant à comprendre comment le nom du mutex est généré. Un peu plus haut dans le code, il récupère le nom de la machine avec la fonction GetComputerName :

La fonction sub_929fae est tout de suite appelée. A partir du nom de la machine, et après un certain nombre d'opérations arithmétiques simples dans deux boucles imbriquées, elle génère un entier :

Le ver utilise ensuite cet entier (dans notre cas 612924626) afin de générer les noms des mutexes via snprintf (NB : les suffixes -7 et -99 sont constants). Cet algorithme s'implémente en quelques lignes de C.
Au final, nous pouvons donc créer un petit exécutable qui va récupérer le nom de la machine, en déduire la valeur de l'entier, puis créer le mutex de la forme chiffres-99. Il peut par exemple être placé dans une clé Run pour assurer son exécution à chaque démarrage du système.
Une fois le système "vacciné" de la sorte, l'exécution de Conficker.C n'aura aucun impact néfaste sur le système.