le format de la chaîne de la vulnérabilité des printf
Pourquoi cette impression de la valeur de l'adresse mémoire à 0x08480110? Je ne suis pas sûr de savoir pourquoi il y a 5 %08x arguments - où est-ce que vous prenez la pile?
address = 0x08480110
address (encoded as 32 bit le string): "\x10\x01\x48\x08"
printf ("\x10\x01\x48\x08_%08x.%08x.%08x.%08x.%08x|%s|");
Cet exemple est pris à partir de la page 11 de ce document http://crypto.stanford.edu/cs155/papers/formatstring-1.2.pdf
OriginalL'auteur Vikas Yendluri | 2011-04-15
Vous devez vous connecter pour publier un commentaire.
Je pense que le papier fournit à ses
printf()
exemples dans une certaine confusion parce que les exemples d'utilisation des littéraux de chaîne pour les chaînes de format, et ceux-ci ne sont généralement pas permis le type de vulnérabilité décrite. La chaîne de format, de la vulnérabilité décrite ici dépend de la chaîne de format fourni par l'utilisateur.Donc l'exemple:
Pourraient être mieux présenté:
Depuis le
outstring
tableau est une automatique, le compilateur va probablement mettre sur la pile. Après la copie de l'entrée de l'utilisateur à l'outstring
tableau, ça va ressembler à ce qui suit comme des "mots" sur la pile (en supposant que little endian):Le compilateur va mettre d'autres éléments sur la pile comme il l'entend (les autres variables locales, enregistrées les registres, peu importe).
Lorsque le
printf()
appel est sur le point d'être faite, la pile pourrait ressembler à:Remarque que je suis complètement de la prise de ceux des entrées de haut - chaque compilateur utilisera la pile de différentes façons (donc une chaîne de format de la vulnérabilité doit être personnalisé conçu pour un scénario précis. En d'autres termes, vous n'aurez pas toujours l'utilisation de 5 factice spécificateurs de format comme dans cet exemple - que l'attaquant, vous aurez besoin de savoir combien de mannequins la vulnérabilité particulière aurait besoin.
D'appeler maintenant
printf()
, l'argument (l'adresse deoutstring
) est poussé sur la pile etprintf()
est appelé, de sorte que l'argument de la zone de la pile ressemble:Cependant, printf ne sais pas vraiment comment, de nombreux arguments ont été placés sur la pile pour cela, il va par les spécificateurs de format qu'il trouve dans la chaîne de format (le seul argument c'est " sûr " pour obtenir). Donc
printf()
obtient le format de l'argument de type string et commence à la traiter. Quand il arrive à la 1ère "%08x" qui correspondent à la "sauvé EDI" dans mon exemple, alors la prochaine "%08x" affichera laenregistré ECX " et ainsi de suite. Ainsi, le "%08x" les spécificateurs de format sont juste de manger des données sur la pile jusqu'à ce qu'il obtient en retour de la chaîne de l'attaquant a été en mesure à l'entrée. De déterminer combien de personnes sont nécessaires est quelque chose d'un attaquant ferait par une sorte d'essai et d'erreur (probablement par l'exécution d'un test qui a toute une série de "%08x" formats jusqu'à ce qu'il peut "voir" où le format de chaîne de caractères commence).
De toute façon, quand
printf()
obtient le traitement de l' "%s" spécificateur de format, il a consommé toute la pile des entrées jusqu'à l'endroit où leoutstring
tampon réside. Le "%s" spécificateur de traite sa pile d'entrée comme un pointeur, et la chaîne de caractères que l'utilisateur a mis dans ce tampon a été soigneusement conçu pour avoir une représentation binaire de0x08480110
, doncprintf()
permet d'imprimer tout ce qui est à cette adresse comme une corde d'ASCIIZ.OriginalL'auteur Michael Burr
Vous avez 6 spécificateurs de format (5 lots de
%08x
et l'un des%s
), mais vous n'avez pas donner des valeurs pour les spécificateurs de format. Vous tombent immédiatement dans le domaine de l'indéfini comportement - quelque chose pourrait se produire et il n'y a pas de mauvaise réponse.Toutefois, dans le cours normal des événements, les valeurs passées à
printf()
aurait été stockées sur la pile, de sorte que le code dansprintf()
lit les valeurs en dehors de la pile comme si les valeurs avaient été transmis. La fonction de l'adresse de retour sur la pile. Il n'y a aucune garantie que je peut voir que la valeur 0x08480110 sera effectivement produit. Ce genre d'attaque dépend très largement de la le programme spécifique ainsi que les défauts d'appel de fonction, et vous pourriez bien obtenir une valeur très différente. L'exemple de code est probablement écrit en supposant un Intel 32 bits (little-endian) CPU - plutôt que d'une version 64-bits ou big-endian CPU.Adapter le fragment de code, le compiler dans un programme complet, ignorant les avertissements de compilation, à l'aide d'un 32-bit compilation sur mac os X 10.6.7 avec GCC 4.2.1 (XCode 3), le code suivant:
produit le résultat suivant:
Comme vous pouvez le voir, finalement, j'ai "trouvé" la chaîne dans le programme principal de la
printf()
déclaration. Quand je l'ai compilé en mode 64 bits, j'ai un core dump à la place. Les deux résultats sont tout à fait correct; le programme invoque un comportement indéterminé, donc tout ce que fait le programme est valide. Si vous êtes curieux, recherche pour "nasale démons" pour plus d'informations sur le comportement indéfini.Et de s'habituer à expérimenter avec ces sortes de questions.
Une autre variation
Ce produit:
Vous pourriez reconnaître la chaîne de format dans l'hex de sortie - 0x41 est capitale, par exemple.
64 bits de sortie de ce code est à la fois semblables et différents:
Merci, je comprends cela, mais le document affirme ensuite que ce code "Va vider la mémoire de 0x08480110 jusqu'à ce qu'un octet NUL est atteint." pourquoi est-ce que mettre l'adresse de la mémoire au début de la chaîne de format vous permet d'imprimer le contenu à cette adresse lorsque vous arrivez à l' %s?
l'article a été écrit en 2001, quand la vie était plus simple. Les choses ont changé depuis. Il note que la chaîne de format doit être sur la pile, puis vous pouvez obtenir à l'adresse plus facilement. Les compilateurs modernes de ne pas mettre la chaîne de formatage sur la pile; il serait plus que probablement, dans le segment de texte (code de programme; mémoire en lecture seule).
OriginalL'auteur Jonathan Leffler
Vous avez mal compris le papier.
Le texte est lié en supposant que la position courante sur la pile est 0x08480110 (voir le texte). Le
printf()
sera le vidage des données à partir de la mesure sur la pile, vous arrive d'être.La
\x10\x01\x48\x08
au début de la chaîne de format est simplement de les imprimer le (supposé) de l'adresse de sortie standard (stdout) en face de la sous-évaluées de données. En aucune façon ces numéros de modifier l'adresse à partir de laquelle les données sont sous-évaluées.OriginalL'auteur DevSolar
Vous avez raison à propos de "vous prenez de la pile", mais à peine; il s'appuie sur l'hypothèse que les arguments sont passés sur la pile, plutôt que dans les registres. (Qui, pour une variadic fonction est probablement une hypothèse sûre, mais encore une hypothèse au sujet de la mise en œuvre de détails.)
Chaque
%08x
demande pour la prochaineunsigned int
argument " pour être imprimé en hexadécimal; ce qui se produit réellement dans ce 'argument suivant l'emplacement est à la fois l'architecture et le compilateur dépendante. Si vous comparez les valeurs que vous obtenez avec/proc/self/maps
pour le processus, vous pourriez être en mesure d'affiner ce que certains veulent dire les chiffres.OriginalL'auteur sarnold