Vulnerability Development mailing list archives

Re: Traceroute exploit details


From: Daniel Jacobowitz <dmj+ () ANDREW CMU EDU>
Date: Tue, 3 Oct 2000 12:49:01 -0400

[I'm moving this over to vuln-dev...]

On Mon, Oct 02, 2000 at 10:18:33PM -0700, pedward () WEBCOM COM wrote:
Today I read up on the Solar post on heap overflows with free and looked at
traceroute again.  I decided to take the bent that it COULD be overflowed.
I found the addresses of __malloc_hook (0x40074ff8) on RH6.0 and the location
that our string gets allocated (0x804cd7a).

So, I got the SRPM for glibc and looked over the code for free.  It looked
kinda promising, excerpt:

      if (!(inuse_bit_at_offset(next, nextsz)))   /* consolidate forward */

That's the problem right there, if I recall correctly.  We have to have
the next chunk in reachable memory, which constrains the size - I don't
think anything is in reachable memory on a little-endian machine, where
the next chunk size comes immediately before a chunk being free()'d,
and thus in this case must end with a null terminating byte.

To make this exercise work, we would need 2 rogue malloc_chunks: rogue1 and rogue2.

The fd and bk pointers in malloc_chunk could be used for the overflow:

Nope.  You're misunderstanding malloc_chunk's use.  Look at the
definition of mem2chunk: fd and bk are on the free list, and malloc
only looks at them if it assumes they are free.  The chunk only starts
2 * sizeof(INTERNAL_SIZE_T) before the pointer given, not
sizeof(malloc_chunk) as you assumed.

In rogue 1, it would have the following values:

prev_size = "CCCC"
size      = "CCCC"
fd        = __malloc_hook - 12
bk        = 0x804cd7a + 0x20 (our rogue code)

In rogue 2, it would have the following values:

prev_size = "CCCC"    (dead value)
size      = 0xFFFFFF01        (0xFFFFFF00 & 0x01 (PREV_INUSE)
fd        = "CCCC"    (dead unused value)
bk        = "CCCC"      (dead unused value)

You could make such chunks, hypothetically, but you'd be freeing a
chunk #3 after the both of them.

The first '-g' argument would look like this:

offset        value
0x00  "CCCC"
0x04  "CCCC"
0x08  __malloc_hook - 12
0x0C  0x804cd7a + 0x0F
0x10  jmp +0x0F
 |
 |    garbage
 |
0x1F
0x20
 |
 |    code to execute
 |
0xF0  "CCCC"
0xF4  0xFFFFFF01
0xF8  "CCCC"
0xFC  "CCCC"

It's not at all easy to get that into a -g argument: (a) you need to
put the code somewhere else, there's a 64char or so length limit on -g
(b) there's character set restrictions.

Also, as above, you're wrong about what goes where.  Note that the high
0xFF in the size will be forced to a zero, and the CCCC's are unneeded.

The theory about how it works:

When the second '-g' is encountered, free() reads ptr - 0x0F for the malloc_chunk.
Our rogue2 malloc_chunk is the last bit of data, which points to the one with our
pointers, free sees that PREV_INUSE on the second chunk is 0x0, so it tries to
consolidate the chunks.  We get at the address of our rogue1 chunk by rolling over
the address space - 0xFF (for our data).  The 0x01 is to prevent backlinking of
our chunk, and it handy to get a NULL too (it gets XORed with 0x01 when the size
is calculated).

You're trying to get chunk 1 and 2 consolidated; you can't do that. 
This would work if you had some way to put data in memory just after
the unallocated area you try to free(), but in this case there's no way
to.

Dan

/--------------------------------\  /--------------------------------\
|       Daniel Jacobowitz        |__|        SCS Class of 2002       |
|   Debian GNU/Linux Developer    __    Carnegie Mellon University   |
|         dan () debian org         |  |       dmj+ () andrew cmu edu      |
\--------------------------------/  \--------------------------------/

Attachment: _bin
Description:


Current thread: