Skip to content
Browse files

arpspoof: completely rewrite command line handling

This commit changes command line handling of arpspoof completely.
Sending arp packets to the broadcast address has been removed, instead
target addresses are specified as command line arguments in CIDR
notation.

The hosts to be imitated are specified by the new option "-m" (as in
role model), specifying a complete network range is possible as well.
The previous switch "-m" has been renamed to "-x", now called "cross
poisoning": it will try to intercept every connection between specified
hosts, rendering the distinction between targets and models
non-existant.
  • Loading branch information...
1 parent 95250d0 commit 09d81d61df647e6b359dcf82933369093f4d7503 @wertarbyte committed Dec 7, 2011
Showing with 74 additions and 71 deletions.
  1. +11 −16 arpspoof.8
  2. +63 −55 arpspoof.c
View
27 arpspoof.8
@@ -9,7 +9,7 @@ intercept packets on a switched LAN
.na
.nf
.fi
-\fBarpspoof\fR [-v] [\fB-i \fIinterface\fR] [\fB-c \fIown|host|both\fR] [\fB-s \fInetwork/prefixlength\fR] [\fB-t \fItarget\fR] [\fB-m\fR] [\fB-r\fR] [\fIhosts...\fR]
+\fBarpspoof\fR [-v] [\fB-i \fIinterface\fR] [\fB-c \fIown|host|both\fR] [\fB-m \fImodel[/prefixlength]\fR] [\fB-x\fR] [\fB-r\fR] [\fItarget[/prefixlength]\fR]
.SH DESCRIPTION
.ad
.fi
@@ -26,27 +26,22 @@ Make arpspoof verbose about what it is doing.
.IP "\fB-i \fIinterface\fR"
Specify the interface to use.
.IP "\fB-c \fIown|host|both\fR"
-Specify which hardware address t use when restoring the arp configuration;
+Specify which hardware address to use when restoring the arp configuration;
while cleaning up, packets can be send with the own address as well as with
the address of the host. Sending packets with a fake hw address can disrupt
connectivity with certain switch/ap/bridge configurations, however it works
more reliably than using the own address, which is the default way arpspoof
cleans up afterwards.
-.IP "\fB-t \fItarget\fR"
-Specify a particular host to ARP poison (if not specified, all hosts
-on the LAN). Repeat to specify multiple hosts.
-.IP "\fB-s \fInetwork/prefixlength\fR"
-Specify a network in CIDR notation to poison. An arpscan is performed to
-locate active hosts in the network.
+.IP "\fB-m \fImodel[/prefixlength]\fR"
+Specify which host(s) to imitate.
.IP "\fB-r\fR"
-Poison both hosts (host and target) to capture traffic in both directions.
-(only valid in conjuntion with -t)
-.IP "\fB-m\fR"
-Consider each host a potential target as well as a model to imitate; Poison the entire
-mesh, i.e. every possible connection between all hosts.
-.IP \fIhost\fR
-Specify the host(s) you wish to intercept packets for (usually the local
-gateway).
+Poison both hosts (model and target) in classic mitm style to capture traffic in both directions.
+.IP "\fB-x\fR"
+Enable cross-poisoning: consider each host a potential target for receiving fake arp packets as
+well as a model to imitate; this way, it is possible to intercept all communication between hosts.
+.IP \fItarget[/prefixlength]\fR
+Any additional arguments will be considered targets which will receive spoofed arp packets, poisoning
+their arp caches. Traffic from these hosts to the ones specified as models will be intercepted.
.SH "SEE ALSO"
dsniff(8), fragrouter(8)
.SH AUTHOR
View
118 arpspoof.c
@@ -39,18 +39,18 @@ struct host {
};
/* host flags */
-#define HOST_ACTIVE (1<<0)
-#define HOST_SUBNET (1<<1)
-#define HOST_TARGET (1<<2)
-#define HOST_MODEL (1<<3)
+#define HOST_ACTIVE (1<<0) /* host is enabled */
+#define HOST_SUBNET (1<<1) /* host originates from a subnet scan */
+#define HOST_TARGET (1<<2) /* we try to poison the arp cache of this host */
+#define HOST_MODEL (1<<3) /* we are trying to imitate this host and intercept traffic towards it*/
static int verbose = 0;
static libnet_t *l;
static int n_hosts = 0;
static struct host *hosts;
static char *intf;
static int poison_reverse;
-static int poison_mesh;
+static int poison_cross;
static uint8_t *my_ha = NULL;
static uint8_t *brd_ha = "\xff\xff\xff\xff\xff\xff";
@@ -63,7 +63,7 @@ static void
usage(void)
{
fprintf(stderr, "Version: " VERSION "\n"
- "Usage: arpspoof [-v] [-i interface] [-c own|host|both] [-t target] [-s network/prefixlength] [-m] [-r] [hosts...]\n");
+ "Usage: arpspoof [-v] [-i interface] [-c own|host|both] [-m model[/prefixlength]] [-x] [-r] [target[/prefixlength]]\n");
exit(1);
}
@@ -170,14 +170,28 @@ static int host_add(in_addr_t addr, uint8_t flags) {
}
static int subnet_add(in_addr_t addr, int prefix_length, uint8_t flags) {
+ int result = n_hosts;
uint32_t mask = ~((1<<(32-prefix_length))-1);
uint32_t net = (ntohl((uint32_t)addr)) & mask;
uint32_t brd = (ntohl((uint32_t)addr)) | ~mask;
uint32_t a;
+ if (prefix_length == 32) {
+ /* there is no network, only the single host! */
+ return host_add(addr, flags);
+ }
for (a = net+1; a<brd; a++) {
in_addr_t ia = (in_addr_t) htonl(a);
- host_add(ia, HOST_SUBNET|flags);
+ result = host_add(ia, HOST_SUBNET|flags);
}
+ return result;
+}
+
+static int count_hosts(uint8_t flags) {
+ int n = 0;
+ struct host *target = hosts;
+ for (; target->ip; target++)
+ if ((target->flags & flags) == flags) n++;
+ return n;
}
static int active_targets(void) {
@@ -217,17 +231,15 @@ cleanup(int sig)
if (fw) {
arp_send(l, ARPOP_REPLY,
(u_int8_t *)&model->mac, model->ip,
- (target->ip ? (u_int8_t *)&target->mac : brd_ha),
- target->ip,
+ (u_int8_t *)&target->mac, target->ip,
src_ha);
/* we have to wait a moment before sending the next packet */
usleep(ARP_PAUSE);
}
if (bw) {
arp_send(l, ARPOP_REPLY,
(u_int8_t *)&target->mac, target->ip,
- (u_int8_t *)&model->mac,
- model->ip,
+ (u_int8_t *)&model->mac, model->ip,
src_ha);
usleep(ARP_PAUSE);
}
@@ -238,6 +250,31 @@ cleanup(int sig)
exit(0);
}
+static int cmd_hosts_add(char *arg, uint8_t flags) {
+ /* number of memory slots allocated for host list */
+ int h_size = n_hosts+1;
+ int scan_prefix_length = 32;
+ in_addr_t target_addr = 0;
+ char *scan_prefix = strchr(arg, '/');
+ /* do we have to scan an entire subnet? */
+ if (scan_prefix) {
+ *scan_prefix = '\0';
+ scan_prefix_length = atoi(scan_prefix+1);
+ if (scan_prefix_length < 0 || scan_prefix_length > 32) {
+ usage();
+ }
+ }
+ h_size += (1<<(32-scan_prefix_length));
+ target_addr = libnet_name2addr4(l, arg, LIBNET_RESOLVE);
+ if (target_addr == -1) {
+ usage();
+ }
+ /* we need some more memory to store the target data */
+ int mem = (h_size) * sizeof(struct host);
+ hosts = realloc( hosts, mem );
+ return subnet_add(inet_addr(arg), scan_prefix_length, flags);
+}
+
int
main(int argc, char *argv[])
{
@@ -254,49 +291,27 @@ main(int argc, char *argv[])
intf = NULL;
poison_reverse = 0;
- poison_mesh = 0;
+ poison_cross = 0;
n_hosts = 0;
- /* allocate enough memory for target list */
- hosts = calloc( argc+1, sizeof(struct host) );
+ hosts = NULL;
- while ((c = getopt(argc, argv, "vrmi:s:t:c:h?V")) != -1) {
+ while ((c = getopt(argc, argv, "vrxm:i:c:h?V")) != -1) {
switch (c) {
case 'v':
verbose = 1;
break;
case 'i':
intf = optarg;
break;
- case 't':
- target_addr = libnet_name2addr4(l, optarg, LIBNET_RESOLVE);
- if (target_addr == -1) {
- usage();
- } else {
- host_add(target_addr, HOST_TARGET);
- }
- break;
case 'r':
poison_reverse = 1;
break;
- case 'm':
- poison_mesh = 1;
+ case 'x':
+ poison_cross = 1;
break;
- case 's':
- scan_prefix = strchr(optarg, '/');
- if (scan_prefix) {
- *scan_prefix = '\0';
- scan_prefix_length = atoi(scan_prefix+1);
- if (scan_prefix_length < 0 || scan_prefix_length > 32) {
- usage();
- }
- }
- n_scan_hosts += (1<<(32-scan_prefix_length));
- /* we need some more memory to store the target data */
- int mem = (argc+1 + n_scan_hosts) * sizeof(struct host);
- hosts = realloc( hosts, mem );
- hosts[n_hosts].ip = (uint32_t)0;
- subnet_add(inet_addr(optarg), scan_prefix_length, HOST_TARGET);
+ case 'm':
+ cmd_hosts_add(optarg, HOST_MODEL);
break;
case 'c':
cleanup_src = optarg;
@@ -332,26 +347,17 @@ main(int argc, char *argv[])
}
while (argc--) {
- if ((target_addr = libnet_name2addr4(l, argv[0], LIBNET_RESOLVE)) == -1) {
- errx(1, "Invalid address: %s", argv[0]);
- usage();
- }
- host_add(target_addr, HOST_MODEL);
+ cmd_hosts_add(argv[0], HOST_TARGET);
argv++;
}
- if (poison_mesh) {
+ if (poison_cross) {
struct host *host = hosts;
for(;host->ip; host++) {
host->flags |= (HOST_TARGET|HOST_MODEL);
}
}
- if (poison_reverse && active_targets() <= 0) {
- errx(1, "Spoofing the reverse path (-r) is only available when specifying at least one target (-t/-s).");
- usage();
- }
-
if (intf == NULL && (intf = pcap_lookupdev(pcap_ebuf)) == NULL)
errx(1, "%s", pcap_ebuf);
@@ -386,15 +392,18 @@ main(int argc, char *argv[])
}
}
-
if ((my_ha = (u_int8_t *)libnet_get_hwaddr(l)) == NULL) {
errx(1, "Unable to determine own mac address");
}
- if (active_targets() == 0) {
+ if (count_hosts( HOST_ACTIVE | HOST_TARGET ) == 0) {
errx(1, "No target hosts found.");
}
+ if (count_hosts( HOST_ACTIVE | HOST_MODEL ) == 0) {
+ errx(1, "No model hosts found.");
+ }
+
signal(SIGHUP, cleanup);
signal(SIGINT, cleanup);
signal(SIGTERM, cleanup);
@@ -411,8 +420,7 @@ main(int argc, char *argv[])
if (!(model->flags & HOST_MODEL)) continue;
if (target->ip != model->ip) {
arp_send(l, ARPOP_REPLY, my_ha, model->ip,
- (target->ip ? (u_int8_t *)&target->mac : brd_ha),
- target->ip,
+ (u_int8_t *) &target->mac, target->ip,
my_ha);
usleep(ARP_PAUSE);
if (poison_reverse) {

0 comments on commit 09d81d6

Please sign in to comment.
Something went wrong with that request. Please try again.