After using the "-z noexecstack" option to compile a C program, a buffer-overflow attack that causes the vulnerable program to return to the code on the stack is supposed to fail, but some students find out that the attack is still successful. What could be the reason? The students did everything correctly.
Solution:
Buffer overflow is defined as the condition in which a program attempts to write data beyond the boundaries of pre-allocated fixed length buffers. This vulnerability can be utilized by a malicious user to alter the flow control of the program, even execute arbitrary pieces of code. This vulnerability arises due to the mixing of the storage for data (e.g. buffers) and the storage for controls (e.g. return addresses): an overflow in the data part can affect the control flow of the program, because an overflow can change the return address.
We can load the shellcode into “badfile”, but it will not be executed because our instruction pointer will not be pointing to it. One thing we can do is to change the return address to point to the shellcode. But we have two problems: we do not know where the return address is stored, and we do not know where the shellcode is stored. To answer these questions, we need to understand the stack layout the execution enters a function
Finding the address of the memory that stores the return address.
From the figure, we know, if we can find out the address of buffer[] array, we can calculate where the return address is stored. Since the vulnerable program is a Set-UID program, you can make a copy of this program, and run it with your own privilege; this way you can debug the program (note that you cannot debug a Set-UID program). In the debugger, you can figure out the address of buffer[], and thus calculate the starting point of the malicious code. You can even modify the copied program, and ask the program to directly print out the address of buffer[]. The address of buffer[] may be slightly different when you run the Set-UID copy, instead of of your copy, but you should be quite close.
If the target program is running remotely, and you may not be able to rely on the debugger to find out the address. However, you can always guess. The following facts make guessing a quite feasible approach:
Stack usually starts at the same address.
Stack is usually not very deep: most programs do not push more than
a few hundred or a few thousand bytes into the stack at any one
time.
Therefore the range of addresses that we need to guess is actually
quite small.
(2) Finding the starting point of the malicious code.
If you can accurately calculate the address of buffer[], you should be able to accurately calcuate the starting point of the malicious code. Even if you cannot accurately calculate the address (for example, for remote programs), you can still guess. To improve the chance of success, we can add a number of NOPs to the beginning of the malcious code; therefore, if we can jump to any of these NOPs, we can eventually get to the malicious code. The following figure depicts the attack.
n your exploit program, you might need to store an long integer (4 bytes) into an buffer starting at buffer[i]. Since each buffer space is one byte long, the integer will actually occupy four bytes starting at buffer[i] (i.e., buffer[i] to buffer[i+3]). Because buffer and long are of different types, you cannot directly assign the integer to buffer; instead you can cast the buffer+i into an long pointer, and then assign the integer. The following code shows how to assign an long integer to a buffer starting at buffer
efore working on this task, remember to turn off the address randomization first, or you will not know which protection helps achieve the protection.
In our previous tasks, we intentionally make stacks executable. In this task, we recompile our vulnerable program using the noexecstack option, and repeat the attack in Task 1. Can you get a shell? If not, what is the problem? How does this protection scheme make your attacks difficult. You can use the following instructions to turn on the non-executable stack protection.
gcc -o stack -fno-stack-protector -z noexecstack stack.c
It should be noted that non-executable stack only makes it
impossible to run shellcode on the stack, but it does not prevent
buffer-overflow attacks, because there are other ways to run
malicious code after exploiting a buffer-overflow vulnerability.
The return-to-libc attack is an example.
root@ubuntu:/home/seed/Desktop# sysctl -w
kernel.randomize_va_space=0
kernel.randomize_va_space = 0
root@ubuntu:/home/seed/Desktop# gcc -o stack -z noexecstack
-fno-stack-protector stack.c
root@ubuntu:/home/seed/Desktop# chmod u+s stack
root@ubuntu:/home/seed/Desktop# exit
exit
seed@ubuntu:~/Desktop$ ./stack
Segmentation fault (core dumped)
#please consider my effort and give me a like...thank u....
Get Answers For Free
Most questions answered within 1 hours.