Vulnerability Development mailing list archives

Re: Buffer Overflow Help


From: "Steve Bonds" <kzzvt3302 () sneakemail com>
Date: Mon, 15 Nov 2004 11:11:31 -0800

Chris:

First off, thanks for the superb information!  In particular the
specific references lead me
to just where I needed to look where Google and grep had both failed.

On Sun, 14 Nov 2004 22:24:17 -0800, Chris Eagle wrote:

You need to read the kernel sources to understand what happens when a
process starts up.  For specific information on the behavior you are witnessing, I
suggest you take a look at the file fs/binfmt_elf.c, specifically the
create_elf_tables function.

I looked at this and found the line where the stack pointer gets tweaked:

---- RH9 2.4.20-8 binfmt_elf.c line 159 ----
        sp = (void *) (u_platform - (((current->pid+jiffies) % 64) << 7));
----

This is introduced by the Red Hat patch
"linux-2.4.20-stackcoloring.patch".  (In hindsight, if I'd looked for
every Red Hat kernel patch with "stack" in the name, I would have
found this.)

2. The size of the padding is cyclic based on PID. If you have discovered a
return address that will successfully exploit a process, then that same
return address should work at least 1/64 of the time because every time 
the process is rerun with a pid that differs from your original pid by a multiple
of 64, the padding will be the same size and all stack-based buffers should 
fall in the same place as they did for your successful exploit. With this in mind, if
you find a return address that should work but doesn't, rerun your exploit and
the change in padding will drive your payload towards your return address.

This is confirmed by the above code, with current->pid % 64 serving as
one factor in determining the stack pointer.

3. The padding grows by 128 bytes each time the PID increments by one.

This follows from the "<< 7" in the above code, but this varies in
practice because of the inclusion of jiffies (as you noted).

The most common change in the stack pointer on my Red Hat 9 system was
a decrement of 384 bytes, with a decrement of 512 bytes as a close
second.

(If any of you are wondering what a "jiffy" is, try this:
http://www.kernelnewbies.org/glossary/#J -- it's a simple incrementing
counter that wraps.)

These statistics are from a test of about 300,000 runs of the "stackp"
program run as fast as I could via:

i=0; while true; do echo $i `./stackp`; i=`expr $i + 1`; done

I never saw a jump of less than 384 bytes.  The minimum stack pointer
I saw was 0xbfffd9a4 and the maximum was 0xbffff924, separated into 64
slices of 128 bytes each.

RedHat throws a wrench into this as jiffies factors into their equation
along with PID, so things do not seem to progress quite linearly all of the time.
The maximum padding size remains restricted to 8k however.

I agree, this stack-based exploit would work nicely if I could get 8k
of NOP sled in place.  Unfortunately, I can't.  I might be able to get
200 bytes, but this just reduces my odds from 1/64 to 1/32.

Someone else has suggested a return-to-libc approach.  I'm not
familiar with this method of exploiting, so I'll have some reading to
do.  From what I've been able to discern, this method is probably
better suited for a local exploit, where I can explore the libc in
memory to determine where to jump.  I don't yet see how this would
work remotely unless libc uses the same address each time for
system().

Thanks again for the excellent information on where to look for the
answer to this problem.

  -- Steve


Current thread: