2010-02-25 28 views
29

J'ai reçu un devoir qui me demandait d'appeler une fonction sans l'appeler explicitement, en utilisant un dépassement de tampon. Le code est fondamentalement ceci:Comment appeler le dépassement de tampon?

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

void g() 
{ 
    printf("now inside g()!\n"); 
} 


void f() 
{ 
    printf("now inside f()!\n"); 
    // can only modify this section 
    // cant call g(), maybe use g (pointer to function) 
} 

int main (int argc, char *argv[]) 
{ 
    f(); 
    return 0; 
} 

Bien que je ne sache pas comment procéder. J'ai pensé à changer l'adresse de retour pour le compteur de programme afin qu'il passe directement à l'adresse de g(), mais je ne sais pas comment y accéder. Quoi qu'il en soit, les pourboires seront super.

+9

4 upvotes pour une question de devoirs! Le PO n'a même pas trouvé la question ... wow, certaines personnes sont facilement impressionnées. – Lazarus

+0

@Lazarus, j'ai upvoted votre commentaire. Oh oh!:-) –

+15

@Lazarus le fait que ce soit une question de devoirs n'a rien à voir avec le fait que je trouve ça intéressant. Je l'ai également mis à la hausse parce que je veux encourager des questions intéressantes de devoirs plutôt que le simple "j'ai fermé le tampon de fichier et maintenant quand j'essaye de lire du dossier cela ne fonctionne pas. (En d'autres termes, je remets en cause les questions auxquelles je ne connais pas la réponse, mais je veux) – Yacoby

Répondre

14

L'idée de base est de modifier l'adresse de retour de la fonction de sorte que lorsque la fonction retourne est continue d'exécuter à une nouvelle adresse piraté. Comme fait par Nils dans l'une des réponses, vous pouvez déclarer une partie de la mémoire (généralement un tableau) et la déborder de telle manière que l'adresse de retour est également écrasée.

Je vous suggère de ne pas prendre aveuglément l'un des programmes donnés ici sans vraiment comprendre comment ils fonctionnent. Cet article est très bien écrit et vous trouverez très utile:

A step-by-step on the buffer overflow vulnerablity

3

Essayez celui-ci:

void f() 
{ 
    void *x[1]; 
    printf("now inside f()!\n"); 
    // can only modify this section 
    // cant call g(), maybe use g (pointer to function) 
    x[-1]=&g; 
} 

ou celui-ci:

void f() 
{ 
    void *x[1]; 
    printf("now inside f()!\n"); 
    // can only modify this section 
    // cant call g(), maybe use g (pointer to function) 
    x[1]=&g; 
} 
+3

Une explication serait grande, parce que c'est les devoirs. –

+2

x est une variable locale, donc située sur la pile. Puisque x est un tableau de taille 1, seul x [0] est valide. En écrivant l'adresse de g dans x [-1] ou x [1], il y a une chance que nous écrasions l'adresse de retour. Cela dépend de l'organisation de la pile quelle version fonctionne. –

11

Ce compilateur dépend, donc pas de réponse unique peut être donné.

Le code suivant fera ce que vous voulez pour gcc 4.4.1. Compiler avec des optimisations désactivées

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

void g() 
{ 
    printf("now inside g()!\n"); 
} 


void f() 
{ 
    int i; 
    void * buffer[1]; 
    printf("now inside f()!\n"); 

    // can only modify this section 
    // cant call g(), maybe use g (pointer to function) 

    // place the address of g all over the stack: 
    for (i=0; i<10; i++) 
    buffer[i] = (void*) g; 

    // and goodbye.. 
} 

int main (int argc, char *argv[]) 
{ 
    f(); 
    return 0; 
} 

sortie (important!):

[email protected]:~$ gcc overflow.c 
[email protected]:~$ ./a.out 
now inside f()! 
now inside g()! 
now inside g()! 
now inside g()! 
now inside g()! 
now inside g()! 
now inside g()! 
Segmentation fault 
+0

J'utilise gcc 4.4.1, et je ne sais pas comment désactiver l'optimisation: essayé gcc -O0 -o buff buff.c (c'est oh-zéro) et aussi gcc -O1 -fno-defer-pop - fno-thread-sauts -fno-branch-probabilités -fno-cprop-registres -fno-deviner-branche-probabilité -fno-omit-frame-pointer -o buff buff.c ni travaillé. – sa125

+1

Faire sortir l'application à l'intérieur de la fonction 'g()' pour éviter une erreur de segmentation =) – Kieveli

+0

sa125, peut-être que gcc essaie d'optimiser à une architecture CPU différente. Pour autant que je sache, il est par défaut le processeur du système que vous utilisez. Cela peut changer la façon dont la pileframe de f() ressemble et peut empêcher le débordement de se produire. –

7

Puisque c'est des devoirs, je voudrais faire écho codeaddict's suggestion de comprendre comment un dépassement de mémoire tampon fonctionne réellement.

J'ai appris la technique en lisant l'article/tutoriel excellent (si un peu daté) sur l'exploitation des vulnérabilités de débordement de tampon Smashing The Stack For Fun And Profit.

+2

+1 pour créer un lien vers cet article. –

3

Bien que cette solution n'utilise une technique de débordement pour remplacer l'adresse de retour de la fonction sur la pile, il provoque toujours g() pour s'appeler de f() sur son chemin de retour à main() que par la modification f() et ne pas appeler g() directement.

Function epilogue assemblage en ligne -like est ajouté à f() pour modifier la valeur de l'adresse de retour sur la pile de telle sorte que f() retournera par g().

#include <stdio.h> 

void g() 
{ 
    printf("now inside g()!\n"); 
} 

void f() 
{ 
    printf("now inside f()!\n"); 
    // can only modify this section 
    // cant call g(), maybe use g (pointer to function) 

    /* x86 function epilogue-like inline assembly */ 
    /* Causes f() to return to g() on its way back to main() */ 
    asm(
     "mov %%ebp,%%esp;" 
     "pop %%ebp;" 
     "push %0;" 
     "ret" 
     : /* no output registers */ 
     : "r" (&g) 
     : "%ebp", "%esp" 
     ); 
} 

int main (int argc, char *argv[]) 
{ 
    f(); 
    return 0; 
}

Comprendre comment fonctionne ce code peut conduire à une meilleure compréhension de la façon dont le cadre de pile d'une fonction est configurée pour une architecture particulière qui constitue la base des techniques de dépassement de mémoire tampon.