[17017] in bugtraq
Traceroute exploit details
daemon@ATHENA.MIT.EDU (pedward@WEBCOM.COM)
Tue Oct 3 12:44:42 2000
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Message-Id: <200010030518.WAA00872@eris>
Date: Mon, 2 Oct 2000 22:18:33 -0700
Reply-To: pedward@WEBCOM.COM
From: pedward@WEBCOM.COM
To: BUGTRAQ@SECURITYFOCUS.COM
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 */
{
sz += nextsz;
if (!islr && next->fd == last_remainder(ar_ptr))
/* re-insert last_remainder */
{
islr = 1;
link_last_remainder(ar_ptr, p);
}
else
unlink(next, bck, fwd);
next = chunk_at_offset(p, sz);
}
The macro 'unlink':
/* take a chunk off a list */
#define unlink(P, BK, FD) \
{ \
BK = P->bk; \
FD = P->fd; \
FD->bk = BK; \
BK->fd = FD; \
} \
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:
struct malloc_chunk
{
INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */
INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */
struct malloc_chunk* fd; /* double links -- used only if free. */
struct malloc_chunk* bk;
};
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)
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"
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).
During the consolidation phase the unlink macro dorks with the chunk of memory directly
after rogue1, so you have to put a relative jump to get over it.
The rogue code appears at offset 0x20 in parameter of the first '-g' and is 208 bytes long.
I think I got all the numbers right, but I may have been off a little here or there.
I didn't actually write the code, just thought it through, but it looks like it's
exploitable to me.
I got the pointer values from an RH6.0 version, RH6.2 has the same bug, possibly the same
offsets.
Further discussion would be enlightening.
--Perry
--
Perry Harrington Director of zelur xuniL ()
perry@webcom.com System Architecture Think Blue. /\