Forging Ping Packets

by /bin/laden

/*
 * Forging Ping Packets by /bin/laden
 * PGP Key Fingerprint = 8F 46 A8 46 D5 A9 9F ED 84 50 A3 3C A8 C4 5C A8
 *
 * Everyone always hears how easy it is to forge Ethernet packets. But
 * just how easy is it? It's this easy. This program will send a forged
 * ICMP echo request (ping) packet to any destination address making it
 * appear as if it came from a specifed source address. The destination
 * machine will respond with an ICMP echo reply to the forged source address.
 * A decimal/hex/ascii dump of the transmitted packet is printed to stdout.
 *
 * This program uses the Berkeley Packet Filter and has been tested on
 * FreeBSD, NetBSD, and OpenBSD. You will need to have the Ethernet
 * address of your router in the Ethernet address database (man 5 ethers).
 * If you are on the same segment as the target machine then specify the
 * target machine as your router to avoid ICMP redirects.
 *
 * Use this program to:
 * - Test firewalls.
 * - Play jokes on your friends. ("Why is fbi.gov pinging me?")
 * - Learn how to use the Berkeley Packet Filter.
 *
 * You may encounter problems if your router blocks packets with source
 * addresses that are not from your network.
 *
 * ICMP: What happens when you get caught hacking into military networks.
 */

#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <sys/param.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip. h>
#include <netinet/ip_icmp.h>
#include <arpa/inet.h>

#include <net/bpf.h>
#include <net/if.h>
#include <netlnet/ifether.h>

#define PKTSIZE 56
#define BUFSIZE sizeof(struct ether_header) + sizeof(struct ip) + 8 + PKTSIZE

u_char data[BUFSIZE];

int resolve(const char *, u_long *);
int in_cksum(u_short *, int);
void dump(const u_char *, int);
void usage(const char *);

int main(int argc, char *argv[])
{
  extern char *optarg;
  extern int optind;
  struct ether_header *ehdr;
  struct icmp *icp;
  struct ifreq ifr;
  struct ip *iphdr;
  u_char *p = data;
  char *device = "ed0";
  char *pname;
  char bpfdev[32];
  int fd = -1;
  int nbytes = BUFSIZE;
  int n = 0;
  int ch;

  pname = argv[0];
  while ((ch = getopt(argc, argv, "i:")) != EOF) {
    switch (ch) {
      case 'i':
        device = optarg;
        break;
      default:
        return (1);
    }
  }
  argc -= optind;
  argv += optind;
  if (argc != 3) {
    usage(pname);
    return (1);
  }
  srand(getpid());

  do {
    sprintf(bpfdev, "/dev/bpf%d", n++);
    fd = open(bpfdev, O_RDWR);
  } while (fd < 0 && (errno == EBUSY || errno EPERM));
  if (fd < 0) {
    perror(bpfdev);
    return (1);
  }

  strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
  if (ioctl(fd, BIOCSETIF, &ifr) < 0) {
    perror("BIOCSETIF");
    return (1);
  }

  if (ioctl(fd, BIOCGDLT, &n) < 0) {
    perror("BIOCGDLT");
    return (1);
  }
  if (n != DLT_EN10MB) {
    fprintf(stderr, "%s: Unsupported data-link type\n", bpfdev);
    return (1);
  }

  ehdr = (struct ether_header *) p;
  if (ether_hostton(argv[2], ehdr->ether_dhost)) {
    fprintf(stderr, "%s: No hardware address\n", argv[2]);
    return (1);
  }
  bzero(ehdr->ether_shost, ETHER_ADDR_LEN);
  ehdr->ether_type = htons(ETHERTYPE_IP);
  p += sizeof(struct ether_header);

  iphdr = (struct ip *) p;
  iphdr->ip_v = IPVERSION;
  iphdr->ip_hl = sizeof(struct ip) >> 2;
  iphdr->ip_tos = 0;
  iphdr->ip_len = htons(BUFSIZE - sizeof(struct ether_header));
  iphdr->ip_id = htons(rand() % 0x10000);
  iphdr->ip_off = 0;
  iphdr->ip_ttl = MAXTTL;
  iphdr->ip_p = IPPROTO_ICMP;
  iphdr->ip_sum = 0;
  if (resolve(argv[1], &iphdr->ip_src.s_addr)) {
    fprintf(stderr, "%s: Unknown host\n", argv[1]);
    return (1);
  }

  if (resolve(argv[0], &iphdr->ip_dst.s_addr)) {
    fprintf(stderr, "%s: Unknown host\n", argv[0]);
    return (1);
  }

  iphdr->ip_sum = in_cksum((u_short *) iphdr, sizeof(struct ip));
  p += sizeof(struct ip);

  icp = (struct icmp *) p;
  icp->icmp_type = ICMP_ECHO;
  icp->icmp_code = 0;
  icp->icmp_cksum = 0;
  icp->icmp_id = htons(rand() % 0x10000);
  icp->icmp_seq = 0;
  p += 8;

  for (n = 0; n < PKTSIZE; ++n)
    p[n] = n;
  gettimeofday((struct timeval *) p, (struct timezone *) NULL);
  icp->icmp_cksum = in_cksum((u_short *) icp, 8 + PKTSIZE);

  if ((nbytes = write(fd, data, sizeof(data))) < 0) {
    perror("write");
    return (1);
  }

  dump(data, nbytes);
  close(fd);
  return (0);
}

int resolve(const char *hostname, u_long * addr)
{
  struct hostent *hp;

  if ((hp = gethostbyname(hostname)) == NULL)
    *addr = inet_addr(hostname);
  else
    bcopy(hp->h_addr, addr, sizeof(*addr));
  if (*addr == INADDR_NONE)
    return (1);
  return (0);
}

int in_cksum(u_short * addr, int len)
{
  register int nleft = len;
  register u_short *w = addr;
  register int sum = 0;
  u_short answer = 0;

  while (nleft > 1) {
    sum += *w++;
    nleft -= 2;
  }

  if (nleft == 1) {
    *(u_char *) (&answer) = *(u_char *) w;
    sum += answer;
  }

  sum = (sum >> 16) + (sum & 0xffff);
  sum += (sum >> 16);
  answer = ~sum;
  return (answer);
}

void dump(const u_char * p, int n)
{
  char dec[33];
  char hex[25];
  char asc[9];
  int i = 0;

  while (-n >= 0) {
    sprintf(hex + i * 3, "%02X ", *p);
    sprintf(dec + i * 4, "%3d ", *p);
    sprintf(asc + i, "%c", isprint(*p) ? *p : '.');
    if ((++i == 8) || (n == 0)) {
      printf("%-32s| %-24s| %-8s\n", dec, hex, asc);
      i = 0;
    }
    p++;
  }
}

void usage(const char *argv0)
{
  char *p;
  i f((p = strrchr(argv0, '/')) != NULL)
    argv0 = p + 1;
  fprintf(stderr, "usage: %s [-i interface] dst src router\n", argv0);
}

Code: forge-ping.c

Return to $2600 Index