Introduction à l'exploitation et à l'inversion à l'aide d'IDA FREE et d'autres outils gratuits. Chapitre 2

Dans la première partie, nous avons installé plusieurs outils qui nous seront utiles pour suivre ce cours. Leur caractéristique est qu'ils sont tous gratuits. Nous n'utiliserons aucun outil payant, et parmi ceux qui ont une version payante, comme IDA ou PYCHARM, nous utiliserons la version GRATUITE ou COMMUNAUTAIRE.

Examinons quelques concepts avant de commencer les exercices.

Qu'est-ce qu'un sac?

BAG est le résultat d'une défaillance ou d'un manque dans le processus de création de programmes informatiques (logiciels) ou d'un ordinateur. L'échec spécifié peut se produire à n'importe quelle étape du cycle de vie du logiciel, bien que l'échec le plus évident se produise au stade du développement et de la programmation.

Comme je le dis toujours, un programmeur peut faire des erreurs, et ces erreurs peuvent provoquer des plantages ou des bugs du programme. Jusqu'à présent, je n'ai rien dit de nouveau.

La question est de savoir la différence entre le SAC et la VULNÉRABILITÉ, voyons donc ce qu'est la VULNÉRABILITÉ.

Qu'est-ce que la VULNÉRABILITÉ?

La VULNÉRABILITÉ est un certain type de bogue dans un programme qui permet de l'utiliser pour violer la sécurité d'un système informatique.

Ainsi, les vulnérabilités vous permettent d'effectuer des actions auxquelles le programme n'était pas destiné et d'en abuser.

En d'autres termes, la vulnérabilité est un certain type de bogue, un sous-ensemble entre eux.



Bien sûr, il existe de nombreux types de vulnérabilités. Nous allons nous concentrer sur l'étude et l'exploitation des vulnérabilités dans WINDOWS.

Qu'est-ce que EXPLOIT?


EXPLOIT est un programme informatique qui tente d'exploiter une certaine vulnérabilité d'un autre programme. Le but ultime d'un exploit peut être malveillant, par exemple, comme détruire ou arrêter un système attaqué, bien qu'il s'agisse généralement d'une violation des mesures de sécurité afin d'accéder aux informations de manière non autorisée et de les utiliser dans votre propre intérêt ou comme source d'autres attaques contre des tiers.

L'abus de la vulnérabilité peut entraîner la défaillance de l'application ou du système lui-même, l'exécution de code natif sur des machines locales ou distantes. Son fonctionnement et sa complexité dépendent de la vulnérabilité elle-même, de l'environnement et des mesures que l'objectif a pendant l'opération.

Le premier type de vulnérabilités que nous examinerons sera le débordement de tampon. Nous commencerons par les exemples les plus simples, puis nous augmenterons progressivement la complexité.

Dans un premier temps, les fonctionnalités de sécurité du système ne seront pas activées, mais progressivement nous les activerons pour savoir comment les gérer et dans quelles situations.

Qu'est-ce qu'un TAMPON?


BUFFER est un espace mémoire d'une certaine taille réservé au stockage et à la gestion des données.

Un exemple de base est un pot de 20 litres, que j'ai pour stocker le contenu. Il peut être inférieur ou égal à 20 litres, ce qui est la taille maximale. Si vous souhaitez stocker plus dans un réservoir, vous devez trouver un moyen d'augmenter la taille du tampon, sinon lorsque vous essayez d'économiser, par exemple, 40 litres dans une boîte de 20 litres, il débordera.

Qu'est-ce qu'un BUFFER OVERFILL?


Un débordement de tampon se produit lorsqu'un programme informatique dépasse la quantité de mémoire qui lui est réservée en écrivant des données dans un bloc de mémoire contigu.

https://www.welivesecurity.com/la-es/tag/buffer-overflow-la-es

En vérité, un débordement de tampon se produit dans une application lorsqu'elle n'a pas les contrôles de sécurité nécessaires dans son code de programme, comme la mesure de la quantité de données qui seront copiés dans le tampon et qui ne dépassent pas la taille du tampon.

Les types de débordements de tampon les plus courants sont les débordements de tampon de pile et les débordements de tampon de tas.

Ici, nous voyons la définition du débordement de tampon, et dans notre exemple précédent, si j'essaie de verser 40 litres dans un réservoir de 20 litres, il débordera, comme nous le comprenons. Il s'agit d'un débordement qui provoque un débordement de tampon, c'est-à-dire débordement de mon réservoir lorsque sa capacité maximale est dépassée.

Expliquez maintenant la différence entre la pile et le tas.

Qu'est-ce qu'une pile?


STACK est utilisé pour stocker les variables de fonction locales qui ne sont nécessaires que tant que la fonction est exécutée. Dans la plupart des langages de programmation, il est important de savoir au moment de la compilation quelle est la taille d'une variable si nous voulons la conserver sur la pile.

Qu'est-ce qu'un LOT?


Le tas est utilisé pour réserver de la mémoire dynamique, dont la durée de vie n'est pas connue à l'avance, mais il est prévu qu'elle durera un certain temps. Si nous ne connaissons pas sa taille ou qu'elle est déterminée lors de l'exécution, la taille doit être calculée et réservée sur le tas.

Le tas est également utilisé pour les objets dont la taille varie car nous ne savons pas au moment de la compilation combien de temps ils seront utilisés.

Je travaille dans notre entreprise depuis plus de 13 ans en tant qu'auteur d'exploits, et la première chose que nous avons faite avec toutes les personnes embauchées m'a même fait quand j'ai rejoint était d'essayer de démêler les piles et les tas du célèbre GERARDO RICHART. Il est l'un des fondateurs de CORE SECURITY et un gourou de l'analyse des exploits.

Nous allons commencer lentement avec les piles les plus simples. Bien sûr, comme je l'ai dit, ils sont compilés pour le moment avec une protection minimale et sont de 32 bits afin de faciliter le fonctionnement.

Examinons le code source de la tâche STACK1.

https://drive.google.com/open?id=16btJAetpa1V5yHDZE2bnnFWTQNpsUR4H

Nous voyons un dossier avec des exercices, et à l'intérieur se trouve le code source STACK1 appelé STACK1_VS_2017.CPP.

#define _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_DEPRECATE

#include <stdlib.h>
#include  <stdio.h> 
#include "Windows.h"


int main(int argc, char **argv) 
{


	MessageBoxA((HWND)-0, (LPCSTR) "Imprimir You win..\n", (LPCSTR)"Vamosss", (UINT)0);

	int cookie;
	char buf[80];

	printf("buf: %08x cookie: %08x\n", &buf, &cookie);
	gets(buf);

	if (cookie == 0x41424344) printf("you win!\n");

}


Nous allons essayer de comprendre ce code et voir où le débordement de tampon peut se produire, et s'il s'agit d'un débordement de tampon sur la pile ou sur le tas.

L'appel de fonction MessageBoxA a été ajouté au code source STACK1 pour nous montrer un petit message nous invitant à le résoudre. Ceci est juste un ajout qui n'affecte rien. Il s'agit d'un appel standard à la fonction WINDOWS spécifiée, que nous n'analyserons pas ici.

Qui a besoin d'informations sur cette fonction, vous pouvez les obtenir ici.

Nous savons qu'à l'intérieur de la fonction, s'il y a des variables locales, vous devez leur réserver une place.

Il nous reste donc ce code source créé par GERARDO RICHART.

int main(int argc, char **argv) 
{

	int cookie;
	char buf[80];

	printf("buf: %08x cookie: %08x\n", &buf, &cookie);
	gets(buf);

	if (cookie == 0x41424344) printf("you win!\n");

}

On voit en rouge la première partie du programme, où était réservé un espace pour les variables locales. Dans ce cas, il existe deux variables locales, COOKIE et BUF.

Vous pouvez voir les types de données dans le tableau . D'autres types de variables s'y trouvent également.

Le code sera compilé en 32 bits.

On voit que la variable COOKIE sera de type INT, donc 4 octets de mémoire seront réservés pour cette variable.



Dans le cas de la variable BUF, on voit qu'il s'agit d'un tableau ou d'une chaîne de caractères (taille de caractère = 1 octet).



Ceux. ce sera un tableau de 80 caractères, c'est-à-dire sa longueur sera de 80x1 = 80 octets.

Quiconque ne sait pas ce qu'un tableau peut lire à ce sujet ici:

https://www.programiz.com/c-programming/c-arrays

Ainsi, un tableau peut stocker de nombreuses valeurs du même type de données. Vous n'avez qu'à lui dire quel type de données seront et combien il y en aura.



Dans le premier exemple, il s'agit d'un tableau d'entiers, c'est-à-dire ce sera 100 octets, et comme chaque entier prend 4 octets, la longueur du tableau sera de 100 x 4 = 400 octets.

Dans le deuxième exemple, FLOAT prend 4 octets, ce sera donc un tableau de 5 FLOAT, donc sa longueur sera de 5 x 4 = 20 octets.

Lorsque nous analysons le tableau à un niveau bas, nous verrons qu'il s'agit d'un espace mémoire ou tampon réservé. Ce n'est pas le seul moyen de réserver de l'espace mémoire. Il existe d'autres types de données variables qui nécessitent également un espace de réserve en mémoire qui seront des tampons pour stocker leur contenu.

Revenons à notre exercice:

char buf[80];

Il s'agit d'un tableau de caractères de 80 x 1 = 80 octets de long, c'est-à-dire il ressemble à notre pot de 20 litres. Si nous essayons de stocker plus de 80 octets, la banque débordera.

Voyons maintenant où le tampon BUF est utilisé.



On voit que le tampon est utilisé à deux endroits marqués de flèches rouges.

La première instruction a une fonction PRINTF, qui est utilisée pour afficher un message dans la console, qui sera une chaîne entre guillemets.

"buf: %08x cookie: %08x\n"

Mais la fonction PRINTF imprime non seulement la chaîne entre guillemets, mais elle imprime également la chaîne au format spécifié. Les pourcentages à l'intérieur nous indiquent qu'une ligne de sortie sera créée. Nous voyons que la chaîne n'est que le premier argument de la fonction. Le format de sortie et d'autres arguments peuvent être plusieurs (il y en aura un pour chaque argument% dans le format). Dans notre cas, il y en a deux.



Dans ce cas, nous avons deux formats% X, donc, si je me réfère à la table de format PRINTF:



Nous voyons que la fonction prendra ces entiers (INT) et les insérera dans la ligne de sortie avec la base du système numérique 16, c'est-à-dire au format hexadécimal. 08 indique que si le numéro contient moins de 8 chiffres, la fonction le remplira d'espaces.

La sortie pour "buf:% 31x", & buf sera comme ceci

buf:             19FED4 

Nous voyons que dans cet exemple sont remplis d'espaces avant le nombre. Il existe plusieurs modificateurs pour afficher la sortie.

Tous les cas possibles sont répertoriés ici:

http://www.cplusplus.com/reference/cstdio/printf/

Notre cas est le suivant:





Nous voyons que le résultat n'est pas tronqué, il est rempli d'espaces uniquement si la longueur de l'argument à insérer est inférieure à la valeur avant X.

Par conséquent, nous savons que la fonction imprime deux nombres hexadécimaux, qui sont obtenus à partir de deux arguments.

printf("buf: %08x cookie: %08x\n", &buf, &cookie);

Nous savons qu'une variable a une adresse mémoire et une valeur qui peuvent être stockées. Il ressemble à notre pot de 20 litres. Il a son contenu ou sa signification, c'est-à-dire litres stockés à l'intérieur, mais aussi si j'ai un garage rempli de bidons similaires, j'ai besoin d'un moyen de déterminer où je peux trouver parmi tous ceux que j'ai.

Le symbole & indique cela. Il renvoie l'adresse ou l'emplacement du pot, pas son contenu ou sa valeur.

Définition de AMPERSAND


AMPERSAND est utilisé pour indiquer l'adresse mémoire de la variable dans laquelle les données seront stockées.

Par conséquent, si j'exécute le fichier exécutable dans la console, je verrai, par exemple, que lorsqu'il exécute la fonction PRINTF, il imprimera:



Les adresses peuvent changer sur votre PC, mais puisque l'adresse inférieure des deux adresses correspond à l'adresse BUF, nous voyons qu'elles sont situées de cette façon:



L'adresse BUF est inférieure à l'adresse COOKIE, elle augmentera donc.

Et que nous disent ces adresses variables? (Dans mon cas, & BUF = 0x19FED4 et & COOKIE = 0x19FF24)



Les deux sont au format hexadécimal. Rappelez-vous que c'était le format% X? J'ai donc mis 0x en avant pour distinguer les nombres décimaux que nous représenterons sans aucun ajout.

Si je fais une soustraction dans la console PYTHON ou dans PYCHARM:



Nous obtenons un résultat de 80 octets, car la variable COOKIE commence censément exactement là où se termine le tampon BUF, donc la différence nous donne la taille du tampon.

Souvent, lorsque nous créons ce type de variable en fonction du code source, il peut arriver que le compilateur nous donne une taille plus grande que celle qui est réservée dans le code source. Le compilateur garantit qu'il réservera au moins 80 octets, c'est-à-dire il peut réserver plus, pas moins.

Le fait est que nous savons déjà quelque chose sur le code, la taille des variables et leur emplacement car il a la fonction PRINTF.

Examinons maintenant un autre endroit où le tampon BUF est utilisé, car maintenant le programme affiche uniquement son adresse, mais ne l'utilise pas pour y stocker des données.

int main(int argc, char **argv) 
{

	int cookie;
	char buf[80];

	printf("buf: %08x cookie: %08x\n", &buf, &cookie);
	gets(buf);

	if (cookie == 0x41424344) printf("you win!\n");

}

Ici, sur la ligne rouge, GET est une fonction pour saisir des données à partir du clavier. Les données seront saisies jusqu'à ce que j'appuie sur Entrée.

Le programme ne peut pas limiter la quantité de données entrées par l'utilisateur, et il n'y a également aucun moyen de vérifier ces données. Tout ce qui est entré avant d'appuyer sur la touche ENTRÉE est copié dans le tampon BUF.

C'est le problème. Nous avons dit que BUF ne peut stocker que 80 octets maximum, donc si nous entrons plus, nous allons créer un débordement de tampon, et voici toutes les conditions pour cela, car si l'utilisateur écrit plus de 80 octets, alors notre réservoir débordera et le liquide coulera .



Le fait est que sous le BUF se trouve la variable COOKIE, donc le débordement va l'écraser et le remplir avec une valeur que vous pouvez contrôler.

Par exemple, si quelqu'un qui imprime écrit 80 * A et 4 * B, 80 * A remplira BUF et 4 * B remplira COOKIE, et comme nous le savons, lorsque quelqu'un imprime un caractère dans la console, la valeur restera faible. ASCII.



Étant donné que le cookie sera rempli de quatre lettres B, qui équivalent à une valeur de 0x42, nous pouvons garantir que la valeur du cookie sera 0x42424242, c'est-à-dire sur mon ordinateur, l'adresse de cookie 0x19FF24 aura 0x42424242 comme contenu.

0x19FF24 => 42424242



Le fait est que nous avons déjà vu comment déborder et contrôler la valeur COOKIE.

int main(int argc, char **argv) 
{

	int cookie;
	char buf[80];

	printf("buf: %08x cookie: %08x\n", &buf, &cookie);
	gets(buf);

	if (cookie == 0x41424344) printf("you win!\n");

}

Vous devez imprimer «vous gagnez» pour terminer l'exercice. Pour cela, le COOKIE doit être égal à la valeur 0x41424344, et s'il n'y avait pas de débordement, cela serait impossible, car la valeur COOKIE n'a jamais changé depuis le tout début du programme. Nous ne pourrons pas imprimer "vous gagnez", et pour cela nous utilisons un débordement de tampon, qui indique que cela peut amener le programme à effectuer une action autre que celle qui a été programmée.

Dans ce cas, vous ne pouvez jamais taper «vous gagnez», seul le débordement vous permettra de le faire.

AAAAAAAA

En d'autres termes, au lieu de passer, par exemple, 80 * A et 4 * B, pour imprimer "vous gagnez", vous devez passer 80 * A puis les lettres DCBA, car cela entraînera le stockage des valeurs dans le COOKIE ASCII.

44434241

https://www.arumeinformatica.es/blog/los-formatos-big-endian-y-little-endian/

Le format dans lequel les données sont stockées est LITTLE ENDIAN. En d'autres termes, les données en mémoire sont stockées dans l'ordre inverse, pour le dire simplement.



Et si la séquence 0x41424344 est sauvegardée, le système l'enregistrera en mémoire comme:

44 43 42 41

Pour cette raison, lors de la copie en mémoire, la copie se produira au fur et à mesure que nous tapons, nous devons donc écrire la valeur dans l'ordre inverse afin que lors de la lecture depuis la mémoire, elle était en bonne forme.

Nous pouvons exécuter l'exécutable dans la console.



Et le curseur clignote, car la fonction GET me demande d'entrer l'entrée. Tapez soigneusement 80 caractères A puis DCBA.

Dans la console PYTHON ou PYCHARM, je peux imprimer la ligne, la copier sans guillemets et la coller dans la console pour ne pas l'imprimer comme un fou, puis appuyer sur la touche ENTRÉE pour la saisir.





Nous voyons que nous avons «vous gagnez».

Nous pouvons voir cela dans le débogueur. Pour cela, nous utiliserons X64DBG.



Je choisis la version 32 bits.





Si nous nous arrêtons à la bibliothèque NTDLL.DLL, nous appuyons à nouveau sur RUN avec F9.

On voit que le débogueur s'arrête à la première instruction du module STACK1, qui s'appelle ENTRY POINT ou la première instruction exécutée par le module.



Évidemment, ce n'est pas comme notre code source. Vous devez comprendre que le compilateur ajoute beaucoup de code pour faire fonctionner l'exécutable et l'exécuter correctement. Nous allons essayer de trouver notre fonction principale. Nous pouvons nous orienter en regardant les lignes du programme.



Nous avons sélectionné uniquement la recherche dans la région actuelle. Nous savons que les lignes seront dans la même section.



Ici, nous voyons qu'il y a des lignes de programme et d'autres que le compilateur a ajoutées. Nous double-cliquons sur l'une de nos lignes.



Maintenant, vous pouvez en voir beaucoup plus. Nous voyons un appel à la fonction MessageBoxA, PRINTF, GETS et une comparaison avec la valeur 0x41424344.

De plus, nous ajoutons un plugin pour décompiler SNOWMAN. Nous pouvons essayer de voir comment il décompile le code, c'est-à-dire comment il essaie d'obtenir le code source ou quelque chose d'aussi similaire que possible à partir du fichier compilé.





On voit que ce n'est pas parfait, mais c'est mieux que ce que c'était.

Je vais mettre BP au début de la fonction et appuyer sur F9 jusqu'à l'arrêt du débogueur.



Pour ceux qui ne savent pas ce qu'est un argument de fonction.



Dans notre cas, la fonction principale a des arguments, mais ils ne sont pas utilisés à l'intérieur de la fonction.

int main(int argc, char **argv) 
{

	int cookie;
	char buf[80];

	printf("buf: %08x cookie: %08x\n", &buf, &cookie);
	gets(buf);

	if (cookie == 0x41424344) printf("you win!\n");

}

Ici, nous voyons qu'il y a deux arguments, et ils sont passés à travers la pile lorsque l'exécutable est compilé en 32 bits.

Juste avant l'appel de fonction, les arguments seront stockés sur la pile.

Lorsque nous nous arrêtons au début de la fonction, la première valeur de la pile sera RETOUR ADRESSE, c'est-à-dire où la fonction reviendra une fois la fonction terminée, et en dessous de cette valeur se trouvent les arguments de cette fonction.

Si je clique avec le bouton droit sur RETOUR D'ADRESSE et sélectionne SUIVRE DWORD DANS LE DÉSASSEMBLEUR, je verrai où le débogueur devrait retourner une fois la fonction terminée.



Il reviendra ici. Cela signifie que la fonction principale a été appelée à partir d'un appel supérieur. Je peux mettre BP ici, redémarrer l'exercice et m'assurer qu'il l'est.



Je mettrai BP un ​​peu plus tôt et redémarrerai le programme.



Le débogueur s'arrêtera ici.



Il va enregistrer les arguments dans la fonction principale en utilisant ces instructions PUSH.

Vous trouverez ci-dessous un lien pour ceux qui souhaitent en savoir plus sur les arguments de la fonction:

https://publications.gbdirect.co.uk/c_book/chapter10/arguments_to_main.html

Ce n'est pas très difficile. Le premier argument d'ARGC est INT, qui indique le nombre de paramètres de console utilisés pour exécuter le programme, y compris le chemin d'accès à l'exécutable, et ARGV est un tableau de pointeurs vers des chaînes.

Nous voyons que si je change la ligne de commande, je passerai plus d'arguments et rechargerai.





Ici, le débogueur s'arrête lorsqu'il est sur le point d'enregistrer des arguments à l'aide de l'instruction PUSH. Le premier argument qui est stocké est le plus éloigné, et le dernier que vous enregistrez sera le premier argument de la fonction.

Je trace et chaque instruction PUSH enregistre les arguments.



Ici, je peux voir les arguments de la fonction. Ci-dessus, le premier argument de l'ARGC. Il s'agit de 3, car il marque le nombre d'arguments transmis à la console.



Voici 3 arguments.

Maintenant, nous appuyons sur F7 pour faire STEP INTO et entrer dans la fonction.

Ici, nous voyons que lors de la saisie de l'appel, le débogueur enregistre l'adresse de retour dans la pile.



Ainsi, comme nous l'avons déjà dit lors de la saisie de la fonction, la première chose qui sera enregistrée sur la pile est RETOUR ADRESSE (en compilation 32 bits), et ci-dessous sont les arguments de la fonction, d'abord le premier argument, puis le reste séquentiellement.



Le deuxième argument, comme nous l'avons vu, est un tableau de pointeurs. Ici, nous voyons en mémoire qu'il y a trois pointeurs vers trois lignes qui sont passés comme arguments.



Ici, nous nous sommes arrêtés au début de la fonction, un peu plus bas, nous avons ADRESSES DE RETOUR et ARGUMENTS.

Nous précisons que le fichier est compilé en 32 bits, car dans la version 64 bits, les arguments sont passés d'une manière différente. Nous le verrons plus tard.

Ensuite, la fonction commence à s'exécuter. La première chose est le soi-disant PROLOGUE, qui stocke la valeur EBP de la fonction qui a appelé la nôtre.



Cela gardera la valeur EBP juste au-dessus de l'adresse de retour.



Si je suis les instructions en utilisant F7.

Je vois que la valeur EBP GUARDADO est sur la pile au-dessus de l'adresse de retour.



L'instruction suivante dans PROLOGUE:

MOV EBP, ESP

Il définit la valeur EBP pour la fonction actuelle qui a été enregistrée et était la fonction parent qui appelle la nôtre (dans ce cas, ma fonction principale est la fonction basée sur EBP, dans d'autres cas, elle peut être différente, et nous les voir plus tard)

En plaçant la valeur ESP actuelle dans EBP, nous nous assurons que nous créons un cadre pour notre fonction actuelle.



Maintenant, puisque cette fonction est basée sur EBP ou EBP BASED, la valeur EBP sera stockée à l'intérieur de la fonction et elle sera acceptée comme référence, et l'ESP changera.



Cette valeur EBP est prise comme base.

Dans les fonctions basées sur EBP, les variables et les arguments peuvent être nommés par leur distance à cette adresse, qui sera stockée dans la valeur EBP jusqu'à son épilogue.

Nous pouvons voir plusieurs variables dans la liste qui sont appelées EBP-4 ou EBP-54, se référant à la valeur EBP qu'elle accepte actuellement.

Nous pouvons dire que dès que l'EBP prend sa valeur après le PROLOGUE, il ressemblera à un drain, donc les arguments iront toujours dans cette direction, donc EBP + XXX fait référence aux arguments (l'EBP et l'ADRESSE DE RETOUR stockés sont également plus bas, mais n'auront pas de liens dans le code), alors que les variables, comme nous le verrons, seront au-dessus de cette adresse, donc le lien vers EBP-XXX fait référence à une variable locale.

Ainsi, dans les fonctions basées sur

EBP : EBP + XXXX = arguments passés à la fonction
EBP - XXXX = variables de fonction locales

Après PROLOGUE, il y aura un moyen de réserver de l'espace pour les variables. Dans notre cas, cela se fait en déplaçant l'ESP vers le haut de sorte que l'espace restant ci-dessous soit réservé à la somme de toutes les longueurs variables et, parfois, un peu plus au cas où, cela dépend du compilateur.

00401043 | 83EC 54 | SUB ESP, 54

Nous voyons que l'ESP est situé au-dessus de l'EBP, qui restera le lien, et que 0x54 converti en décimal est 84, qui est la somme des longueurs de BUF et COOKIE. N'oubliez pas qu'ils étaient respectivement 80 et 4.







Lors de l'exécution, un espace est créé pour les variables BUF et COOKIE de 84 octets. Vous pouvez cliquer sur la première colonne dans le sens horizontal et regarder la valeur EBP et trouver cette valeur sur la pile. Évidemment, maintenant, ce sera plus bas.



Je double-clique ici.



Ainsi, nous aurons également des valeurs concernant EBP sur la pile.

Par exemple, EBP-4 correspond à la liste, -4 est affiché dans la première colonne de la pile, et dans l'explication, est également affiché comme EBP-4.



Si je trace, on voit que de l'endroit où se trouvait l'ESP pour réserver les variables, il remontera toujours, car il doit tenir compte de l'espace alloué aux variables. Lors de l'exécution de 4 PUSH pour MessageBoxA, le débogueur place les variables au-dessus de l'espace réservé et augmente l'ESP.



Si je regarde la pile, je vois 4 arguments verts que j'ajoute sur l'espace réservé marqué en rouge.



Lorsque vous entrez dans la fonction MessageBoxA, l'adresse de retour de cette fonction est stockée dans la pile.



Voici l'adresse de retour de MessageBoxA. Quand j'arrive au RET de cette fonction en traçant avec F8, et j'exécute MessageBoxA.



Nous voyons que le débogueur reviendra juste en dessous de l'appel MessageBoxA.



Et les valeurs PUSH que vous avez passées pour la fonction MessageBoxA et l'adresse de retour pour cette fonction ont déjà été utilisées, et l'ESP est à nouveau juste au-dessus de la zone réservée, comme avant toute fonction a été appelée. La même chose se produira lors de l'appel de la fonction PRINTF.

Après avoir passé la fonction PRINTF, les adresses BUF et COOKIE seront imprimées.



L'adresse BUF sur ma machine sera 0x19FED4 et l'adresse COOKIE sera 0x19FF24.

Ici, le programme lit l'adresse BUF pour la transmettre à la fonction GETS et remplir le BUF. Nous pouvons vérifier si l'adresse correspond à ce que la console 0x19FED4 affiche.





Ici, nous voyons que c'est EBP-54. Si je double-clique sur la pile où elle affiche -54, cela montrera que l'adresse est BUF = 0x19FED4 sur ma machine.



Maintenant, quand j'enregistrerai les données saisies à cette adresse, je pourrai les mettre dans un vidage pour voir comment les octets y sont stockés.





Les voici. De plus, rien n'est affiché ci-dessous, car il n'y a pas de données.

Lorsque j'appelle la fonction GETS à l'aide de F8, je vais devoir accéder à la console, taper et appuyer sur ENTRÉE pour remplir le tampon BUF et réécrire le COOKIE.



Nous voyons que la variable COOKIE était à 19FF24 sur ma machine.

Ici, le programme compare le cookie avec 0x41424344.



Nous voyons que EBP-4 indique qu'il s'agit d'un COOKIE, en plus de l'adresse, si nous définissons l'HORIZON sur la valeur EBP, comme précédemment.



Je double-clique ici.

Nous voyons que EBP-4 est un COOKIE, puisque la variable est au niveau de pile -4, mettant à zéro l'HORIZON.



Nous voyons que le programme ne sautera pas et nous montrera que vous gagnez!





Donc, nous

atteignons manuellement l'objectif que vous gagnez! Dit Nous avons analysé dynamiquement STACK1 en utilisant X64DBG, qui est un débogueur et ne nous permet pas d'analyser le programme sans le démarrer. Pour ce faire, nous devons utiliser d'autres outils, tels que IDA PRO, GHIDRA ou RADARE.

Je peux créer un modèle de script pour faire fonctionner l'exercice à partir de PYTHON.

import sys
from subprocess import Popen, PIPE

payload = b"A" * 80 + b"\x44\x43\x42\x41"

p1 = Popen(r"C:\Users\ricardo\Desktop\abos y stack nuevos\STACK1_VS_2017.exe", stdin=PIPE)
print ("PID: %s" % hex(p1.pid))
print ("Enter para continuar")
p1.communicate(payload)
p1.wait()
input()

Dans le cas de PYTHON 3, je dois mettre des parenthèses dans la fonction PRINT et faire attention lors de l'ajout de lignes qui devraient être des octets (mettre b devant les lignes dans PYTHON 2).

Je vérifie que le chemin est correct et lorsque j'exécute le fichier.



Bien. Nous avons déjà un modèle de script pour PYTHON 3 pour faire fonctionner STACK1. Dans la prochaine partie, nous poursuivrons l'analyse statique dans IDA, RADARE et GHIDRA.


Veuillez noter qu'en plus de la tâche STACK1, il existe également des versions 2, 3 et 4. Vous pouvez essayer de les résoudre. Ils sont très simples et similaires à STACK1, alors ne vous ennuyez pas.

Dans la prochaine partie, nous verrons IDA FREE, RADARE et GHIDRA.

Rendez-vous dans la prochaine partie 3.

Ricardo Narvaha
25/10/2019

PS # 1
Un beau PDF peut être téléchargé sur ma page d'accueil - yasha.su

PS # 2
Bientôt, j'écrirai une suite de l'article https://habr.com/en/post/464117/ sur la façon dont j'ai collecté de l'aide pour le père Chris Kaspersky et quoi d'autre arrivé.

Ne vous ennuyez pas.

All Articles