28

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 Answers 7

34

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

Sign up to request clarification or add additional context in comments.

1 Comment

Great answer. However, one minor comment -- (Blind) ROP actually defeats ASLR ieeexplore.ieee.org/xpl/…
13

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.

Comments

4

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".

3 Comments

But don't you also need to have access to the console in this case?
No. I was assuming the process's stdin is a socket or terminal you're connected to, but if not, just change "/bin/sh" to "/bin/sh 0<&n" where n is the file descriptor number of the server's socket for your connection.
Or of course you can change it to do whatever you want without an interactive shell, e.g. "echo 'toor::0:0::/:/bin/sh' >> /etc/passwd"
1

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

2 Comments

In theory, you can do it yourself, it's essentially just a bunch of calls to mprotect(2).
No problem :) Just remember that the most important thing to do is to make sure that memory is not both writable and executable at the same time.
1

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

1 Comment

This doesn't add anything to the accepted answer posted 3 years earlier, and makes an irrelevant claim about memory layout that may or may not apply. Your own citation says "With large address spaces and virtual memory techniques [segments] tend to be placed more freely".
0

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.

1 Comment

The question appears to be about the case when everything except the program's code is in non-executable memory. How do you load your code into executable memory then? Jumping to it may be easy.
0

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

1 Comment

To begin with, how do you load your code into executable locations if everything but the program's code is in non-executable memory? Address space randomization alone doesn't prevent ROP-based exploits. See my answer.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.