La première moitié de l'année 2009 a été marquée par 3 familles de malware : Conficker, Virut et Neeris. Ce dernier est un ver se propageant comme Conficker via la vulnérabilité
MS08-067. Il est loin d'avoir eu la visibilité médiatique de Conficker, mais il a bel et bien infecté de nombreuses entreprises, y compris françaises. Nous allons décrire dans ce billet différentes méthodes pour tenter de repérer le premier système infecté dans un parc de machines, autrement dit la source de l'infection.
On part du principe que les machines sont synchronisées avec un serveur de temps ; la comparaison du temps entre elles a donc du sens et le problème revient ainsi à déterminer la date d'infection de chaque poste. Cela s'effectue à partir des modifications opérées par le malware sur le poste, principalement sur le système de fichiers, les événements et la base de registre (NB : un filtre "Category is Write" dans Process Monitor est un bon point de départ).
Système de fichiers
Le ver commence par se recopier dans C:\WINDOWS\system sous un nom choisi parmi une liste prédéfinie, netmon.exe dans notre cas. Les attributs NTFS fournissent l'heure de création du fichier et donc une heure d'infection (NB : on utilise d'abord fls pour connaitre l'index dans la MFT associé à ce fichier, puis istat pour obtenir l'information voulue) :
$ fdisk -ul neeris_disque.raw
neeris_disque.raw1 * 63 8369864 4184901 7 HPFS/NTFS
$ fls -o 63 -r neeris_disque.raw | grep netmon
++ r/r 9433-128-3: netmon.exe
$ istat -o 63 neeris_disque.raw 9433
$STANDARD_INFORMATION Attribute Values:
Created: Mon Aug 31 18:02:33 2009
File Modified: Mon Aug 31 18:02:32 2009
MFT Modified: Tue Sep 1 06:36:38 2009
Accessed: Mon Aug 31 18:02:33 2009
De même, le ver droppe une rootkit dans C:\WINDOWS\system32\drivers\sysdrv32.sys. Les propriétés de ce fichier nous donnent aussi une heure d'infection :
$ fls -o 63 -r neeris_disque.raw | grep sysdrv32.sys
+++ r/r 9437-128-3: sysdrv32.sys
$ istat -o 63 neeris_disque.raw 9437
$STANDARD_INFORMATION Attribute Values:
Created: Mon Aug 31 18:02:36 2009
File Modified: Mon Aug 31 18:02:36 2009
MFT Modified: Mon Aug 31 18:02:36 2009
Accessed: Mon Aug 31 18:02:36 2009
On remarque que l'heure fournie n'est pas identique à la précédente, montrant que cette action a eu lieu peu de temps après.
Une autre option s'offre à nous : les fichiers de prefetch. Le prefetch est une fonctionnalité du Memory Manager de Windows destinée à optimiser le chargement du système et des applications, activée par défaut et configurable via la clé HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\PrefetchParameters (cf chapitre 7 du livre Windows Internals pour les détails). Comme toute application qui se respecte, le malware est affecté par ce mécanisme et Windows va donc créer des fichiers correspondant dans C:\WINDOWS\Prefetch :
$ fls -o 63 -r neeris_disque.raw | grep NETMON
++ r/r 9436-128-4: NETMON.EXE-0D87B210.pf
$ istat -o 63 neeris_disque.raw 9436
$STANDARD_INFORMATION Attribute Values:
Created: Mon Aug 31 18:02:34 2009
File Modified: Mon Aug 31 18:02:44 2009
MFT Modified: Mon Aug 31 18:02:44 2009
Accessed: Mon Aug 31 18:02:34 2009
En générant la timeline du disque dur (la capture ci-dessous provient de PTK), on observe qu'à l'heure déterminée ci-dessus, des fichiers Internet temporaires sont écrits sous le compte NetworkService. Ceci est typique de l'exploitation réussie d'une vulnérabilité dans un service réseau Windows :

Tous les fichiers et répertoires ci-dessus, pour peu qu'ils aient un nom ne dépendant pas du système, peuvent donc potentiellement servir à déterminer la date d'infection.
Événements
La rootkit est chargée via le Service Control Manager de Windows et cela génère un événement 7035 dans le journal Système, nous fournissant une date d'infection :

La recherche est rendue triviale par le fait que cette rootkit utilise le nom constant Play Port I/O Driver. Le seul problème qui pourrait se poser pour cette méthode serait un écrasement des événements. Cependant, on remarque que l'heure donnée est relativement tardive (10s après le drop de l'exécutable principal).
Base de registre
Plusieurs modifications ont lieu dans la base de registre :
- ajout d'une valeur dans la clé HKLM\SOFTWARE\CurrentVersion\Run sous un nom choisi parmi une liste prédéfinie (ici netmon), pointant vers la copie du ver présente dans C:\WINDOWS\system
- ajout d'une exception au pare-feu (nouvelle valeur dans la clé HKLM\SYSTEM\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy\StandardProfile\AuthorizedApplications\List)
- rootkit noyau (nouvelle clé HKLM\SYSTEM\CurrentControlSet\Services\sysdrv32)
- lancement du malware même en mode sans échec avec ou sans support réseau (nouvelles clés HKLM\SYSTEM\CurrentControlSet\Control\SafeBoot\{Minimal,Network}\netmon)
Dans la base de registre Windows, des dates et heures sont bien enregistrées, mais elles concernent les clés et non les valeurs. Le champ LastWriteTime est en effet stocké dans une structure _CM_KEY_CONTROL_BLOCK :
lkd> dt nt!_CM_KEY_CONTROL_BLOCK
+0x038 KcbLastWriteTime : _LARGE_INTEGER
Idéalement, on cherche donc une clé créée spécifiquement par le malware dont on va pouvoir extraire le champ LastWriteTime contenant l'heure de dernière modification, et non une nouvelle valeur dans une clé existante. Les deuxième et troisième points ci-dessus correspondent précisément à notre attente. On peut alors extraire manuellement ces date et heure depuis regedit en exportant la clé de registre au format texte :

La procédure peut s'automatiser via la fonction RegQueryInfoKey qui nous retourne l'information voulue dans son paramètre lpftLastWriteTime.
Une autre méthode envisageable consiste à analyser la RAM. La tâche est rendue facile par la récente possibilité de lancer les plugins RegRipper sur une image de la RAM via Volatility. Concrètement, on commence par utiliser le plugin hivelist afin de lister les ruches présentes dans le dump de RAM :
$ ./volatility hivelist -f neeris_ram.raw
Address Name
0xe17ff008 \Documents and Settings\<user>\Local Settings\Application Data\Microsoft\Windows\UsrClass.dat
0xe17f7b60 \Documents and Settings\<user>\NTUSER.DAT
0xe13112b0 \WINDOWS\system32\config\software
0xe1311b60 \WINDOWS\system32\config\default
0xe1309008 \WINDOWS\system32\config\SECURITY
0xe1309758 \WINDOWS\system32\config\SAM
0xe101b008 \WINDOWS\system32\config\system
On peut ensuite lancer notre plugin sur les ruches ainsi trouvées en mémoire, et obtenir l'information voulue, par exemple depuis les clés de la ruche SYSTEM :
$ perl rip.pl -p neeris_lexsi -r neeris_ram.raw@0xe101b008
ControlSet001\Services\sysdrv32
[Mon Aug 31 16:02:41 2009]
ControlSet001\Control\Safeboot\Minimal\netmon
[Mon Aug 31 16:02:33 2009]
ControlSet001\Control\Safeboot\Network\netmon
[Mon Aug 31 16:02:33 2009]
ControlSet001\Services\SharedAccess\Parameters\FirewallPolicy\StandardProfile\AuthorizedApplications\List
[Tue Sep 1 04:36:38 2009]
Ici, l'heure donnée ne tient pas compte du décalage horaire et on retrouve bien le 18:02 du 31/08/2009 (il s'agit d'un système à l'heure de Paris). L'heure de la clé sysdrv32 correspond à celle trouvée via l'event log. En revanche, la clé AuthorizedApplications\List a été modifiée après coup (cette clé est modifiée et non créée par le malware) et ne donne donc pas une heure correcte.
Ce plugin RegRipper est disponible en téléchargement (à noter qu'il n'est pas exhaustif au niveau des clés testées, il ne s'agit que d'une preuve de concept).
Si ces clés ont été supprimées par l'antivirus, il reste toujours possible d'appliquer la méthode du LastWriteTime non pas sur une clé créée par le malware, mais sur une clé dans laquelle il a ajouté une valeur, comme par exemple HKLM\SOFTWARE\CurrentVersion\Run ou HKLM\SYSTEM\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy\StandardProfile\AuthorizedApplications\List. On est sûr d'obtenir un résultat, mais pas forcément celui attendu car un logiciel légitime a pu aussi ajouter des valeurs dans ces clés et ainsi modifier leur date (voir l'exemple ci-dessus sur la RAM). Cela dit, si les deux dates coïncident, il y a de fortes chances qu'il s'agisse bien de la date réelle d'infection.
Processus
Toujours par analyse de la RAM, il est aussi possible de déterminer l'heure du lancement du processus netmon.exe via le plugin psscan2 de Volatility (NB : un simple pslist ne va pas marcher en raison de la rootkit qui cache ce processus) :
$ ./volatility psscan2 -f neeris_ram.raw
PID PPID Time created Time exited Offset PDB Remarks
1352 556 Mon Aug 31 11:07:23 2009 0x00f79228 0x00f66000 spoolsv.exe
916 556 Mon Aug 31 11:06:55 2009 0x0102f6b0 0x06a00000 svchost.exe
852 556 Mon Aug 31 11:06:53 2009 0x0103b020 0x0643a000 svchost.exe
772 556 Mon Aug 31 11:06:48 2009 0x0104da90 0x05c50000 svchost.exe
568 484 Mon Aug 31 11:06:41 2009 0x0106b938 0x057d7000 lsass.exe
556 484 Mon Aug 31 11:06:41 2009 0x0106d090 0x057cb000 services.exe
1664 1608 Mon Aug 31 16:02:34 2009 0x0107d670 0x06f26000 netmon.exe
356 4 Mon Aug 31 11:06:34 2009 0x0108c4d0 0x047dc000 smss.exe
460 356 Mon Aug 31 11:06:37 2009 0x010b5488 0x052ae000 csrss.exe
484 356 Mon Aug 31 11:06:38 2009 0x011b7020 0x05473000 winlogon.exe
4 0 0x011f29c8 0x00039000 System
1964 556 Mon Aug 31 11:08:13 2009 0x0604cb00 0x001c4000 alg.exe
1924 556 Mon Aug 31 11:08:09 2009 0x060c8020 0x024a0000 svchost.exe
1036 556 Mon Aug 31 11:07:06 2009 0x078e9508 0x0791e000 svchost.exe
1208 1140 Mon Aug 31 11:07:16 2009 0x07d29020 0x07de8000 explorer.exe
1204 1208 Mon Aug 31 11:19:46 2009 0x07d92820 0x0554a000 cmd.exe
Modulo les 2 heures de décalage horaire, on retrouve bien l'heure et la date déjà déterminées ci-dessus.
Connexions réseau
Pour finir, les sockets possèdent également une date de création. En listant celles associées à notre processus (ici celui de PID 1664), on obtient les connexions correspondant aux tentatives d'exploitation de la vulnérabilité MS08-067 sur des systèmes distants ; la première de ces dates nous donne donc la première tentative, et la date correspond bien si on prend en compte le décalage horaire :
$ ./volatility sockets -f neeris_ram.raw | grep 1664
Pid Port Proto Create Time
1664 4637 6 Tue Sep 01 04:39:01 2009
1664 4641 6 Tue Sep 01 04:39:02 2009
1664 4645 6 Tue Sep 01 04:39:02 2009
1664 1664 6 Tue Sep 01 01:10:06 2009
1664 2866 6 Mon Aug 31 22:01:10 2009
1664 4634 6 Tue Sep 01 04:39:00 2009
1664 4638 6 Tue Sep 01 04:39:02 2009
1664 3502 6 Tue Sep 01 01:52:38 2009
1664 4642 6 Tue Sep 01 04:39:02 2009
1664 4646 6 Tue Sep 01 04:39:02 2009
1664 3762 6 Tue Sep 01 01:53:03 2009
1664 14575 6 Mon Aug 31 16:02:36 2009
1664 3495 6 Tue Sep 01 01:52:37 2009
1664 1669 6 Tue Sep 01 01:10:07 2009
1664 4635 6 Tue Sep 01 04:39:00 2009
1664 4639 6 Tue Sep 01 04:39:02 2009
Conclusion
Nous venons de décrire différentes manières d'obtenir la date d'infection d'un système par le ver Neeris, par analyse du disque dur et de la mémoire vive. Ces méthodes ont chacune leurs avantages et inconvénients mais leur efficacité peut surtout être mise à mal par l'antivirus qui, lors de la suppression du malware, pourrait également supprimer les "preuves" de son ancienne présence. L'analyse de la RAM peut alors s'avérer précieuse, à condition de ne pas arriver trop tard...