Ich versuche, rücksprungorientierte Programmierung (ROP) zu lernen.
Und zwar habe ich ein Programm mit einem Pufferüberlauf auf dem Stack, und ich möchte das Programm dazu bringen, /bin/sh zu öffnen.
Das geht mit dem execve Syscall, wenn ich die richtigen Instruktionen finden kann, um die Funktionsparameter vorzubereiten. Das ist die Signatur von execve:
int execve(const char *pathname, char *const _Nullable argv[], char *const _Nullable envp[]);
Also muss ich die folgenden Register setzen:
- rax = 0x3b (Syscallnummer von execve)
- rdi = "/bin/sh" Pointer
- rsi = NULL
- rdx = NULL
Die folgenden Instruktionen habe ich bereits gefunden:
pop rax ; ret
pop rdi ; ret
pop rsi ; ret
pop rdx ; ret
syscall
Ich kann also die Instruktionen und Registerwerte mit dem Pufferüberlauf auf den Stack schreiben und so meine Register füllen. Das Problem ist aber, dass ich einen "/bin/sh" Pointer in rdi brauche (also nicht "/bin/sh" im Register, sondern eine Speicheradresse, an der "/bin/sh" steht).
Ich kann natürlich "/bin/sh" in den Puffer auf dem Stack schreiben, aber leider ist die Speicheradresse jedes Mal anders und ich kenne sie vorher nicht.
Ich weiß, dass "/bin/sh" in libc vorkommt, aber auch dort ist die Speicheradresse jedes Mal anders und ich kenne sie vorher nicht.
Wie komme ich also an einen "/bin/sh" Pointer? Gibt es Tricks oder bestimmte Instruktionen, nach denen ich mich umsehen sollte?