OSEC

Neohapsis is currently accepting applications for employment. For more information, please visit our website www.neohapsis.com or email hr@neohapsis.com
 
From: Ben Laurie (benalgroup.co.uk)
Date: Sat Jun 22 2002 - 12:31:10 CDT

  • Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]

    Ulf Bahrenfuss wrote:
    > Hi!
    >
    > Does anyone know, if the chunk handling vulnerability carries through
    > a proxy i.e. Squid or Webcache? (Updating is currently not possible,
    > because it is not the plain apache, but the Oracle IAS flavour...)
    >
    > Or has anyone further information how this vulnerabilty really works?

    Here's an analysis I wrote for iternal use at the ASF - it doesn't go
    into detail on the shellcode (which is just the usual shellcode), but
    does explain how the expected SEGV from overrunning the stack is
    avoided. Note that someone (sorry, forgotten who) posted a similar
    generic analyis a day or two ago - this one was independently arrived at
      and refers to the Gobbles attack specifically.

    First, the exploit code puts stuff on the stack (legitimately, in
    buffers). It then arranges a negative offset, as previously described,
    to be handed to memcpy. Here's where it gets cute. memcpy has memmove
    semantics (i.e., it copies in the correct direction to handle
    overlapping source/dest) on both OpenBSD and FreeBSD (in fact, I believe
    this is a requirement for this exploit to work on any system where the
    stack grows downwards). As a result, when the memcpy is attempted, it is
    done backwards (i.e. the copy starts at source+length-1 -> dest+length-1
    and downwards for length bytes). Now, here's the cute bit. memmove (et
    al) are optimised to copy in 4 byte chunks, for speed. This means that
    they have to copy the leftover bytes separately. This is handled by
    copying the odd 0-3 bytes before the remaining bytes.

    So, if you arrange for the negative offset of the buffer to point at
    where the length is stored on the stack, then when these odd bytes are
    copied, you can modify the length. What they do is modify an initial
    length of 0xffffxxxx to 0x0000xxxx - note that the length is also the
    offset, so there is also a certain amount of luck involved, but all that
    is needed is for the offset to be small enough that the length remains
    big enough to zap enough stack (since the offset is a few hundred, that
    leaves the length at near to 64k, which is plenty to zap a few return
    addresses). Then, when the length is reloaded to do the second copy, it
    is miraculously smaller (I boggled first time I saw this in the
    debugger), and doesn't cause the expected SEGV, just nice corruption of
    the stack, as required![1]

    So, to illustrate with source:

    0x400f9d6c <memcpy>: push %esi
    0x400f9d6d <memcpy+1>: push %edi
    0x400f9d6e <memcpy+2>: mov 0xc(%esp,1),%edi
    0x400f9d72 <memcpy+6>: mov 0x10(%esp,1),%esi
    0x400f9d76 <memcpy+10>: mov 0x14(%esp,1),%ecx
    0x400f9d7a <memcpy+14>: cmp %esi,%edi
    0x400f9d7c <memcpy+16>: jae 0x400f9d94 <memcpy+40>
    ...

    at this point, we've decided to go backwards, edi is dest, esi is source
    and ecx is count (aka -146 aka ffffff6e)

    0x400f9d94 <memcpy+40>: add %ecx,%edi
    0x400f9d96 <memcpy+42>: add %ecx,%esi

    Now we are pointing at the "end" of the buffers (i.e. somewhere down the
    stack from them, and, lo and behold, edi now points at the two MS bytes
    of the count)

    0x400f9d98 <memcpy+44>: std
    0x400f9d99 <memcpy+45>: and $0x3,%ecx

    calculate spare bytes (2 in this case)

    0x400f9d9c <memcpy+48>: dec %edi
    0x400f9d9d <memcpy+49>: dec %esi
    0x400f9d9e <memcpy+50>: repz movsb %ds:(%esi),%es:(%edi)

    and copy them - in fact two zeroes are copied, so the length is now
    0000ff6e.

    0x400f9da0 <memcpy+52>: mov 0x14(%esp,1),%ecx

    load the length again (now ff6e)

    0x400f9da4 <memcpy+56>: shr $0x2,%ecx

    divide by 4

    0x400f9da7 <memcpy+59>: sub $0x3,%esi
    0x400f9daa <memcpy+62>: sub $0x3,%edi
    0x400f9dad <memcpy+65>: repz movsl %ds:(%esi),%es:(%edi)

    and copy that many longs (i.e. just shy of 64k bytes). Here is where we
    would have gone bang with a SEGV, but don't coz of the cunningness.

    0x400f9daf <memcpy+67>: mov 0xc(%esp,1),%eax
    0x400f9db3 <memcpy+71>: pop %edi
    0x400f9db4 <memcpy+72>: pop %esi
    0x400f9db5 <memcpy+73>: cld
    0x400f9db6 <memcpy+74>: ret

    return to a corrupted return address (or is it the next one up that's
    corrupted? not sure, don't care). And hey presto, remote shell.

    Note that glibc is _not_ vulnerable in this way, so I have no idea how
    the Linux attack works. I have not examined Solaris.

    Cheers,

    Ben.

    [1] For those not familiar with this class of exploit, the stack is
    corrupted such that the return address for some function call points to
    code which spawns a shell, which is then used by the attacker to have
    his or her evil way with your machine.

    -- 
    http://www.apache-ssl.org/ben.html       http://www.thebunker.net/
    

    "There is no limit to what a man can do or how far he can go if he doesn't mind who gets the credit." - Robert Woodruff