Stack-Overflow



  • Hallo Leute,

    ich beschäftige mich im mom mit kontrollierten Stacküberläufen unter Linux und versuche dies bei einem recht einfachen Programm zu provozieren:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    void foo(char* x)
    {
      char y[10];
    
      strcpy(y, x);
    }
    
    int main(int argc, char* argv[])
    {
      if (argc < 2)	{printf("No Command\n"); exit(1);}
    
      foo(argv[1]);
    
      if (atoi(argv[1]) == 42)	printf("ok\n");
    
      return 0;
    }
    

    Compilert mit gcc 4.5.2

    gcc test.c -o test -g -fno-stack-protector
    

    versuche ich dann die Rücksprungadresse aus der Funktion foo mit der Adresse vor printf("ok\n"), die ich durch disassemblieren herausgefunden habe, zu überschreiben:

    ./test $(perl -e 'print "\x48\x85\x04\x08"x50')
    

    Aber anstatt dem erwartetem 'ok' erhalte ich 'Speicherzugriffsfehler' als Ausgabe.

    Wodran liegt das?



  • Bist du dir denn sicher, daß hinter deinem Array wirklich die Rücksprungadresse im Speicher untergebracht ist? Ansonsten liegen solche Basteleien in der Kategorie "undefiniertes Verhalten", d.h. du kannst dich nicht wirklich darauf verlassen, was dort passiert (und mußt dich sehr gut auskennen, um nicht irgendwas anderes auf dem Weg dorthin kaputtzumachen).



  • Soweit ich weiß baut sich das Stacksegment von Programmen mit kleiner werdenden Adressen auf.
    Die Rücksprungadresse wird vor der Variable auf den Stack gelegt und somit liegt diese in dem Bereich der durch den Stack-Overflow überschrieben wird.
    Oder?



  • Dann besteht immer noch die Möglichkeit, daß der Compiler zwischen dem char-Array und den internen Verwaltungsdaten noch Padding-Bytes unterbringt (und wo in der ganzen Anordnung die Parameter untergebracht sind, bin ich auch nicht sicher).

    PS: Ich bin mir noch nicht mal sicher, was genau dein Programmaufruf erreichen soll.



  • Mit dem Programmaufruf wird (in diesem Fall) einfach die gewünschte Rücksprungadresse (nach printf("ok\n)) 50 mal übergeben,
    was dann zur Folge haben soll, dass die ursprüngliche Rücksprungadresse damit überschrieben wird.
    Das mit den Padding-Bytes lässt sich ja kompensieren, indem man die neue Adresse, anstatt 50 mal, öfter angibt. Aber das funktioniert auch nicht..
    Es bleibt immer bei der Ausgabe 'Speicherzugriffsfehler'.



  • NEO.PIXEL schrieb:

    Mit dem Programmaufruf wird (in diesem Fall) einfach die gewünschte Rücksprungadresse (nach printf("ok\n)) 50 mal übergeben,
    was dann zur Folge haben soll, dass die ursprüngliche Rücksprungadresse damit überschrieben wird.

    Da könnte es natürlich sein, daß du ein wenig übertrieben hast: das Array ist 10 Byte groß, der dort rein kopierte String kommt auf 200 Byte - damit überschreibst du vermutlich ein wenig mehr als nur die Rücksprungadresse deiner Funktion.



  • Die 50 mal war jetzt nur als Beispiel gedacht..
    Ich hab das von 1 bis 50mal durchprobiert aber es funktioniert nichts davon..
    Kann doch nicht so schwer sein diese Adresse zu überschreiben 🤡



  • Geh dein Programm mit einem Debugger durch und versuche dann ganz gezielt einen Buffer zu erstellen, der genau die Rücksprungadresse überschreibt.



  • Vielleicht verwendet der Compiler auch kein Padding - und die Adresse die du überschreiben willst, liegt wirklich 10 oder (hinter dem Parameter) 14 Byte hinter dem String-Anfang - in dem Fall landet dort nur die halbe Adresse (oder die Hälften in falscher Reihenfolge).

    PS: Wie gut kennst du dich eigentlich mit Assembler und der (echten, nicht irgendwie vermuteten) Architektur deines Rechners aus? Ich kenne mich da nur oberflächlich aus, deshalb kann ich nur Vermutungen anstellen.



  • Jetzt funktionierts 😃

    Ich hatte die falsche Rücksprungadresse angegeben.
    Außerdem habe ich die ersten 10 Byte des Buffers einfach mit 0x90 beschrieben, um das Problem mit der halben Adresse, was Cstoll meinte, auszuschließen..
    Durch langsames rantasten ergab sich dann das die zu überschreibende Adresse 26 Byte hinter dem Anfang des Buffers liegt 🙂

    Es wird zwar immer noch 'Speicherzugriffsfehler' ausgegeben, aber er spring nun an die richtige Adresse und gibt zusätzlich 'ok' aus.

    ./test $(perl -e 'print "\x90"x10 . "\xaa\x84\x04\x08"x4')
    ok
    Speicherzugriffsfehler
    

    Danke für die Hilfe


Anmelden zum Antworten