Re: Telnetd AYT overflow scanner and linux telnet 0.17

From: H D Moore (hdmat_private)
Date: Fri Aug 03 2001 - 21:15:06 PDT

  • Next message: Sam Vaughan: "Re: slackware permissions"

    I have been educated.  Comments are inline:
    
    On Fri, 3 Aug 2001 07:25:40 +1200 (NZST)
    <zen-parseat_private> wrote:
    
    > bash-2.04$ objdump -t /usr/sbin/in.telnetd|grep netobuf
    > 080585a0 g     O .bss   00002040              netobuf
    > 
    > As you can see, netobuf is in the .bss segment. (NOT THE STACK)
    
    Which explains why eip/esp was never any part of the response...
    
    > A good hint that something might be on the stack is the list of variables
    > declared in the function. Local variables are on the stack. For example.
    > len and maxsize are probably on the stack in this function...
    
    And this explains why I couldn't find any of the local variables...
    
    > (Multiples of 4 are also more likely to be the right length (More likely
    > only though.)) An int is length 4bytes. (I have no idea where you got 30
    > from.) You didn't give any addresses in the posting that I could use
    > to verify you knew what you were talking about when you said that gdb
    > might've been allocating 30 bytes per int, so I'm going to assume you
    > didn't.
    
    Looking at the memory with gdb (starting at pcc) shows this:
    
    (gdb) x 0x<address of pcc>\n
    0x<addr> <pcc>: 0x0000
    (gdb) \n
    0x<addr+2> <pcc + 2>: 0x0000
    (gdb) \n
    0x<addr+4> <pcc + 4>: 0x0000
    [ ... ]
    (gdb) \n
    0x<addr+30> <pcc + 30>: 0x0000
    
    Does that mean that 30 bytes are allocated for the integer pcc, or that gdb
    has no idea what the memory is after the variable's base address? The
    netoprintf walk went all the way up to netoprintf+8256, which happened to 
    be the correct size for it, I assumed that other variables were treated the
    same way.  If everything after pcc+4 isn't something allocated by gcc for 
    that int variable, what is in that space? Examining the memory before the
    overflow shows it all zero'd out.
    
    > (I say probably, because depending on optimizations in compiling, they may
    > be stored in registers, and not even [be able to be touched with / need
    > to be counted in calculatning the size of] a stack overflow.)
    
    Does register optimization only apply to numeric variables?  What about
    pointers and single char's?
    
    > I think you maths is slightly out. 8192 + 64 = 8256 and its unlikely that
    > any form of optimization or rearrangement so its able to be traced more
    > efficienlty would result in a buffer that is 2 bytes smaller than it has
    > been declared.
    
    That was a typo, I had 8256 in my notes. The mod 4 is a good tip though.
    
    > > A normal (4000 ayt's) only seems to get about halfway into subbuffer
    > > before the program exits.
    > 
    > Could it be you were sending them in 'packets'? If the daemon does a
    > netflush() between parts then they start going back from the beginning of
    > the buffer.
    
    Hrm.  They were sent as a single packet, I need to look at the buffer length
    passed to the read() call and see if I went over.
    
    > The 2nd thing you said initially that made me write this email.
    > >  You can't control the data.
    > 
    > You can control the data.
    > Can you show me the rule that says you are only allowed to use AYT to
    > explot this bug?
    
    No ;)
    
    > Have a look on the internet for RFCs (Request For Comments) dealing with
    > the TELNET protocol.
    > 
    > You will see there is a great deal of things you can do.
    
    I didn't get far enough into the protocol to figure out the right order. Just
    sending a few thousand can_do/will_do's didn't crash it, but I probably needed to set
    something else up first.  I spent some time with a sniffer and the telnet client's
    ^]send functions trying to determine the packet order and possible paths through
    the state engine in state.c, obivously I didn't get far enough before I sent this
    out, just reading the RFC would have been easier I guess.
    
    > Also looking at the source (did you?) will should you there are more
    > replies that get put into the netobuf (via the variable nfrontp, which
    > I'm sure you would've noticed is initialized to be equal to netobuf.)
    > You also would've seen the send_will() send_wont() send_do() and send_dont()
    > functions, and noticed that they don't do any bounds checking either,
    > trusting that if you could send it in one message, it could be stored in a
    > buffer the same size. You would also notice that you can control the last
    > byte of each 3 byte cluster? And noticed that a \0 gets added to the end
    > of the buffer under most situations, either by the vsnprintf() or by
    > another function?
    
    The last byte is the option the client requests?  I will definately take a
    closer look here, the rather crude tests I did weren't having any effect.
    
    > Read the RFCs there is even one quite funny one, if you look hard enough,
    > that should entertain you enough to continue looking through them enough
    > to work out how to do this properly.
    > 
    > > (strlen(hostname) + 12) * ayt
    > 
    > Yoy! Something that is accurate!
    
    Woohoo, I get 1 point!
    
    > Alright what do we have.  We can make a string which is
    > 
    > (strlen(hostname)+12) *N + 3 *M bytes long by sending a string that is
    > 2 * N + 3 * N bytes long. Now, bear with me for a momement.
    > 
    > In an ideal world (which this isn't, but we will pretend it is)
    > two-thirds of computer names will not be a multiple of 3 letters long.
    > 
    > Huh? you go.
    > 
    > Well, if you are slightly lucky, and have a machine that returns a name
    > that is not a multiple of 3 bytes long, you can overflow ANY distance (up
    > 2 the maximum imposed by the input length of course)  distance into the
    > heap.
    > 
    > 'Huh?' you go.
    > 
    > (.bss segment is 'low heap', followed by the area that get malloc()ed for
    > things, the heap, proper.)
    > > To exploit this, you would need to use the AYT overflow to overwrite one
    > > of the internal stack variables (and create a secondary vulnerability),
    >                   ^^^^^ <- not stack!!!!!        ^^^ YAY
    > > then exploit this newly created vulnerability to launch a shell. )
    >                                                             ^^^^^^<-no!!!!
    > 
    > In a few days, maybe a week, all will become clear.
    
    Cool, looking forward to seeing it, thanks again for the explanation. Hopefully
    I didn't cause too much damage with my ignorant overview of the problem. 
     
    > -- zen-parse
    
    -HD
    



    This archive was generated by hypermail 2b30 : Sat Aug 04 2001 - 09:55:07 PDT