Vulnerability Development mailing list archives

[Fwd: spoofing the ethernet address]


From: fredrik.widlund () DEFCOM-SEC COM (Fredrik Widlund)
Date: Thu, 2 Mar 2000 16:34:44 +0100


Hi

Wrote a quick hack a couple of years back that changes kernel info
realtime...
for OpenBSD though. It sets a mac address on a chosen interface. There
are
actually 2 structs that you can set separately, one for sending, and
one for accepting pkts...

There is a patch from around 97 for if_ethersubr that is still in cvs
tree,
that makes the kernel keep its hands of the mac source.... OpenBSD here
too...

I haven't really tried this for OpenBSD 2.6 and later... might blow it
up...
be prepared for it...

/Fredrik Widlund - Defcom Security

"Bobby, Paul" wrote:

Been playing with hping, and I imagine other IP spoofing tools
generate the
same types of packets.

The spoofed packet contains a bogus IP address, yes. However the
ethernet
address (MAC) is the address of the sending machine.

Is it possible to spoof this address also? Would someone have to write
a
custom ethernet driver?

Paul Bobby
-----------------
<dream> Got Root? </dream>


/*
 *  sea.c : set ethernet interface addresses on openbsd
 *  Copyright (c) 1998 lone_wolf (Fredrik Widlund) <fredrik.widlund () defcom-sec com>
 *
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. The name of the author(s) may not be used to endorse or promote
 *    products derived from this software without specific prior written
 *    permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 *  sea.c : set ethernet interface addresses on openbsd
 *
 *  Changes the hardware address for ethernet interface(s) on OpenBSD.
 *  Requires securelevel 0 to write to kernel memory.
 *
 *  Don't know which ethernet chips it will work on.
 *
 *  Takes affect instantly, which might confuse other hosts arp databases.
 *  Clearing the arp table will make us promote it in arp requests. Guess
 *  we should broadcast-publish ourself...
 *
 *  If you want to run it interactively (ie. not script it in /etc/rc) you
 *  must recompile a kernel with 'option insecure' in it, to allow the
 *  securelevel to remain at zero altitude.
 *
 *  Oh btw, this is not standard procedure. Dont blame me if it takes down
 *  your system. It is for OpenBSD *exclusively*. Try it on other platforms
 *  and they will most certainly crash.
 *
 *  Hacked if_ethersubr to keep mr. bsd off the eh for af_unspec, then
 *  noticed that the exact (letter for letter) patch had been used a year
 *  ago, for a couple of months, until deraadt ruled it out... I'll keep it
 *  though. It's still in the cvs tree, of course. Try it out.
 *
 *  v1.0a2 is hackerished and actually quite improved...
 *
 *  This is still fresh code, and probably filled with annoying creatures...
 *
 *
 *  usage: sea [-vd] interface address [interface address ...]
 *
 *  example: sea -vd fxp0 00:00:6C:6F:6E:65 fxp1 00:00:77:6F:6C:66
 *
 *  options: -v verbose
 *           -d debug (wont write changes into the kernel vm)
 *           -h help
 *
 *  compile: gcc -Wall -O2 -o sea sea.c -lkvm
 */

/************/
/* Includes */
/************/

#include <sys/param.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_types.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <err.h>
#include <fcntl.h>
#include <kvm.h>
#include <limits.h>
#include <nlist.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

/**********/
/* Macros */
/**********/

#define KREAD(kd, addr, buf)                                                 \
if (kvm_read((kd), (addr), (char *) (buf), sizeof (*buf)) != sizeof (*buf))  \
  errx(EXIT_FAILURE, "%s", kvm_geterr(kd));

#define KWRITE(kd, addr, buf)                                                \
if (kvm_write((kd), (addr), (char *) (buf), sizeof (*buf)) != sizeof (*buf)) \
  errx(EXIT_FAILURE, "%s", kvm_geterr(kd));

/***********/
/* Globals */
/***********/

extern char *__progname;
extern char *optarg;
extern int optind;

/**************/
/* Prototypes */
/**************/

int if_sethwaddrs(char **if_data, int nif, int verbose, int debug);
void usage();

/***********/
/* Program */
/***********/

void usage()
{
  fprintf(stdout,
          "usage: %s [-vdh] interface address [interface address ...]\n",
          __progname);
  exit(EXIT_FAILURE);
}

int main(int argc, char **argv)
{
  int ch, verbose, debug, found, i, nif;
  struct ether_addr *addr;

  verbose = debug = 0;
  while ((ch = getopt(argc, argv, "dvh")) != -1)
    switch(ch)
      {
      case 'v': verbose = 1; break;
      case 'd': debug = 1  ; break;
      case 'h':
      default : usage();
      }
  argc -= optind;
  argv += optind;

  if (argc % 2 != 0)
    usage();

  nif = argc/2;
  for (i=0; i < nif; i++)
    if (strlen(argv[2*i]) >= IFNAMSIZ)
      errx(EXIT_FAILURE, "invalid interface name: %s", argv[2*i]);
    else if ((addr = ether_aton(argv[2*i+1])) == NULL)
      errx(EXIT_FAILURE, "invalid interface address for %s", argv[2*i]);

  found = if_sethwaddrs(argv, nif, verbose, debug);

  if (nif && found == 0)
    errx(EXIT_FAILURE, "unable to find any of the interfaces");
  else if (found != nif)
    for (i = 0; i < nif; i++)
      if (argv[2*i][0])
        fprintf(stderr, "%-8s not found\n", argv[2*i]);

  exit(EXIT_SUCCESS);
}

int if_sethwaddrs(char **if_data, int nif, int verbose, int debug)
{
  char buf[_POSIX2_LINE_MAX];
  kvm_t *kd;
  struct ether_addr *addr;
  struct nlist nl[] = {{ "_ifnet" } , {}};
  struct ifnet_head ifnet_head;
  struct arpcom arpcom;
  struct ifnet *ifnet_p;
  struct ifaddr ifaddr;
  struct sockaddr_dl sdl;
  u_long ifnet_addr;
  u_long ifaddr_addr;
  u_long ifa_addr_addr;
  int n, found = 0;

  if ((kd = kvm_openfiles(NULL, NULL, NULL, O_RDWR, buf)) == NULL)
    errx(EXIT_FAILURE, "kvm_open: %s", buf);

  if (kvm_nlist(kd, nl) < 0 || nl[0].n_type == 0)
    errx(EXIT_FAILURE, "no namelist");

  KREAD(kd, nl[0].n_value, &ifnet_head);
  for(ifnet_addr = (u_long) ifnet_head.tqh_first;
      ifnet_addr;
      ifnet_addr = (u_long) ifnet_p->if_list.tqe_next)
    {
      KREAD(kd, ifnet_addr, &arpcom);
      ifnet_p = (struct ifnet *) &arpcom;
      ifaddr_addr = (u_long) ifnet_p->if_addrlist.tqh_first;
      if(ifaddr_addr == NULL)
        continue;

      KREAD(kd, ifaddr_addr, &ifaddr);
      ifa_addr_addr = (u_long) ifaddr.ifa_addr;
      KREAD(kd, ifa_addr_addr, &sdl);
      if (sdl.sdl_family != AF_LINK || sdl.sdl_type != IFT_ETHER)
        continue;

      if (!nif)
        {
          fprintf(stdout, "%-8s %s\n", ifnet_p->if_xname,
                  ether_ntoa((struct ether_addr *) LLADDR(&sdl)));
          continue;
        }

      for (n = 0; n < nif && strcmp(ifnet_p->if_xname, if_data[2*n]); n++)
        {}
      if (n >= nif)
        continue;
      if_data[2*n][0] = '\0';
      found++;

      addr = ether_aton(if_data[2*n+1]);
      if (!debug)
        {
          KWRITE(kd, ifnet_addr + ((char *)&arpcom.ac_enaddr -
                                   (char *)&arpcom), addr);
          KWRITE(kd, ifa_addr_addr + ((char *)&sdl.sdl_data + sdl.sdl_nlen -
                                      (char *)&sdl), addr);
        }
      if (verbose)
        {
          fprintf(stdout, "%-8s %s", ifnet_p->if_xname,
                  ether_ntoa((struct ether_addr *) LLADDR(&sdl)));
          fprintf(stdout, " -> %s\n", ether_ntoa(addr));
        }
    }
  if (kvm_close(kd) != 0)
    errx(EXIT_FAILURE, "%s", kvm_geterr(kd));

  return found;
}


Current thread: