Speicheradresse überspringen

#1
Hallo Leute!

Ich habe vor kurzem ein tut über exploids gefunden insecure.org/stf/smashstack.html
Jetzt habe ich mich mal etwas mit dem Thema versucht zu befassen und habe ein paar Fragen.

Dazu muss ich sagen ich arbeite auf einer 64bit maschine

zu erstmal wird Speicher ja immer durch das vielfache des Datenwortes allokiert heißt bei mir ich kann nur speicher mit dem Vielfachen von 8 byte allokieren
wenn ich jetzt aber

Code:
void function(int a, int b, int c) {
  
 char buffer1[5];
 char buffer2[10];
}
schreibe dann müsste er doch für den ersten buffer 8 byte reservieren weil er ist ja nur 5 groß für den zweiten buffer würden 2 Datenworte reichen also 16 byte aber er allokiert den ersten mit 16 byte und den zweiten mit 32 byte warum ? (das weiß ich weil ich mir mit gcc -S den assembler code angeschaut habe )

als nächstes versuche ich gezielt eine neue Return adresse zu setzen und somit eine Anweisung im Code zu überspringen wie im tut beschrieben

Code:
void function(int a, int b, int c)
{
    char buffer1[5];
    char buffer2[10];
    int *ret;
    
   ret = buffer1 +24;
    (*ret) +=17;
}

void main(){
  
  int x;
  
  x=0;
  
  function(1,2,3);
  x=1;
  
  printf("%d\n",x);
  
}
hier ist die zeile x=1 das was ich überspringen möchte mit ret = buffer1[]+24 gehe ich an das ende der adresse von buffer 1 auf 24 komme ich in dem ich 16 byte so groß ist der buffer + 8 byte (länge des Datenworts ) auf addiere so und dann zähle ich auf die ret noch mal 17 byte drauf um die zeile mit x =1 zu überspringen die 17 byte ergeben sich aus gdb

Code:
Dump of assembler code for function main:
   0x000000000040059a <+0>:    push   %rbp
   0x000000000040059b <+1>:    mov    %rsp,%rbp
   0x000000000040059e <+4>:    sub    $0x10,%rsp
   0x00000000004005a2 <+8>:    movl   $0x0,-0x4(%rbp)
   0x00000000004005a9 <+15>:    mov    $0x3,%edx
   0x00000000004005ae <+20>:    mov    $0x2,%esi
   0x00000000004005b3 <+25>:    mov    $0x1,%edi
   0x00000000004005b8 <+30>:    callq  0x400564 <function>
   0x00000000004005bd <+35>:    movl   $0x1,-0x4(%rbp)
   0x00000000004005c4 <+42>:    mov    $0x4006cc,%eax
   0x00000000004005c9 <+47>:    mov    -0x4(%rbp),%edx
   0x00000000004005cc <+50>:    mov    %edx,%esi
   0x00000000004005ce <+52>:    mov    %rax,%rdi
   0x00000000004005d1 <+55>:    mov    $0x0,%eax
   0x00000000004005d6 <+60>:    callq  0x400460 <printf@plt>
   0x00000000004005db <+65>:    leaveq 
   0x00000000004005dc <+66>:    retq
nach aufruf der Funktion kann man erkennen das eine 1 in den rpb (stack pointer ) geschrieben wird das ist nun die zeile die ich überspringen möchte also springe ich zu <+47> daher kommen nun die 17 byte allerdings bekomm ich dann nach dem ausführen des programmes nichts mehr ausgegeben ? warum rechne ich etwas falsch oder springe ich zur falschen adresse ? wo werden die 17 byte auf den rpb aufaddiert (müsste doch irgenwo zu finden sein im assembler ?)

Ich hoffe ihr könnt mir weiter helfen und ich habe mich deutlich genug ausgedrückt .. hoffe das ist der richtige platz für den Thread wenn nicht entschuldigung einfach verschieben Danke
 
#2
Also zuerst mal bevor ich irgendwie versuche zu helfen...
EXPLOITS SIND ILLEGAL!!!

Aber ich gehe einfach mal davon aus das du, so wie ich auch einmal, einfach Interesse am Thema hast und nicht vorhast den programmierten Exploit einzusetzen...


Das mit dem Speicher ist einfach beantwortet...
Wenn du einen String von 5-Zeichen hast, reserviert sich das OS mehr Zeichen als angegeben... Die genaue Zahl kenne ich nich aber es sind vorher und nachher ein Paar reserviert um Anfang/Ende oder eventuelle Speicherbezeichnungen aufzunehmen...
Deshalb kommst du mit den 10-Zeichen wahrscheinlich nich hin...
Angenommen vorher werden 3 und dahinter werden 5 Zeichen reserviert (is nur ein Beispiel) dann bist du mit 18 Zeichen über der 16-Bit Marke...
Dabei werden dann 32-Bit reserviert...

Beim Rest bin ich mir unsicher ob ich das laut Regeln erklären darf und mein letzer Versuch in dem Bereich is 2 Jahre her deshalb is es eh nich möglich dir meinerseits noch zu helfen...

Ansonsten versuch es mal mit anderen Tutorials die vllt beschreiben wie es 100% klappt und vllt findest du dann deinen Fehler
 

xrayn

New member
#3
@MCStreetguy: Exploits sind nicht illegal, wer erzählt denn so etwas?

Ein disassembly von der Funktion "function" wäre hilfreich. Hier kannst du dann nämlich sehen wie viel Speicherplatz auf dem Stack reserviert wird - ähnlich wie bei der main-Funktion (in diesem Fall 16 Byte)

Code:
0x000000000040059e <+4>:    sub    $0x10,%rsp
idR ist dein Stack so aufgebaut:

lower addresses ... local var | saved basepointer | ret | call args ... higher addresses

Das gilt aber nur https://de.wikipedia.org/wiki/Aufrufkonvention#stdcall , in deinem Fall werden die Funktionen https://de.wikipedia.org/wiki/Aufrufkonvention#.C3.9Cbersichtstabelle_Aufrufkonventionen.5B2.5D aufgerufen, das siehst du daran, dass die Parameter in die Register EDX, ESI und EDI geladen werden:
Code:
0x00000000004005a9 <+15>:    mov    $0x3,%edx
0x00000000004005ae <+20>:    mov    $0x2,%esi
0x00000000004005b3 <+25>:    mov    $0x1,%edi
0x00000000004005b8 <+30>:    callq  0x400564 <function>
Ist für dein Problem aber nicht relevant, sondern nur gut zu wissen ;) Was für dich noch relevant sein könnte, sind Stackcookies (pseudozufälliger Wert zwischen saved bp und ret-addr), wodurch sich das Stacklayout noch einmal verändert.
 

CDW

Moderator
Mitarbeiter
#4
?

Das mit dem Speicher ist einfach beantwortet...
Wenn du einen String von 5-Zeichen hast, reserviert sich das OS mehr Zeichen als angegeben...
...
Deshalb kommst du mit den 10-Zeichen wahrscheinlich nich hin...
Angenommen vorher werden 3 und dahinter werden 5 Zeichen reserviert (is nur ein Beispiel) dann bist du mit 18 Zeichen über der 16-Bit Marke...
Dabei werden dann 32-Bit reserviert...
Bitte was?
Hier generiert der Compiler Code, der den ganzen Stackkram verwaltet. Aber auch bei expliziten allozierungen mit malloc wird i.d.R nicht das OS belästigt/beauftragt, sondern eine Heap-Bibliothek.

Daher wäre die Compilerversion samt Flags von Interesse.

I.d.R gibt es mehrere Faktoren, die die Größe beeinflussen - "Stackcookies"/Canaries", "Off-By-One" Schutz sowie Alignment als Optimierung.
Das Endergebnis kann man als Programmierer rein theoretisch nicht beeinflussen - denn wie der Compiler das nun tatsächlich umsetzt (Stackvariable, Heap oder reservierter Block in der Executable selbst oder inlining der aufgerufenen Funktion), bleibt diesem überlassen.

Rein praktisch gibt es die Compilerflags sowie "interne" Dokumentation - das ganze ist aber compilerabhängig. Aber das "Abschätzen" aus den Arraygrößen funktioniert schon länger nicht mehr ;).


In diesem Fall wäre diese Option von Interesse:
gcc -mpreferred-stack-boundary=2 bla
gcc doku hat gesagt.:
-mpreferred-stack-boundary=num
Attempt to keep the stack boundary aligned to a 2 raised to num byte boundary. If -mpreferred-stack-boundary is not specified, the default is 4 (16 bytes or 128 bits).
 
#5
Also zuerst mal bevor ich irgendwie versuche zu helfen...
EXPLOITS SIND ILLEGAL!!!

Aber ich gehe einfach mal davon aus das du, so wie ich auch einmal, einfach Interesse am Thema hast und nicht vorhast den programmierten Exploit einzusetzen..
]

Die genaue Zahl kenne ich nich aber es sind vorher und nachher ein Paar reserviert um Anfang/Ende oder eventuelle Speicherbezeichnungen aufzunehmen...
]

18 Zeichen über der 16-Bit Marke...
Dabei werden dann 32-Bit reserviert...
]

Beim Rest bin ich mir unsicher ob ich das laut Regeln erklären darf
]
 
Oben