Le weekend dernier, Scott Tenaglia, le directeur de la recherche chez Invincea, a expliqué que le laboratoire s’est lancé dans l’étude de ce logiciel malveillant pour en exposer les failles : « les attaquants exploitent souvent de failles dans les logiciels pour installer leurs outils sur les systèmes. Lorsque ces outils sont sur des dispositifs IdO, les choses deviennent plus compliquées parce que les attaquants ont accès à plus de dispositifs que nous. Alors pourquoi ne pas utiliser leur propre stratégie contre eux ? ». « C’est la première d’une série de publications qui va exposer les vulnérabilités de Mirai et montrer comment s’en servir pour stopper les attaques », a-t-il promis.
Pour commencer, il estime qu’il est important de comprendre comment Mirai initialise une attaque afin de comprendre les implications de l'exploitation des vulnérabilités dans le code d'attaque. Ci-dessous le code de la fonction attack_start() telle qu’écrite dans bot/attack.c :
Code C : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | void attack_start(int duration, ATTACK_VECTOR vector, uint8_t targs_len, struct attack_target *targs, uint8_t opts_len, struct attack_option *opts) { int pid1, pid2; pid1 = fork(); if (pid1 == -1 || pid1 > 0) return; pid2 = fork(); if (pid2 == -1) exit(0); else if (pid2 == 0) { sleep(duration); kill(getppid(), 9); exit(0); } else { int i; for (i = 0; i < methods_len; i++) { if (methods[i]->vector == vector) { #ifdef DEBUG printf("[attack] Starting attack...\n"); #endif methods[i]->func(targs_len, targs, opts_len, opts); break; } } //just bail if the function returns exit(0); } } |
Les lignes 5 à 7 font un fork d’un processus enfant qui sera responsable de l'attaque. Les lignes 9 à 16 font un fork d’un autre processus enfant qui va arrêter l'attaque après la durée spécifiée, simplement en la mettant en sommeil sur cette durée puis en terminant le processus parent lorsqu’il tente de s’exécuter à nouveau. Enfin, le processus d'attaque appelle le gestionnaire de fonction correcte pour l'attaque spécifiée (lignes 22 à 32), puis effectue un exit (ligne 35). Cela signifie que si le processus d'attaque se bloque, alors l'attaque s'arrêtera mais le bot lui-même restera fonctionnel.
Par la suite le chercheur indique avoir trouvé une vulnérabilité stack buffer overflow dans le code de l’attaque par inondation HTTP. Lorsque cette vulnérabilité est exploitée, elle va provoquer un « signal de violation de segmentation » (SIGSEGV, un signal envoyé à un processus lorsque celui-ci fait référence à une zone de mémoire invalide, par exemple parce qu'elle ne lui appartient pas. Une interruption est alors déclenchée et interrompt le programme). Le SIGSEGV va donc interrompre le processus et par conséquent arrêter l’attaque du bot. « La vulnérabilité du code est tributaire de la façon dont Mirai traite l'emplacement en-tête HTTP qui peut faire partie de la réponse HTTP envoyée depuis une requête d’inondation HTTP », explique-t-il. Elle réside dans la fonction attack_app_http () du bot / attack_app.c, et se présente comme suit :
Code C : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | int offset = util_stristr(generic_memes, ret, table_retrieve_val(TABLE_ATK_LOCATION_HDR, NULL)); if (generic_memes[offset] == ' ') offset++; int nl_off = util_memsearch(generic_memes + offset, ret - offset, "\r\n", 2); if (nl_off != -1) { char *loc_ptr = &(generic_memes[offset]); if (nl_off >= 2) nl_off -= 2; generic_memes[offset + nl_off] = 0; //increment it one so that it is length of the string excluding null char instead of 0-based offset nl_off++; if (util_memsearch(loc_ptr, nl_off, "http", 4) == 4) { //this is an absolute url, domain name change maybe? ii = 7; //http(s) if (loc_ptr[4] == 's') ii++; memmove(loc_ptr, loc_ptr + ii, nl_off - ii); |
Pour commencer, supposons que l’en-tête de l’emplacement est quelque chose de simple comme http://google.com\r\n.
Les lignes 1 à 3 du code ci-dessus cherchent l’emplacement de l'en-tête de l'emplacement et mette l’indice du début d l’URL (notamment le caractère “h”) dans la variable offset. Ensuite, les lignes 5 à 15 s’occupent de mettre l’index “\ r \ n” qui termine l’URL dans la variable nl_off. Tenagila précise qu’il est important de noter qu’il s’agit d’un index de base zéro (une façon de numérotage qui voudrait que le premier élément d’une séquence soit associé à “0” au lieu de “1”. L’élément initial dans ce cas est donc appelé “élément zéro” au lieu de “premier élément”) de l’URL et PAS du début de l’emplacement de l’en-tête ou du buffer generic_memes.
Dans la ligne 25, l’appel de memmove tente d’enlever le "http: //" de l'URL en déplaçant simplement ce qui vient après vers la gauche de 7 caractères. C’est la raison pour laquelle la variable ii est fixée à 7 sur la ligne 20. Dans le cas que nous étudions, nl_off vaut 18, ce qui signifie que le paramètre len de memmove est 11 (nl_off - ii, soit 18 - 7).
Code C : | Sélectionner tout |
memmove(loc_ptr, loc_ptr + 7, 11);
Ce qui contribue à déplacer “google.com” (une chaîne de 10 caractères plus un caractère de fin de chaîne) vers la gauche de 7 caractères. Cependant, si l’entête de location était http\r\n. Alors nl_off vaut 5, ce qui signifie que le paramètre lenvaut -2 (nl_off - ii, soit 5 - 7). Étant donné que le paramètre len est traité comme un entier non signé (à savoir de type size_t), alors -2 sera traité comme un entier positif très large, 0xFFFFFFFE. Par conséquent, memmove va inonder le buffer generic_memes et corrompre une bonne partie de la mémoire.
Pour vérifier leur supposition, les chercheurs se sont servi de trois machines virtuelles où Mirai a été déployé et le programme a effectivement reçu un SIGSEGV comme le montre le montre la capture d’écran ci-dessous.
« Ce simple “exploit” est un exemple de défense active contre un botnet IdO pouvant être utilisé par tout service d’atténuation d’attaque DDoS pour se défendre contre une attaque Mirai par inondation HTTP en temps réel », a conclu Tenaglia. Il prévient toutefois que « bien qu’il ne peut pas être utilisé pour enlever le bot d’un dispositif IdO, il peut être utilisé pour stopper l’attaque en provenance de ce dispositif ».
Il regrette néanmoins que cet exploit ne soit spécifique qu’aux attaques par inondation HTTP et n’aurait donc pas pu servir à défendre Dyn. Quoiqu’il en soit, d’autres publications dans ce sens sont attendues.
Mirai est l’une des plus dangereuses familles de botnets avec plus de 791 000 zombies à sa disposition et uniquement sur le port 23 d’après des statistiques de Qihoo 360.
Source : blog Invincea, Qihoo 360