Exploit-DB #20250
Description: LBL Traceroute 1.4 a5 - Heap Corruption (1)
Type: local
Platform: linux
Date: 2000-09-28
Author: Dvorak

Exploit:
// source: https://www.securityfocus.com/bid/1739/info

Traceroute is a well-known network diagnostic tool used for analyzing the path on a network between two hosts. On unix systems, traceroute is typically installed setuid root because of its use of raw sockets. Certain versions of LBNL traceroute are vulnerable to an interesting attack involving freeing of pointers pointing to unallocated memory.

When traceroute is executed with the arguments "-g x -g x", the function "savestr()" is called twice. savestr() does what strdup() does without the extra malloc() call and is used when parsing the hostname or "dotted quad notation" ip address argument to the -g parameter. It uses a block of pre-allocated memory instead of allocating memory itself. After the first instance of "-g" is parsed and savestr() is called, the pointer to the block used by savestr() is unallocated via free(). When the next gateway parameter (-g) is interpreted, savestr() is called again and the user data argument is written to the block of unallocated memory. Like in the first instance, free() is called on the pointer to where the data begins inside the old-buffer of unallocated memory. When free() doesn't find a valid malloc header before the pointer it is passed, traceroute crashes.

What makes this possibly exploitable is that the region of memory to which the pointer points is user-controlled and can be written to with (somewhat) arbitrary data before free() is called. An attacker may be able to construct a malicious malloc() header and carefully stuff it into the first savestr() buffer, so that is there when free() looks for it after the second savestr(). What complicates exploitation of this issue are the functions involved with savestr(), inet_addr() and gethostbyname(), which limit the type of user data that can be put into the buffer (which would need to be binary). If pulled off, however, it may be possible to overwrite aribitrary locations in the heap (such as a function pointer) with arbitrary data.

If successfully exploited this would yield local root access for the attacker. 

            LBL traceroute exploit.

         By Dvorak, Synnergy Networks
                www.synnergy.net

Vulnerable:
	All versions of LBL traceroute using savestr.
	See Chris Evans post in bugtraq
	(http://www.securityfocus.com/archive/1/136215)
Discovery:
	Pekka Savola (pekkas@netcore.fi)
	Published to bugtraq by: Chris Evans
	(chris@ferret.lmh.ox.ac.uk)
	http://www.securityfocus.com/archive/1/136215
Exploit:
	dvorak (dvorak@synnergy.net)
Exploit successful:
	RH 6.1 RH 6.2 Debian 2.2
Exploit not successful:
	Debian woody (didn't check source)
	Slackware 7.1: non vulnerable traceroute
	
Patches
-------

Should come from your vendor. The flaw was published about two weeks
ago, every vendor should have a patch by now.

Description & Vulnerability
---------------------------

Please take a look at Chris Evans post:
http://www.securityfocus.com/archive/1/136215

Thanks
------
Scrippie (ronald@synnergy.net)
 for the idea about MALLOC_TOP_PAD_ since that got me started again.

Dethy (dethy@synnergy.net)
Emphyrio (Robert van der Meulen, rvdm@cistron.nl)
 both for valuable comments to the text.

Sonnema en dr. Pepper
 for providing the drinks needed to build the exploit.

Exploit + Story
---------------

This text starts with the story about the exploit. The exploit can be found at the
end, but getting it to work might require reading the story.

I won't go into details about malloc internals because i think it's
not needed and you should be able to find that out yourself. (ok
probably closer to the truth is that i can't explain it as clear as
the source of malloc does: i don't understand the malloc internals
well enough to be able to explain it clearly.)

What you should know is that the internals of malloc work with chunks
in which they keep the data. Malloc gives out a pointer to the memory
to the user. These pointers are actually ((char *)chunk)+8, hope that
helps in the explanation. Its possible to get free() to work with
incorrect chunks, which is the base for the exploit.

Using nice ascii it looks like:

chunk
 |
 |
 +--->+--------------
      | prev_size
      +--------------
      | size
 +--->+--------------
 |    | fd  or data
 |    +--------------
 |    | bk  or data
 |    +--------------
 |    | ....
 |
mem

chunk is used as pointer in the internals of malloc while mem is the
pointer given to the user. If the chunk is not being used (that is
the chunk hasn't been given to the user using malloc() or the user
has retunred the chunk) fd and bk are used to hold pointers. If chunk
is in use they are used to hold data.


What happens if free(mem) is called?

First free() converts mem into a chunk ((char *)mem) - 8) on the
Intel. free() then calls chunk_free() to do the rest.

The chunk given to chunk_free() as argument will be called 'p' during
the rest of the text. Using p->prev_size (the size of the previous
chunk) and p->size (the size of chunk p) chunk_free() finds the
previous chunk (called prev from now on) and the next chunk (called
next from now on). It then checks if next and/or prev are chunks
which aren't in use (by checking chunk->size & PREV_INUSE). If they
aren't p is linked into the double linked list of free chunks using
the fd and bk field of prev and/or next.

This linking into the free chunks list is done using the macro
'unlink':

#define unlink(P, BK, FD) \
{                         \
  BK = P->bk;             \
  FD = P->fd;             \
  FD->bk = BK;            \
  BK->fd = FD;            \
}

If we manage to let chunk_free call unlink() with a chunk of which
the fields fd and bk have been filled in by us, we will be able to
change values in memory:

if chunk->fd = (int *) x and chunk->bk = (int *) y
after an unlink() of that chunk
x[3] will be y
and
y[2] will be x

exam