Buffer overflow

Résolu
tomk_41 Messages postés 2 Date d'inscription jeudi 16 novembre 2000 Statut Membre Dernière intervention 31 octobre 2005 - 31 oct. 2005 à 19:53
cs_neria Messages postés 319 Date d'inscription vendredi 21 février 2003 Statut Membre Dernière intervention 16 février 2009 - 1 nov. 2005 à 16:17
Voila maintenant plusieurs jour que je flanche sur un problème.
Dans le cadre d'un cours de sécurité informatique, je dois réussir à faire afficher "Bienvenu sur ce systeme..." sans entrer un des nom et mots de passe du tableau users.
Quelqu'un aurait il une idée sur la chaine de caractères à rentrer pour faire un buffer overflow et choisir notre propre nom et mot de passe ?

#include <stdio.h>

char users[][2][20] =
{ { "root", "98765" },
{ "moi", "allo" },
{ "abc", "motdepasse" },
{ "", "" }
};

int check_name()
{
char user_name[20];
char password[20];
int i;

printf("Nom: "); gets(user_name);
printf("Mot de passe: "); gets(password);

for(i=0; users[i][0][0] != 0; i++)
{
if(strcmp(user_name, users[i][0]) == 0 &&
strcmp(password, users[i][1]) == 0)
return 1;
}
return 0;
}

void logon()
{
printf("Bienvenu sur ce systeme...\n");
exit(1);
}

void reject()
{
printf("Connection fermee!\n");
exit(0);
}

main()
{
unsigned int i;
for(i=(unsigned)-3; i && !check_name(); i++);
if(i>=(unsigned)-3)
logon();
else
reject();
}

5 réponses

cs_neria Messages postés 319 Date d'inscription vendredi 21 février 2003 Statut Membre Dernière intervention 16 février 2009
1 nov. 2005 à 00:44
Salut tom_k !


Tout d'abord je tiens à préciser que je n'ai jamais réaliser de buffer overflow donc ma méthode sera peut être mauvaise, mais j'ai quand même réussi à sauter le test et aller directement dans logon(). Il faut aussi préciser que j'ai compilé le programme avec Visual C++ 6 en le modifiant légérement (pour la fonction exit par exemple) et que les adresses ne seront pas forcement les bonnes. De plus j'ai utilisé le débogueur intégré de VC++ ce qui m'a beaucoup aidé.
Voici le code que j'ai compilé :

#include <stdio.h>
#include <string.h>


char users[][2][20] =
{ { "root", "98765" },
{ "moi", "allo" },
{ "abc", "motdepasse" },
{ "", "" }
};


int check_name()
{
char user_name[20];
char password[20];
int i;


printf("Nom: "); gets(user_name);
printf("Mot de passe: "); gets(password);

for(i=0; users[i][0][0] != 0; i++)
{
if(strcmp(user_name, users[i][0]) == 0 &&
strcmp(password, users[i][1]) == 0)
return 1;
}
return 0;
}


void logon()
{
printf("Bienvenu sur ce systeme...\n");
//exit(1);
}


void reject()
{
printf("Connection fermee!\n");
//exit(0);
}


void main()
{
unsigned int i;
for(i=(unsigned)-3; i && !check_name(); i++);


if(i>=(unsigned)-3)
logon();
else
reject();
}


En tout ça m'a prit 1h30 pour comprendre (j'ai pénétré le système à minuit pile :) ). Le principe est que lors du retour du check_name() (dans le for) il ne faut non pas aller à l'instruction suivante (pour tester si le code de retour est bon), mais aller directement à l'adresse du call logon juste après le test if. Chez moi cette adresse est 0x00401211.
Nous le savons tous, lors d'un ret, la machine dépile le contenu de l'adresse d'ESP (*ESP) dans EIP (qui pointe vers l'instruction suivante à éxécuter). Hors les variables statiques (pas static !!!) sont elles même contenue dans la pile. De plus on utilise un gets ce qui aura effet d'écrire chaque caractère tapé au clavier sur cette même pile, donc si on déborde de la taille prévue au départ on pourra écraser des valeurs de la pile dont la fameuse adresse de retour !!
Pour faire simple on va utiliser la variable user_name car c'est la plus proche du début de la pile. On lance le programme en mode pas à pas avec vue désassemblée et on tape dans Nom:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 afin de voir ce qu'on écrase et où. Pour mot de passe on tape ce qu'on veux. On remarque que avant d'éxecuter le ret, ESP pointe sur 0x0012FF2C. Un petit coup d'oeil dans la mémoire pour voir ce qui s'y trouve, et qu'est ce qu'on découvre ??? "YZab". Ce sont donc ces caractères qu'il faudra changer pour modifier l'adresse de retour. On Recommence l'opération,
Nom:ABCDE...X il faut alors taper l'adresse 0x00401211 à la place de YZab. Attention, il faut les taper à l'envers car on est en litle endian --> 11 12 40 00 et en décimal 17 18 64 00 (alt + 17 sur le pavé numérique [ne fonctionne pas sur les portables] pour écrire le caractère 17). Puis entrer et entrer (mot de passe) et ... miracle on arrive directement au logon() après le if en squizzant le test !!!!
Il faudra sûrement changer les valeurs des adresses suivants les compilos et ce ne sera peut être pas aussi évident si tu as juste le binaire et un débogueur mais bon perso je me suis bien amusé à faire mon premier buffer overflow :p

@+ Neria
3
Taron31 Messages postés 199 Date d'inscription vendredi 16 avril 2004 Statut Membre Dernière intervention 28 février 2008
1 nov. 2005 à 13:10
Ouais c'est exactement ça, tu peux preciser que la valeur pointée par
ESP est EIP Saved précédement pushée lors de l'appel de check_name() :)



Ps : puis-je savoir dans quel cursus te situes-tu et en quelle année ? (ca m'interesse)

Bye.
3
cosmobob Messages postés 700 Date d'inscription mardi 30 décembre 2003 Statut Membre Dernière intervention 27 janvier 2009 4
31 oct. 2005 à 23:56
salut,

tu dois recuperer l'adresse de ta fonction logon (rajout un printf("addresse : %u\n", logon);)

et le but est de donner un nom trop long, pour ecraser l'adresse a
laquelle la fonction check_name retourne (cette adresse est placée sur
la pile lors du call check_name) et y mettre celle de la fonction logon.

ya des chances qu'elle se situe aux alentours de password[22] ou 23, c la que le debugger de ton compilo doit t'aider.

Donne le nom AAAAAAAAAAAAAAAAAAAAAAAA jusqu'a depasser de 20
caracteres, et regarde qd ton programme va planter. il va planter qd
justement t'auras ecrasé l'adresse de la pile qui est utilisée qd
check_name retourne.



bref si ca a pu un peu t'éclairer ...
1
tomk_41 Messages postés 2 Date d'inscription jeudi 16 novembre 2000 Statut Membre Dernière intervention 31 octobre 2005
31 oct. 2005 à 23:44
J'ai cru comprendre qu'il fallait debuguer par exemple sous Dev C++ pour voir ou sont stockée les variables. Si quelqu'un pense pouvoir m'aider, je peux lui envoyer l'executable qui est fourni.
Mon adresse : tomk_41@yahoo.fr
Merci d'avance à tous.
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
cs_neria Messages postés 319 Date d'inscription vendredi 21 février 2003 Statut Membre Dernière intervention 16 février 2009
1 nov. 2005 à 16:17
On peux continuer cette discussion en MP si tu le souhaites.

@+
0
Rejoignez-nous