/* EXCLUDED-TEAM    [www.excluded.org]
   --------------------------------------------
   gull.c   [~] 1. Trottel m, Toelpel m; 2. uebertoelpeln, verleiten
   --------------------------------------------

   written by l0om

   yet another tcp/udp port scanner. 
   you can add or remove ports from the globals tcpstd odr udpstd. 
 
                             
                          LET's GULL THEM!

V 1.2  added:
-port describtion for every open port

-connect scanning with "-Con"
 useful to scan urself for open tcp ports

-subnet pinging with tcp +ack packets "-Subs"
 to scan a subnet try the following
 gull -f 192.168.1.100 -d 192.168.1.63 -Subs
 the host id (63 here) doesnt matter. 
 gull will ping 1 - 254 with tcp packets.
*/

#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <sys/types.h>
 #define __FAVOR_BSD
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <netinet/ip_icmp.h>

#define   SYNSCAN          10   /* tcp stealth (syn) scanning */
#define   FINSCAN          20   /* tcp fin scanning */
#define   NULSCAN          30   /* tcp null scanning */
#define   XMASSCAN         40   /* tcp xmas scanning */
#define   SUBSCAN          50   /* tcp subscanning */
#define   CONSCAN          60   /* connect scan - vanilla scan or whatever */
#define   WAIT_SEC          2   /* seconds to wait for an answer */
#define   WAIT_USEC         0   /* useconds nto wait for an answer */
#define   OPEN              2   /* returnvalue for a open port */
#define   CLOSE             3   /* returnvalue for a closed one */

struct pseudohdr {              /* for creating the checksums */ 
  unsigned long saddr;
  unsigned long daddr;
  char useless;
  unsigned char protocol;
  unsigned short length;
};

struct iptcphdr {               /* read the answers header */
  struct iphdr ip;
  struct tcphdr tcp;            
};

struct ipicmphdr {               /* same here */
  struct iphdr ip;
  struct icmphdr icmp;
};

ssize_t tcpsend(u_int saddr, u_int daddr, unsigned short sport, unsigned short dport, unsigned char flags, char *data, unsigned short datalen);
ssize_t udpsend(u_int saddr, u_int daddr, unsigned short sport, unsigned short dport, char *data, unsigned short datalen);
int readtcp(int sock, u_int dest, int scanmode);
int readudp(int sock, u_int dest);
unsigned short in_cksum(unsigned short *ptr, int nbytes);
void scantcp(u_int saddr, u_int daddr, unsigned short source,
	     int scanmode);
void scanudp(u_int saddr, u_int daddr, unsigned short source);
static void sig_int(int sig);
void conscan(u_int dest);
void quickread(int sock);
void help(void);
void head(void);
void subscanscan(char *destnet, u_int saddr, unsigned short source);

unsigned char flags = 0x00;
int verbose = -1, found = 0, hostup = 0;

/******************* TCP PORTS TO SCAN ***********************/

int tcpstd[] = { 21,   /* ftp */
                 23,   /* smtp */
                 25,   /* telnet */
                 43,   /* whois */
                 53,   /* domain name server */
                 70,   /* gopher */
                 79,   /* finger */
                 80,   /* http */
		 110,  /* pop3 */
		 111,   /* rpc */ 
		 113,   /* ident */
		 115,   /* sftp */
		 119,   /* nntp */
		 135,   /* ep resolution */
		 139,   /* NETBIOS session service */
		 389,   /* ldap */
		 443,   /* http -> ssl */
		 445,   /* m$ ds */
		 1080,   /* socks */
		 6667,   /* sub7 */
		 1433};  /* my sql */

/******************* UDP PORTS TO SCAN ***********************/

int udpstd[] = { 49,    /* login host protocol */ 
                 53,    /* dns */
                 69,    /* tftp */
		 135,    /* ep resulution */
		 137,    /* NETBIOS name service */
		 138,    /* NETBIOS datagram service */
		 161,    /* snmp */
		 162,    /* snmp trap */
		 513,    /* who */
		 514,    /* syslog */
		 515,     /* printer */
		 5000,     /* GPnP (win xp)*/
		 31337,    /* DDoS */
		 32780};  
 

int main(int argc, char **argv)
{
  int tcpscan = 0, udpscan = 0;
  double value;
  int scanmode = SYNSCAN, i;
  time_t start, end;
  unsigned short tcpsport = 80;   /* often gets trough */
  unsigned short udpsport = 54;   /* same here */
  u_int saddr = -1, daddr = -1;

  head();

  if(argc == 1) {
    help();
    exit(0);
  }

  if(getuid()|getgid() != 0) {
    fprintf(stderr, "you must be root\n");
    return(-1);
  }

  for(i = 1; i < argc; i++) {
    if(strncmp(argv[i], "-d", 2) == 0) daddr = inet_addr(argv[++i]);
    if(strncmp(argv[i], "-f", 2) == 0) saddr = inet_addr(argv[++i]);
    if(strncmp(argv[i], "-v", 2) == 0) verbose = 0;
    if(strncmp(argv[i], "--T", 3) == 0) tcpscan = -1;
    if(strncmp(argv[i], "--U", 3) == 0) udpscan = -1;
    if(strncmp(argv[i], "-Usp", 3) == 0) udpsport = atoi(argv[++i]);
    if(strncmp(argv[i], "-Tsp", 3) == 0) tcpsport = atoi(argv[++i]);
    if(strncmp(argv[i], "-h", 2) == 0) {
      help();
      exit(0);
    }
    if(strncmp(argv[i], "-Syn", 5) == 0) {
      flags = TH_SYN;
      scanmode = SYNSCAN;
    }
    if(strncmp(argv[i], "-Xmas", 5) == 0) {
      flags = TH_URG|TH_PUSH|TH_FIN;
      scanmode = XMASSCAN;
    }
    if(strncmp(argv[i], "-Con", 4) == 0) 
      scanmode = CONSCAN;
    if(strncmp(argv[i], "-Null", 5) == 0) 
      scanmode = NULSCAN;
    if(strncmp(argv[i], "-Fin", 4) == 0) {
      flags = TH_FIN;
      scanmode = FINSCAN;
    }
    if(strncmp(argv[i], "-Subs", 5) == 0) {
      flags = TH_ACK;
      subscanscan((char *)inet_ntoa(daddr), saddr, tcpsport);
      exit(0);
    }
  }

  if(scanmode == SYNSCAN && flags == 0x00) flags = TH_SYN;

    if(daddr == -1 || saddr == -1) {
      fprintf(stderr, "you must choose a dest or source address\n");
      return(-1);
    }

    signal(SIGINT, sig_int);  /* if it fails- who cares? */

    if(verbose == 0) {
      puts("\treport:");
      puts("\t******");
    printf("\tsource address:%s, dest address:%s
        used tcp source port:%d, used udp source port:%d
        %s %s\n",
	   inet_ntoa(saddr), inet_ntoa(daddr), tcpsport, udpsport, 
	   (tcpscan == 0) ? "[+] scanning tcp " : "[-] no tcp scanning",
	   (udpscan == 0) ? "[+] scanning udp " : "[-] no udp scanning");
    printf("\t--------------------------------------------------\n");
    }

    start = time(NULL);
    if(tcpscan == 0) scantcp(saddr, daddr, tcpsport, scanmode); /*scan tcp*/
    if(udpscan == 0) scanudp(saddr, daddr, udpsport);    /* scan udp ports */
    end = time(NULL);
    value = difftime(start, end);
    value *= -1;
    printf("\t-------------------------------------------------------\n");
    printf("found ports: %d  needed time: %.2lfsec  now is: %s\n",
	   found, value, ctime(&end));
  return(0);
}

void scantcp(u_int saddr, u_int daddr, unsigned short source, int scanmode)
{
  int sockfd, i, reval;
  ssize_t arrysize;
  struct servent *port;

  arrysize = ((sizeof(tcpstd))/(sizeof(int)));

  sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
  if(sockfd < 0) {
    fprintf(stderr, "cannot creat socket\n");
    exit(-1);
  }

  if(verbose == 0) {
  printf("starting tcp scan\n");
  printf("-----------------\n");
  if(scanmode == SYNSCAN) {
    printf("for every open port we ll receive an tcp +ack +syn.\n");
    printf("for every closed one we ll receve an tcp +rst +ack.\n\n");
  } else if( scanmode != CONSCAN){
    printf("for every open port we ll receive nothing.\n");
    printf("for every closed port we ll receive tcp +rst\n\n");
   }
  else  
    printf("we will connect to every port to see it is open or closed\n\n");
    
  }

  if(scanmode == CONSCAN) { 
    conscan(daddr);
    return;
  }

  for(i = 0; i < arrysize; tcpstd[i++]) {
    if( (reval = tcpsend(saddr, daddr, source, tcpstd[i], flags, "here comes a gull...", 19)) == 0) { 
      fprintf(stderr, "cannot send\n");
      return;
    } else if(verbose == 0 && scanmode != CONSCAN) printf("trying port nr. %d...\n",tcpstd[i]);
    if(readtcp(sockfd, daddr, scanmode) == OPEN) {
      port = getservbyport(htons(tcpstd[i]), "tcp");
      printf("tcp port nr. %d  (%s)  is open \n",tcpstd[i],
((port == NULL) ? "unknown" : port->s_name));;
      found++;
    }
  }
}

void conscan(u_int daddr) 
{
  struct sockaddr_in servaddr;
  int sockfd, i;
  ssize_t arrysize;

  sockfd = socket(AF_INET, SOCK_STREAM, 0);
  if(sockfd == -1) {
    fprintf(stderr, "cannot creat socket\n");
    exit(-1);
  }

  arrysize = ((sizeof(tcpstd)/sizeof(int)));

  for(i = 0; i < arrysize; i++) {
  servaddr.sin_addr.s_addr = daddr;
  servaddr.sin_port = htons(tcpstd[i]);
  servaddr.sin_family = AF_INET;

  if(connect(sockfd, (struct sockaddr *)&servaddr, sizeof(struct sockaddr_in)) == 0) {
    printf("tcp port nr. %d is open \n",tcpstd[i]);
    found++;
  } 
  }
}

void subscanscan(char *destnet, u_int saddr, unsigned short source)
{
  int range = 1, dot = 0, check = 0, sockfd;
  char *ptr, ip[16];

  sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
  if(sockfd == -1) {
    fprintf(stderr, "cannot creat socket\n");
    exit(-1);
  }

  ptr = destnet;
  while(dot != 3) {
    check++;
    if(*ptr++ == '.') dot++;
  } 

  strncpy(ip, destnet, check);
  for( ; range < 255; range++) {  
    sprintf(&ip[check],"%d\n",range);
   if(tcpsend(saddr, inet_addr(ip), source, 80, TH_ACK, "excluded", 8) == 0){
      fprintf(stderr, "cannot send\n"); 
      exit(-1);
    }
   quickread(sockfd);
  }
}

int readtcp(int sock, u_int dest, int scanmode)
{
  int i, nbytes;
  fd_set rset;
  struct iptcphdr hdr;
  struct timeval tv;
 
  tv.tv_sec = WAIT_SEC;          
  tv.tv_usec = WAIT_USEC;

  FD_ZERO(&rset);
  FD_SET(sock, &rset);

  if(select(255, &rset, NULL, NULL, &tv) > 0) {
    if(FD_ISSET(sock, &rset)) {
      nbytes = read(sock, (struct iptcphdr *)&hdr, sizeof(hdr));
      if(nbytes <= 0) {
	fprintf(stderr, "read error\n");
	return(0);
      }
      if(hdr.ip.saddr != dest) return(0);  /* pkt not from victim */

      if(hostup == 0) hostup = 1;
      
      if(hdr.tcp.th_flags & TH_RST)
	return(CLOSE);
      else if((hdr.tcp.th_flags & TH_SYN) && scanmode == SYNSCAN)
	return(OPEN);
    }
  } else if(scanmode != SYNSCAN) return(OPEN);
  else if(hostup == 0) printf("no answer-> host up?\n");
  else printf("filterd\n");
  return(0);
}

void scanudp(u_int saddr, u_int daddr, unsigned short source)
{
  int sockfd, i, retval;
  ssize_t arrysize;
  struct servent *port;

  arrysize = ((sizeof(udpstd))/(sizeof(int)));

  sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
  if(sockfd < 0) {
    fprintf(stderr, "cannot creat socket!\n");
    exit(-1);
  }

  if(verbose == 0) {
    printf("starting udp scan\n");
    printf("-----------------\n");
    printf("we ll sending a udp to the dests port. if we receive\n");
    printf("no icmp dest unreachable the port is up for us.\n\n");
  }
  for(i = 0; i < arrysize; udpstd[i++]) {
    if( (retval = udpsend(saddr, daddr, source, udpstd[i], "...", 3)) == 0) {
      fprintf(stderr, "cannot send\n");
      return;
    }
    if(verbose == 0) printf("trying port nr. %d...\n",udpstd[i]);
    if(readudp(sockfd, daddr) == OPEN) {
      port = getservbyport(htons(udpstd[i]), "udp");
      printf("udp port nr. %d  (%s)  is open\n",udpstd[i],
((port == NULL) ? "unknown" : port->s_name));;
      found++;
    }
  }
}

void quickread(int sock)
{
  char buf[100];
  struct iptcphdr *thehead;
  fd_set rset;
  struct timeval tv;

  tv.tv_sec = 0;
  tv.tv_usec = 8000;

  FD_ZERO(&rset);
  FD_SET(sock, &rset);

  thehead = (struct iptcphdr *)buf;

  switch(select(sock+1, &rset, NULL, NULL, &tv)) {
  case -1: 
    fprintf(stderr,"fatal error- select\n");
    exit(-1);
  case 0: 
    return;
  default: 
    read(sock, buf, sizeof(buf));
    printf("%s is up\n",inet_ntoa(thehead->ip.saddr));
    break;
  }
}


static void sig_int(int sig)
{
  fflush(stdin); fflush(stdout); fflush(stderr);
  printf("\t received interrupt- exiting...\n");
  sleep(1);
  exit(0);
}

int readudp(int sock, u_int dest) 
{
  int nbytes;
  fd_set rset;
  struct timeval tv;
  struct ipicmphdr hdr;

  tv.tv_sec = WAIT_SEC;
  tv.tv_usec = WAIT_USEC;
  
  FD_ZERO(&rset);
  FD_SET(sock, &rset);

  if(select(sock+1, &rset, NULL, NULL, &tv) > 0) {
    if(FD_ISSET(sock, &rset)) {
      nbytes = read(sock, (struct ipicmphdr *)&hdr, sizeof(hdr));
      if(nbytes <= 0) {
	fprintf(stderr, "cannot read\n");
	return(0);
      }
      if(hdr.ip.saddr != dest) return(0); /* pkt not from victim */
      
      if(hdr.icmp.code == 3 && hdr.icmp.type == 3) return(CLOSE);
    }
  } return(OPEN);
}

ssize_t udpsend(u_int saddr, u_int daddr, unsigned short sport, unsigned short dport, char *data, unsigned short datalen) 
{
        struct	sockaddr_in servaddr;
	struct	iphdr *ip;
	struct	udphdr *udp;
	struct pseudohdr *pseudo;
        char packet[sizeof(struct iphdr)+sizeof(struct udphdr)+datalen];
	int nbytes, sockfd, on = 1;
		
	sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
	if(sockfd < 0) {
	  fprintf(stderr,"cannt creat socket\n");
	  return(0);
	}
	if(setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) == -1) {
	  fprintf(stderr, "cannot setsockopt\n");
	  return(0);
	}

        memset(packet, 0x00, sizeof(packet));
	memcpy(packet+sizeof(struct iphdr)+sizeof(struct udphdr), data, datalen);

	servaddr.sin_addr.s_addr = daddr;
	servaddr.sin_port = htons(dport);
	servaddr.sin_family = AF_INET;

	ip     = (struct iphdr *)packet;
	udp    = (struct udphdr *)(packet + sizeof(struct iphdr));
        pseudo = (struct pseudohdr *)(packet + sizeof(struct iphdr) 
					 - sizeof(struct pseudohdr));

        udp->uh_sport = htons(sport);
	udp->uh_dport = htons(dport);
	udp->uh_sum = 0;
	udp->uh_ulen = htons(sizeof(struct udphdr)+datalen);
	
        pseudo->saddr    = saddr;
	pseudo->daddr    = daddr;
	pseudo->useless     = 0;
	pseudo->protocol = IPPROTO_UDP;
	pseudo->length   = udp->uh_ulen;

	udp->uh_sum = in_cksum((u_short *)pseudo,sizeof(struct udphdr)+sizeof(struct 
pseudohdr)+datalen);

	ip->ihl      = 5;
	ip->version  = 4;
	ip->tos      = 0x10;
	ip->tot_len  = sizeof(packet);
	ip->frag_off = 0;
	ip->ttl      = 69;
	ip->protocol = IPPROTO_UDP;
	ip->check    = 0;
	ip->saddr    = saddr;
	ip->daddr    = daddr;

	nbytes = sendto(sockfd, packet, ip->tot_len, 0, (struct sockaddr *)&servaddr, 
sizeof(servaddr));
	close(sockfd);
	return(nbytes);
}

ssize_t tcpsend(unsigned int saddr, unsigned int daddr, unsigned short sport,
		unsigned short dport, unsigned char flags, char *data,
		unsigned short datalen)
{
  char *packet;
  struct iphdr *ip;
  struct tcphdr *tcp;
  struct pseudohdr *pseudo; 
  struct sockaddr_in servaddr;
  int retval, sockfd, on = 1;

  packet = (char *)malloc((sizeof(struct iphdr)+
			   sizeof(struct tcphdr)+datalen)*sizeof(char));

  servaddr.sin_family = AF_INET;
  servaddr.sin_port = htons(dport);
  servaddr.sin_addr.s_addr = daddr;

  sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
  if(sockfd < 0) {
   fprintf(stderr,"cannot creat socket\n");
   return(0);
 }
 if(setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) == -1) {
   fprintf(stderr, "cannot setservaddr\n");
   return(0);
 }

 ip = (struct iphdr *)packet;
 tcp = (struct tcphdr *)(packet + sizeof(struct iphdr));
 pseudo = (struct pseudohdr *)(packet + sizeof(struct iphdr) - sizeof(struct 
pseudohdr));

 memset(packet, 0x00, sizeof(packet));
 memcpy(packet+sizeof(struct iphdr)+sizeof(struct tcphdr), data, datalen);

 pseudo->saddr = saddr;
 pseudo->daddr = daddr;
 pseudo->protocol = IPPROTO_TCP;
 pseudo->length = htons(sizeof(struct tcphdr) + datalen);

 tcp->th_sport = htons(sport);
 tcp->th_dport = htons(dport);
 tcp->th_seq = rand() + rand();
 tcp->th_ack = rand() + rand();
 tcp->th_off = 5;
 tcp->th_flags = flags;
 tcp->th_win = htons(2048);
 tcp->th_sum = in_cksum((unsigned short *)pseudo, sizeof(struct tcphdr) + 
		       sizeof(struct pseudohdr) + datalen);

 memset(ip, 0x00, sizeof(struct iphdr));
 ip->version = 4;
 ip->ihl = 5;
 ip->tot_len = htons(sizeof(struct iphdr) + sizeof(struct tcphdr) + datalen);
 ip->id = rand();
 ip->ttl = 255;
 ip->protocol = IPPROTO_TCP;
 ip->saddr = saddr;
 ip->daddr = daddr;
 ip->check = in_cksum((unsigned short *)ip, sizeof(struct iphdr));

 if((retval = sendto(sockfd, packet, ntohs(ip->tot_len), 0,
		     &servaddr, sizeof(servaddr))) == -1) {
   fprintf(stderr, "cannot sendto()\n");
   return(0);
 }

   close(sockfd); return(retval);
}


unsigned short in_cksum(unsigned short *ptr, int nbytes)
{
  register long	sum;
  u_short oddbyte;
  register u_short answer;

  sum = 0;
  while(nbytes > 1)
  {
    sum += *ptr++;
    nbytes -= 2;
  }

  if(nbytes == 1)
  {
    oddbyte = 0;
    *((u_char *) &oddbyte) = *(u_char *)ptr;
    sum += oddbyte;
  }

  sum  = (sum >> 16) + (sum & 0xffff);
  sum += (sum >> 16);
  answer = ~sum;

  return(answer);
}


void head(void) 
{
  puts("
       EXCLUDED [www.excluded.org]
 °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° 
                 gull              
 °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°
 by l0om                 LET'S GULL THEM!
");
}

void help(void)
{
  puts("gull V.1.2     <-->   help
\tl0om@excluded.org 

gull -f 1.1.1.1 -d 2.2.2.2 [scanmode] [options]

options:
-f: next argument must be ur ip address
-d: next argument must be ur dest ip address
--------
you must specify these two. 
if you only enter these two, gull will make a tcp and udp scan with
the defined tcpstd and udpstd ports in list. gull will use stealth as 
standard.
now the free to choise options.
--------
--T: no tcp scan
--U: no udp scan
-Syn: tcp stealth scan
-Xmas: tcp xmas scan
-Subs: scanns a subnet for hosts with tcp +acks
-Con: tcp connect port scan
-Fin: tcp fin scan
-Null: tcp null scan
-Tsp: the tcp source port for all packets  (default(80))
-Usp: the udp source port for all packets  (default(54))
-v: gives you more output and infos

example:
gull -f 1.1.1.1 -d 1.1.1.2 -Null -Tsp 20 -Usp 69 -v
");
}


