Niveau :      
Résumé : kill -9 $$ && ...

Lors d'un recent article je vous expliquais qu'on peut faire disparaître son propre historique shell. Malheureusement, il reste une trace de votre connexion dans le fichier /var/log/wtmp lisible par la commande last.

On m'a demandé comment y remédier, et c'est ce que nous allons voir. Attention, seul root peut faire ceci, si vous le faites, c'est donc que la machine vous appartient ;-)

Étude de fichier

Tout d'abord étudions le format de ce fichier. C'est un fichier binaire dont chaque entrée correspond à une structure bien décrite dans man 5 utmp. Pour mieux la comprendre nous allons écrire un petit programme en C pour lire le fichier. Nous comparerons sa sortie à la commande last.

#include <utmp.h>
#include <stdio.h>
#include <string.h>

// Traite une ligne de wtmp
int process_entry(FILE* fd)
{
        struct utmp wtmp;
        int result;
        time_t tmp;

        // lecture d'une entree
        result = fread(&wtmp, sizeof(struct utmp), 1, fd);
        if(result == 0)
                return result;

        // on affiche une entree
        tmp = wtmp.ut_time;
        printf("type=%i, pid=%i, device=%s, tty=%s, user=%s, host=%s, time=%s",
                wtmp.ut_type, wtmp.ut_pid, wtmp.ut_line,
                wtmp.ut_id, wtmp.ut_user, wtmp.ut_host,
                ctime(&tmp) );

        // fin
        return result;
}

// lit et traite tout le fichier wtmp
int main()
{
        FILE *fd;
        // on ouvre le ficheir qui va bien
        fd = fopen(_PATH_WTMP,"r");
        // on traite le tout
        while(process_entry(fd)) ;
        // fin
        fclose(fd);
        return 0;
}

Modification du fichier

Voilà, vous avez toutes les informations qui se trouvent dans le fichier. Nous allons nous intéresser aux entrées de type 7 et 8. Selon man 5 utmp, le type 7 correspond à un login et le type 8 à un logout. La lecture du source de la commande last (apt-get source sysvinit-utils dans src/last.c pour ceux qui cherchent) nous apprend que last fait correspondre l'une à l'autre pour afficher ses entrées. Et il affiches les types 7 sans type 8 comme "still logged in". Par conséquent, si on transforme un type 7 en type 8, last ne pourra pas faire de correspondance et n'affichera rien.

C'est ce que fait le code suivant :

#include <utmp.h>
#include <stdio.h>
#include <string.h>

#define FILTER_PID 4070
#define FILTER_TTY "pts/0"

// Traite une ligne de wtmp
int process_entry(FILE* fd)
{
        struct utmp wtmp;
        int result;
        time_t tmp;

        // lecture d'une entrees
        result = fread(&wtmp, sizeof(struct utmp), 1, fd);
        if(result == 0)
                return result;

        // on ne garde que les login
        if(wtmp.ut_type != USER_PROCESS )
                return result;

        // on grille l'entree qui nous intéresse
        if(wtmp.ut_pid == FILTER_PID && strcmp(wtmp.ut_line,FILTER_TTY) == 0)
        {
                // on recule pour mieux ecrire
                fseek(fd, -sizeof(struct utmp), SEEK_CUR);

                // on reecrit l'histoire
                wtmp.ut_type = DEAD_PROCESS;
                fwrite(&wtmp, sizeof(struct utmp), 1, fd);
        }

        // fin
        return result;
}

// lit et traite tout le fichier wtmp
int main()
{
        FILE *fd;
        // on ouvre le ficheir qui va bien
        fd = fopen(_PATH_WTMP,"r+");
        // on traite le tout
        while(process_entry(fd)) ;
        // fin
        fclose(fd);
        return 0;
}

La ligne a supprimer est codée en dur avec les paramètres PID et TTY, mais rien ne vous empêche de modifier le code pour les passer en paramètre et pour être plus pratique. En attendant, vous pouvez à partir du résultat du code précédent remplir les 2 constantes FILTER_PID et FILTER_TTY pour éliminer l'entrée qui vous concerne.

Attention, ce code-ci doit être lancé en root.

Et voila ! Maintenant tapez last, puis ./a.out puis re last et voyez votre ligne de login qui a disparu !

Furtivité

N'oubliez pas une dernière chose, vous n'êtes pas pour autant totalement furtif. Il reste des traces dans /var/run/utmp (au même format, même astuce :-) que ne lit pas last par défaut (last -f /var/log/utmp), lesquelles sont effacées à chaque reboot. Il reste aussi éventuellement des traces de vos erreurs de login dans /var/log/btmp (commande lastb), au même format.

De plus, nous n'avons fait que berner la commande last, vos logs sont encore dans le fichier. Pour une furtivité plus grande, il faudrait décaler toutes les entrées pour supprimer totalement l'entrée. Et lorsque vous vous déconnecterez, une entrée de logout sera écrite dans ce fichier. Vous ne pourrez l'empêcher, car si vous tuez le processus qui écrit cette ligne (l'application qui a lancé votre shell), init s'en chargera.

Et enfin, il reste des traces de votre login dans /var/log/auth.log et éventuellement dans /var/log/syslog si vous êtes connecté en ssh. Mais cela reste du texte plus simple à éditer.