25
votes

I read a book about buffer overflow, and it suggest the next to deal with:

Making the stack (and heap) non-executable provides a high degree of protection against many types of buffer overflow attacks for existing programs.

But I don't understand how we can do it - where the execute would take place, if not on the heap or on the stack?

7

7 Answers

30
votes

If I understand your question correctly, none of the other answers address it. The answer is that execution occurs in the code section, which is neither stack nor heap. In a typical paged memory system, the code from a program file (e.g., a .exe in Windows) is loaded into executable but read-only pages. Additional writable (and executable) pages are allocated to the process for the stack and heap. The suggestion here is that the operating system and hardware should cooperate to mark those pages writable but not executable (rgngl's answer explains how to do that in Windows).

Even with non-executable heap and stack, exploits are still possible that use the return-oriented programming mentioned in Alexey Frunze's answer, but there are protection techniques that stymie even those, such as stack-smashing protection and address space layout randomization -- see http://en.wikipedia.org/wiki/Return-to-libc_attack#Protection_from_return-to-libc_attacks

11
votes

There's what's called "return-oriented programming" (AKA ROP) type of exploits.

The attacker finds how to make his evil code out of different pieces of the program that's being exploited.

He finds usable byte sequences (instructions) before the return instruction byte(s) that can do useful operations on registers or memory like move a value to a location, add values, compare values, etc etc. Those are micro subroutines that the exploit gets built of.

Then by exploiting a code bug the attacker forces the program to start executing the chain of those micro subroutines that does all the evil work.

So, now good code turns into evil code. Nothing's executed on the stack or in the heap.

It's also noteworthy that on CPUs where instructions span multiple bytes and are of variable length, even the immediate instruction operands (IOW, numerical constants) that are part of instructions can become code, and so the chances of finding usable byte sequences are higher there than on "simpler" CPUs.

It's also often possible to construct malicious code that will change memory protection and the exploit will no longer be constrained by the existing application's code.

4
votes

Very concrete example: Arrange for the return address to point to system and the next slot on the stack (or the first argument register on pass-by-register archs) to be a pointer to the string "/bin/sh".

1
votes

That kind of protection is provided by the OS and cannot be done in the application layer.

See the wikipedia article, which also tells how to enable it under Windows: http://en.wikipedia.org/wiki/Data_Execution_Prevention

1
votes

Your code runs in the text segment, not in the stack or the heap (both of which are for data storage). So the organization is:

<highest addresses>
stack
...
heap
data section (initialized data & bss - uninitialized data) 
code section (text)
<lowest addresses> 

The code section is executable but immutable. This wikipedia article has more details: https://en.wikipedia.org/wiki/Data_segment

0
votes

you can jump to any other place which is executable segment and run your evil code...

After all, All the data on any storage, memory is bits and bits can be instructions to the cpu to execute.

0
votes

You can use your overflow to overwrite the return address of a function, which can jump to some known address with your code on it. But then OS writers responded by randomizing the address code is executed on...