4

I have a question about heap overflows.

I understand that if a stack variable overruns it's buffer, it could overwrite the EIP and ESP values and, for example, make the program jump to a place where the coder did not expect it to jump.

This seems, as I understand, to behave like this because of the backward little endian storing (where f.e. the characters in an array are stored "backwards", from last to first).

If you on the other hand put that array into the heap, which grows contra the stack, and you would overflow it, would it just write random garbage into empty memory space then?
(unless you where on a solaris which as far as I know has a big endian system,side note)
Would this basicly be a danger since it would just write into "empty space"?
So no aimed jumping to adresses and areas the code was not designed for?
Am I getting this wrong?

To specify my question:
I am writing a program where the user is meant to pass a string argument and a flag when executing it via command line, and I want to know if the user could perform a hack with this string argument when it is put on the heap with the malloc function.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
clockw0rk
  • 576
  • 5
  • 26
  • 1
    while any writing outside the bounds of an array on the stack or in the heap is undefined behaviour, leading to a seg fault event; the problem with the heap is that there are structures in the heap, that surround the allocated memory. These structures include the length of the allocated memory block and the address on the next allocated block. (certain 'pre-allocated' memory structs in the heap are implemented via arrays rather than as freeBlocks and allocatedBlocks as linked lists) In any case the coder should always put their best effort into NOT writing past the end of a buffer – user3629249 May 02 '15 at 03:46
  • 1
    another correction is that stack overflows cannot overwrite registers only memory. the way an attacker jumps to arbitrary locations is by overwritting the **return address** which is stored in the stack and EIP is set to that address when returning from the currently executing function. Of course, once the attackers code is running it can do anything to registers. – Diego May 02 '15 at 03:53
  • 1
    This has nothing to do with big-endian vs. little-endian architectures. That just affects things like whether the number 258 is stored as a 1 then a 2, or a 2 then a 1. It doesn't affect the order in which characters are stored in a string. Nor does it affect whether the stack grows upward or downward. – abarnert May 02 '15 at 04:05
  • 1
    "Backwards" is wrong, "little endian" is disconnected. Stack frame data is stored "forwards", but each new frame is below the last in address space. Endianness does not change that layout. – user3125367 May 02 '15 at 05:53

3 Answers3

8

If you on the other hand put that array into the heap, which grows contra the stack, and you would overflow it, would it just write random garbage into empty memory space then?

You are making a couple of assumptions:

  1. You are assuming that the heap is at the end of the main memory segment. That ain't necessarily so.

  2. You are assuming that the object in the heap is at the end of the heap. That ain't necessarily so. (In fact, it typically isn't so ...)

Here's an example that is likely to cause problems no matter how the heap is implemented:

  char *a = malloc(100);
  char *b = malloc(100);
  char *c = malloc(100);
  for (int i = 0; i < 200; i++) {
      b[i] = 'Z';
  }

Writing beyond the end of b is likely to trample either a or c ... or some other object in the heap, or the free list.

Depending on what objects you trample, you may overwrite function pointers, or you may do other damage that results in segmentation faults, unpredictable behaviour and so on. These things could be used for code injection, to cause the code to malfunction in other ways that are harmful from a security standpoint ... or just to implement a denial of service attack by crashing the target application / service.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
5

There are various ways heap overflow could lead to code execution:

  • Most obvious - you overflow into another object that contains function pointers and get to overwrite one of them.
  • Slightly less obvious - the object you overflow into doesn't itself contain function pointers, but it contains pointers that will be used for writing, and you get to overwrite one of them to point to a function pointer so that a subsequent write overwrites a function pointer.
  • Exploiting heap bookkeeping structures - by overwriting the data that the heap allocator itself uses to track size and status of allocated/free blocks, you trick it into overwriting something valuable elsewhere in memory.
  • Etc.

For some advanced techniques, see:

http://packetstormsecurity.com/files/view/40638/MallocMaleficarum.txt

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
2

Even if you can't overwrite a return address, how do you feel about an attacker modifying the rest of your data? This shouldn't thrill you.

To answer your question generally: it is a very bad idea to let the user copy data anywhere without checking its size. You should absolutely never do that, especially on purpose.

If the user means no harm, they may crash your program, either by overwriting useful data, or by causing a page fault. If your user is malicious, you're potentially letting them hijack your system. Both are highly undesirable.

Endianness does not matter to buffer overflows. Big endian machines are just as vulnerable as little-endian machines. The only difference will be the byte order of the malicious data.

You may be thinking instead of the direction the stack grows in, which is independent of endianness. In the case where it grows up, you won't be able to hijack the return address of the function that declares the buffer. However, if you pass that buffer address to any other function, and this function overflows instead, an attacker may change this function's return address. This would be the case, for instance, if you called memcpy of scanf or any other function to modify your buffer (assuming that the compiler didn't inline them).

The stack usually grows downwards. In this case, an attacker can use an overflow to hijack the return address of the function that declares it.

In other words, neither the stack configuration nor endianness offer meaningful protection against stack buffer overflows.

As for the heap:

If you on the other hand put that array into the heap, which grows contra the stack, and you would overflow it, would it just write random garbage into empty memory space then?

The answer, as almost always, is it depends, but probably not. The 32-bit implementation of malloc in glibc keeps bookkeeping structure at the end of the buffer (or at least, used to). By overflowing onto the bookkeeping structures with the correct incantations, when the allocation was freed, you could cause free to write four arbitrary bytes at an arbitrary location. This is a lot of power. This kind of exploit comes up regularly in capture-the-flag competitions and is very exploitable.

zneak
  • 134,922
  • 42
  • 253
  • 328