Aleph One Tutorial - Verständnisproblem

  • Hi Leute,


    ich habe bereits gecheckt wie man bei vuln1.c vorgehen muss,
    allerdings habe ich auch versucht die Bsp. im Tutorial vom
    Aleph nachzuvollziehen und da hänge ich etwas.


    Im Kapitel "Writing an exploit", ist es mir nicht möglich die Beispiele overflow1.c und exploit3.c erfolgreich zu starten. (immer Seg-Fault)


    Programmablauf ist klar soweit (bsp overflow1):
    --------------------
    buffer mit 96 Bytes, large_string array mit 128 Bytes.
    In der ersten For-Schleife wird die Anfangsaddy vom buffer
    in large_string reinkopiert (über den Pointer long_ptr) - in Ordnung soweit


    In der zweiten For-Schleife wird der shellcode in large_string
    geschrieben


    Danach wird strcpy ausgeführt und large_string in buffer kopiert.
    --------------------
    Folgendes Problem: Bei Ausführung am Server bekomme ich immer einen segmentation Fault.
    Warum? Wie schaut hier der Stack aus?


    Code
    1. <-- [ buffer 96 bytes ] [sfp] [ret] --|

    Ret sollte sich auf der Pos. buffer[99] befinden? (0...95 + 4 bytes für sfp = 99)



    2.Problem

    Nächstes Prob ist beim Bsp. Exploit3.c:


    Die Funktion get_sp() gibt ja eigentlich den Stack Pointer zurück der ja an den Top of the Stack
    zeigt. Das würde allerdings heißen dass das mim Offset nicht klappt außer mit einem negativen Offset,
    macht aber wenig Sinn wenn da steht get_sp() - offset.


    Vom Prinzip her stelle ich es mir so vor bzw. wird es auch so im Dokument erklärt, und zwar, dass

    Code
    1. __asm__("movl %esp,%eax");

    an den Anfang des Stacks verweist (dann macht das "get_sp() - offset"
    auch wieder Sinn :) ).
    Vielleicht kann mir wer den movl esp,eax Befehl genauer erklären, ich dachte das wäre der stack
    pointer der immer an den Top of the Stack zeigt???



    Wie das Bsp exploit3.c im Dokument ausgeführt werden kann ohne einen Offset anzugeben ist mir auch
    ein Rätsel.
    Wenn ich die Ret-Addy, welche an den Anfang des Stacks zeigt, in den Buffer schreibe werde ich ja nicht
    mit der ret-addy in den Anfangsbereich des buffer Array zeigen??


    Selbes Problem beim Starten des Programms --> Seg-Fault.


    Ohne offset müsste doch die ret ans Ende des Buffer Array verweisen??



    Was habe ich hier nun überlesen oder was genau verstehe ich hier nun falsch?


    Kann mir wer bitte weiterhelfen?


    Thx,
    Tno

  • ich habe auch einige Probleme zu verstehen, wie der stack auf dem server genau aussieht. bei mir hat es auf jeden fall funktioniert das beispiel overflow1.c erfolgreich auszufuehren, als ich den char buffer auf 104 bytes geaendert habe.


    bei exploit3.c bekomme ich allerdings auch immer einen segmantation fault und habe keine ahnung warum? ich wuerde mal auf ein adressproblem tippen.


    des weiteren wuerde mich auch interesieren, ob man fuer vuln1.c einen eigenen shellcode schreiben muss, oder einen schon vorhandenen nehmen kann? problem ist ja allerdings dieses gemeine stoppzeichen.


    ich waere auch fuer jeden tipp sehr dankbar :-)

    Es gibt nur einen Gott:
    Farin - Bela - Rod
    ---------------------------------------
    There are 10 types of people:
    those that understand binary,
    and those that don´t!!!

  • Hallo,


    aaalso...bei einer so komplexen Materie ist es klar dass die Übersicht schnell verlorengeht. Jetzt kann man sich alle Adressen und das Stack-Layout mit Zettel und Stift mühsam überlegen und aufschreiben nur um dann draufzukommen dass man eine Kleinigkeit übersehen hat und alles nochmal machen muss. ODER man verwendet einfach einen Debugger und schaut sich an was passiert.
    LERNT DEN DEBUGGER ZU LIEBEN - er ist mehr oder weniger das wichtigste Werkzeug für jemanden, der wissen will, was im Computer eigentlich passiert. Ich weiß, GDB ist furchtbar, aber wenn man mal damit zurechtkommt ist die Challenge 2 ein Kinderspiel.
    Genug der Predigt; zu den konkreten Fragen:


    fuxi17:

    Quote

    bei exploit3.c bekomme ich allerdings auch immer einen segmantation fault und habe keine ahnung warum? ich wuerde mal auf ein adressproblem tippen.

    ich nehme an, du springst an die falsche adresse. es gibt aber einen einfachen weg, herauszufinden, was genau falsch läuft: genau, debugger anwerfen und durchtracen. gdb-Tutorials gibts genug falls das ein Problem sein sollte.


    Quote


    des weiteren wuerde mich auch interesieren, ob man fuer vuln1.c einen eigenen shellcode schreiben muss, oder einen schon vorhandenen nehmen kann? problem ist ja allerdings dieses gemeine stoppzeichen.

    Ach ja, dieses gemeine stoppzeichen...nachdem dieses ja im shellcode vom aleph one-tutorial 2x vorkommt, kann man diesen shellcode nicht so einfach verwenden [ich hoff mal ich hab jetzt nicht zuviel verraten...:rolleyes:]. überleg mal, was jede einzelne assembler-instruktion im shellcode genau macht. dann schau dir an, welche assembler-instruktion für das stoppzeichen verantwortlich ist. und dann ersetze die verantwortliche instruktion durch eine, die logisch gesehen dasselbe tut aber keine bösen zeichen enthält...ist recherchearbeit, ich weiß...
    übrigens nicht vergessen: wenn man den shellcode ändert kann es leicht passieren, dass die offsets der realtiven sprünge (call, jmp) nicht mehr passen. das muss man dann ebenfalls entsprechend anpassen.


    Tno:

    Quote

    Folgendes Problem: Bei Ausführung am Server bekomme ich immer einen segmentation Fault.
    Warum? Wie schaut hier der Stack aus?

    selbiges wie fuxi17...der debugger weiß alles. auch wie der stack aussieht. man muss ihn nur fragen. angenommen du hast irgendwo im programm einen breakpoint getriggert und willst wissen wie der stack gerade aussieht. dann würde ein befehl wie "p $esp" den aktuellen stack pointer ausgeben und "x/20xw $esp-32" den speicherbereich um den stack pointer. und so kann man sich recht gut ein bild von den abläufen im programm machen.


    Quote

    Vielleicht kann mir wer den movl esp,eax Befehl genauer erklären, ich dachte das wäre der stack
    pointer der immer an den Top of the Stack zeigt???

    "movl esp, eax" kopiert den stack pointer (esp) in das akkumulatorregister (eax). der stack pointer zeigt immer auf das zuletzt auf den stack gepushte (double)word.


    Quote

    Wie das Bsp exploit3.c im Dokument ausgeführt werden kann ohne einen Offset anzugeben ist mir auch
    ein Rätsel.
    Wenn ich die Ret-Addy, welche an den Anfang des Stacks zeigt, in den Buffer schreibe werde ich ja nicht
    mit der ret-addy in den Anfangsbereich des buffer Array zeigen??

    Mir ist die Frage nicht ganz klar...kannst du das eventuell anders formulieren? Soweit ich sehe, wird ja (zumindest implizit durch die konstante DEFAULT_OFFSET) ein offset angegeben...



    viel erfolg
    onkel_keks

    [chaas4747]: What the hell is a defence?
    [dermalin3k]:
    It's that wall in deyard between dehouses.

    Edited 2 times, last by onkel_keks ().

  • thx einmal für deine Hilfe, ich werde mir den Debugger genauer anschauen.


    Quote

    Mir ist die Frage nicht ganz klar...kannst du das eventuell anders formulieren? Soweit ich sehe, wird ja (zumindest implizit durch die konstante DEFAULT_OFFSET) ein offset angegeben...

    Ja es ist ein Default Offset von 0 angegeben, aber genau dieser Wert ist für mich nicht verständlich, da wir dann die adresse von get_sp() verwenden ohne Änderung. Nach meiner Überlegung verweist das dann falsch (Anfang des Stacks) und dadurch kann man dann nicht in die NOPs springen um den Shellcode auszuführen.


    Die Frage die sich mir noch stellt ist, warum overflow1.c und exploit3.c nicht funktionsfähig sind, wenn ich es genau nach dem Tutorial ausführe? (immer Seg-Fault)


    Code
    1. [aleph1]$ ./exploit3 612
    2. Using address: 0xbffffdb4
    3. [aleph1]$ ./vulnerable $EGG
    4. $

    Ist was beim InetSec Server anders (also die Arbeitsumgebung)?


    Ich weiß wie ich exploit3.c zum Laufen bringen theoretisch (offset richtig setzen :) ), ausprobiert habe ich es jetzt noch nicht, ist aber sicher nicht schwierig.



    Quote

    "movl esp, eax" kopiert den stack pointer (esp) in das akkumulatorregister (eax). der stack pointer zeigt immer auf das zuletzt auf den stack gepushte (double)word.


    Genau das ist aber das merkwürdige, denn so habe ich es mir auch gedacht, allerdings wenn ich nun testausgaben von get_sp() mache an verschiedenen Stellen in einem Programm, dann kommt immer die selbe Addy zurück!! egal ob ich davor nochmal int a = 2; oder float b = 3; habe !.
    Nach solchen Zuweisungen muss sich doch der Stackpointer ändern???


    Ein weiteres Bsp.: Ausgabe von get_sp() liefert immer eine höhere Adresse als der Anfang eines Buffer Arrays ??? wie soll das möglich sein wenn der Buffer ganz oben am Stack liegt und der Stack vom hohen zu niedrigem Adressspeicher wächst???


    -Tno

    Edited once, last by Tno ().

  • Quote

    Genau das ist aber das merkwürdige, denn so habe ich es mir auch gedacht, allerdings wenn ich nun testausgaben von get_sp() mache an verschiedenen Stellen in einem Programm, dann kommt immer die selbe Addy zurück!! egal ob ich davor nochmal int a = 2; oder float b = 3; habe !.
    Nach solchen Zuweisungen muss sich doch der Stackpointer ändern???

    achtung: durch zuweisungen alleine ändert sich der stack pointer nicht! wenn du mitten in einer funktion eine variable deklarierst, wird diese vom compiler zu den lokalen variablen gezählt, damit wird nur der stack frame der aktuellen funktion größer. der aleph one-artikel erklärt das mit folgendem diagramm (ich hoffe das forumssystem ruiniert die formatierung nicht komplett):


    Code
    1. bottom of top of
    2. memory memory
    3. buffer2 buffer1 sfp ret a b c
    4. <------ [ ][ ][ ][ ][ ][ ][ ]
    5. top of bottom of
    6. stack

    hier sind buffer2 und buffer1 lokale variablen und a, b, und c auf den stack gepushte werte(argumente für die funktion). in c kann man afaik nicht "direkt" werte auf den stack pushen; das geht nur explizit mit inline assembler oder implizit durch einen funktionsaufruf. wenn du folgendes machst

    dann bekommst du sehr wohl verschiedene stack pointer-werte.


    es ist für das verständnis hier sehr hilfreich (und wenn wir dann zu reverse engineering kommen umso mehr), nicht in C, sondern in Assembler zu denken.



    Quote

    Ein weiteres Bsp.: Ausgabe von get_sp() liefert immer eine höhere Adresse als der Anfang eines Buffer Arrays ??? wie soll das möglich sein wenn der Buffer ganz oben am Stack liegt und der Stack vom hohen zu niedrigem Adressspeicher wächst???

    [sorry, vorhin stand hier schwachsinn]
    wie hast du das getestet? bei mir liegen die lokalen variablen auf einer höheren adresse als der stack pointer...
    ich teste das so:


    und das gibt mir

    Code
    1. buffer: 0xbffffbf4
    2. sp: 0xbffffbc8


    Quote

    Ist was beim InetSec Server anders (also die Arbeitsumgebung)?

    Die Frage kann ich dir leider nicht eindeutig beantworten, da kenn ich mich mit Linux zu wenig aus. Mein Erklärungsversuch wäre folgender: Die Umgebungsvariable mit dem Shellcode wird in einem Programm, nennen wir es ./exploit, generiert. In diesem Shellcode steht als Sprungadresse eine absolute Speicheradresse (nämlich die, die die "echte" rücksprungadresse später überschreiben wird). diese absolute speicheradresse errechnet sich durch den vom user angegebenen offset und dem stack pointer auf der main() ebene von ./exploit. der so generierte shellcode wird nun in einem anderen programm, ./vulnerable, verwendet, unter der annahme, dass der stack pointer auf der main() ebene von ./vulnerable denselben wert hat wie der stack pointer auf der main() ebene von ./exploit. Und aus einem bestimmten Grund (wie gesagt, da reichen meine Linux-Kenntnisse nicht), trifft diese Annahme im Aleph ONe-Tutorial zu, aber auf unserem Server nicht (zumindest nicht immer). Daher kann es sein, dass die im Tutorial angegebenen Offsets nicht stimmen.
    Kann da evtl jemand der besser bescheid weiß was dazu sagen?

    [chaas4747]: What the hell is a defence?
    [dermalin3k]:
    It's that wall in deyard between dehouses.

    Edited 5 times, last by onkel_keks: blödsinn entfernt ().

  • Hi again,


    hier mal das Bsp mit dem ich teste (ist das exploit3.c nur wenig hinzugefügt zu testzwecken):


    Ergebnis:


    Code
    1. ./exploit3 612
    2. Using address - SP: 0xbffff3c8
    3. Using address - char *Buff: 0xb7fddff4
    4. Using address - SP: 0xbffff3c8
    5. Using address - char *buff: 0x804a008
    6. Using address - SP: 0xbffff3c8
    7. Using address - char *test: 0x804a270
    8. Using address - char *buff: 0x804a008
    9. Using address - SP: 0xbffff3c8


    Mir ist klar dass sich die Adresse des buffers nach dem malloc ändert, da ja vorher nicht angegeben ist wie groß es ist.


    Nun aber hier sieht man eindeutig dass die SP Adresse größer ist als die des Buffers, wie soll das möglich sein? Ich dachte ja, wie bereits erwähnt, dass der SP immer on the top of the stack (= niedrige Adresse im Speicher) zeigt.


    -Tno

  • hallo tno,


    jetzt verstehe ich was du meinst. ich dachte mit "buffer array" meinst du eine lokale variable.
    also zu deinem beispiel folgendes: dein buffer array ist keine lokale variable, sondern eine mittels malloc() alloziierte speicherregion. die tatsache, dass der zeiger auf diese speicherregion (buffer) eine lokale variable ist, hat hier keine bedeutung. wie man sieht, alloziiert malloc() den speicher in der "gegend" von 0x804aXXX. so.
    lokale variablen werden anders behandelt, denn sie werden am stack angelegt (wie das aleph one - tutorial erklärt). wenn man in einer funktion ein array deklariert, dann liegt dieses array auf dem stack. der stack liegt in einer eigenen "speicherregion", so um 0xbffffXXX. daher haben lokale variablen adressen in der region 0xbffffXXX und mittels malloc alloziierte speicherbereiche adressen in der region 0x804aXXX. das warum und die genauen umstände kann ich für linux leider nicht erklären; ich komm da eher von windows. auf jeden fall liegen stack-adressen aber eher weiter oben im speicher (eben bei 0xbffffXXX; eigtl. ja logisich, da der stack von oben nach unten wächst).
    malloc hat mit buffer overflows (oder zumindest mit diesem beispiel) aber wenig zu tun. wenn wir hier von "buffer overflow" reden, dann ist damit ein buffer gemeint, der am stack liegt (also eine lokale variable ist).

    [chaas4747]: What the hell is a defence?
    [dermalin3k]:
    It's that wall in deyard between dehouses.

    Edited once, last by onkel_keks ().

  • Hi onkel_keks,


    aso :),damn it so einfach.... daran habe ich ja gar nicht gedacht, obwohl ich das eigentlich auch selbst sehen hätte können...


    ja klar weiß ich dass das File (exploit3.c) nur ein Hilfsmittel ist um einen BO in einem anderen Prog. zu erzeugen/auszunutzen, trotzdem hat mir dieser wichtige, auch wenn simpler, Hinweis bzw. Info gefehlt. Thx für die Hilfe, jetzt ergibt es auch natürlich mehr Sinn - bzgl. Adressenvergabe in dem Fall.


    Das einzige was noch offen ist, ist warum die Examples vom Aleph nicht wie beschrieben lauffähig sind. Ohne Offset scheint dies ja aufm InetSec Server nicht zu laufen.


    Aja ich habe mich gerade eben mit dem gdb beschäftigt ... etwas verwirrend noch aber es wird langsam, ich nehm mal an die wichtigsten Sachen die man braucht ist frame, registers anzeigen, disas, display, list, break, s.


    Soweit ich sehe, kann man mittels frame ausgabe die RET (Return Address) auslesen, wobei man mittels disas <fkt> natürlich auch sieht was die RET sein sollte.
    Sobald die RET geändert wurde sollte dies ja unter frame anzeigen im gdb zu sehen sein unter saved eip oder?.. Ich probiere es aber eh gleich aus :)


    Hast du vielleicht noch Tipps zur gdb oder geh ich da eh richtig ran?


    Thx!


    -Tno

  • ach damn it, irgendwo fehlt mir noch immer der Zusammenhang.


    Wie komme ich dann in die NOPs rein wenn der char *buff (genauer gesagt "buff") und get_sp() ganz woanders hinverweisen??


    Kannst du oder wer anderer mir diese Schritte mal genauer erklären?


    -Tno


    Added: Ich habe das Exploit3.c so geändert dass es dem vuln1.c ähnelt, my_strcat und echo funktion (my_strcat ohne der x31 abfrage!).... nun wie gesagt ich checke das mit den adressen nicht, wenn ich statt der addr einfach "buff" addy eintragen lasse per for schleife, funktz. es einwandfrei... *(addr_ptr++) = buff;
    Wie soll das nun klappen wenn buff auf 0x804a.... addy verweist und addr auf 0xbffffba4 addy?.... da hilft nicht mal ein offset von einigen tausend....

    Edited once, last by Tno ().

  • 1.frage:


    ich habe nun vuln1.c so kommentiert, dass env nicht geloescht wird und auch das stoppzeichen ignoriert wird.
    dann habe ich exploit3.c vom tutorial 1:1 uebernommen und getestet. bei einer buffergroesse von 712byte oeffnete sich eine shell.
    dann habe ich mir eine debugausgabe in die funktion echo in vuln1.c hinzugefuegt, welche mir die startadresse von buf ausgiebt.
    beim ausfuehren von "exploit 712" erhielt ich "Using address: 0xbffffbb8", die adresse von buf lautete jedoch 0xbffff458.


    jetzt frage ich mich, wie das funktionieren kann??? die verwendete adresse mit der ich die ret ueberschreibe zeigt ja wo ganz anders hin als in den anfangsbereich des buffers??


    2.frage:


    wenn ich exploit3.c so aendere, dass ich meinen string nicht in $EGG lege und eine shell oeffne, sondern statt dessen execve verwende, funktionierts mit einer bufergroesse von 712byte ploetzlich nicht mehr.


    kann mir bitte jemand erklaeren wo da bloss wieder der hacken liegt??

    Es gibt nur einen Gott:
    Farin - Bela - Rod
    ---------------------------------------
    There are 10 types of people:
    those that understand binary,
    and those that don´t!!!

    Edited once, last by fuxi17 ().

  • Bei shellcodeasm im Alpeh one tutorial bewirkt der "jmp" Befehl einen ganz anderen Sprung als er dies im Tutorial tut.
    Statt diesem jmp:


    Code
    1. 0x8000133 <main+3>: jmp 0x800015f <main+47>


    bekomme ich diesen:


    Code
    1. 0x08048392 <main+14>: jmp 0x2a


    und ich versteh nicht warum

  • das jmp 0x2a sollte wohl eigentlich ein relativer jump sein, kein absoluter.
    opcode: 0xEB 0x2A
    (wenn ich mich nicht irre...aber bitte, bemüht doch eine referenz...)

    [chaas4747]: What the hell is a defence?
    [dermalin3k]:
    It's that wall in deyard between dehouses.

  • mal abgesehen davon - es ist ja sehr unterstützenswert, den shellcode verstehen zu wollen, aber so kurz vor der deadline...kopier doch einfach den shellcode vom tutorial, mach die notwendigen modifikationen daran (siehe stop-zeichen) und schau dass du fertig wirst...
    ich weiß nicht, wie du das mit dem jmp getestet/ausprobiert hast, aber irgendwas in deinem procedere passt nicht. denn der jmp war eigtl. kein problem. wie gesagt - ich würde mich jetzt nicht unbedingt darauf konzentrieren.
    oder hängst du dabei fest? dann versuch, dein problem genauer zu beschreiben.


    viel erfolg,
    onkel_keks

    [chaas4747]: What the hell is a defence?
    [dermalin3k]:
    It's that wall in deyard between dehouses.

  • Da ich nicht mehr zuversichtlich bin... hat es keine Eile - das mal vorweg (ich hab einfach zu spät damit angefangen, selbst schuld...). Aber kann mir jemand sagen wieso sich bei den "testsc.c" und "testsc2.c" shells vom Aleph One Tutorial auf dem Server nach dem kompilieren keine Shell aufmacht?
    Ja, mir ist klar, dass man den Code aufgrund von (0x00 und) 0x31 Character nicht verwenden könnte...


    Ich grüble schon seit heute Nachmittag rum und alles was nach dem Kompilieren und Ausführen passiert ist, garnichts. Kein segfault, keine invalid instruction, nichts... könnte mir jemand bitte sagen wieso das so ist?