Skip to content

Instantly share code, notes, and snippets.

@phretor
Created October 19, 2011 15:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save phretor/1298561 to your computer and use it in GitHub Desktop.
Save phretor/1298561 to your computer and use it in GitHub Desktop.
Packet reflector that reflects packets back to the attacker
/*-
* Copyright (c) 2008
* Federico Maggi <fmaggi@elet.polimi.it>, Politecnico di Milano. All rights reserved.
*
* 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. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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, WHETHER 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.
*
* @(#)reflector.c 0.1 (Santa Barbara) 10/24/08
*/
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <net/ethernet.h>
#include <netinet/ether.h>
#include <netinet/if_ether.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <libnet.h>
#include <pcap.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <syslog.h>
#define _BSD_SOURCE 1
#define LOG_ID "[RFLC]"
#define VICTIM 130
#define RELAYER 131
#define IP_ADDR_LEN 4
#define DEV_STRLEN 8
#define PCAP_BUF_LEN 51200
#define DEFAULT_DEV NULL
#define min(x,y) \
(x < y ? x : y)
#define AR_V(arp_pld) \
!(memcmp(arp_pld->ar_tpa, opts->victim_ip, sizeof(arp_pld->ar_tpa)))
#define AR_R(arp_pld) \
!(memcmp(arp_pld->ar_tpa, opts->relayer_ip, sizeof(arp_pld->ar_tpa)))
#define AR_CAREOF(arp_pld) \
(AR_R(arp_pld) || AR_V(arp_pld))
#define TO_V(ip_hdr) \
!(memcmp(&(ip_hdr->ip_dst), opts->victim_ip, sizeof(struct in_addr)))
#define TO_R(ip_hdr) \
!(memcmp(&(ip_hdr->ip_dst), opts->relayer_ip, sizeof(struct in_addr)))
#define CAREOF(ip_hdr) \
(TO_R(ip_hdr) || TO_V(ip_hdr))
#define MIRROR(ip_hdr) \
(TO_V(ip_hdr) ? RELAYER : VICTIM)
#define AR_WHO(arp_pld) \
(AR_R(arp_pld) ? RELAYER : VICTIM)
/*
* Command line options
*/
typedef struct {
struct in_addr * victim_ip; /* Victim IP */
struct ether_addr * victim_eth; /* Victim ETH */
struct in_addr * relayer_ip; /* Relayer IP */
struct ether_addr * relayer_eth; /* Relayer ETH */
char * device; /* Device */
} opts_t;
/*
* ARP Payload
*/
struct rflc_arp_pld {
u_char ar_sha[ETHER_ADDR_LEN]; /* Source HW */
u_char ar_spa[IP_ADDR_LEN]; /* Source IP */
u_char ar_tha[ETHER_ADDR_LEN]; /* Target HW */
u_char ar_tpa[IP_ADDR_LEN]; /* Target IP */
};
/*
* Command line options
*/
opts_t * opts;
/*
* Libnet context
*/
libnet_t * l;
/*
* Prints usage message to stdout and exits according to
* the status.
*/
void
usage (int status)
{
printf(
"Usage: reflector options\n\n"
" -h --help Display this help.\n"
" -v --victim-ip Victim IP.\n"
" -w --victim-ethernet Victim ETHER Address.\n\n"
" -r --relayer-ip Relayer IP.\n"
" -s --relayer-ethernet Relayer ETHER Address.\n\n"
" -i --interface Use the another interface.\n"
);
exit(status);
}
/*
* Parses the command line and returns not 1 if something
* goes bad.
*/
int
optparse (int argc, char * argv[])
{
int c;
struct ether_addr * eth;
const struct option longopts [] = {
{ "victim-ip", required_argument, NULL, 'v' },
{ "victim-ethernet", required_argument, NULL, 'w' },
{ "relayer-ip", required_argument, NULL, 'r' },
{ "relayer-ethernet", required_argument, NULL, 's' },
{ "interface", required_argument, NULL, 'i' },
{ "help", no_argument, NULL, 'h' },
{ NULL, 0, NULL, 0 }
};
/* All null */
opts->victim_ip = NULL;
opts->victim_eth = NULL;
opts->relayer_ip = NULL;
opts->relayer_eth = NULL;
/* Default interface */
opts->device = DEFAULT_DEV;
/* -------------------------------------------------------------------- */
/* Let's prepare the buffer */
if ((eth = malloc(sizeof(struct ether_addr))) == NULL) {
syslog(LOG_ERR, "Error allocating temporary memory for ether_aton");
return -1;
}
/* Get the options */
while ((c = getopt_long(argc, argv, "v:w:r:s:i:hd", longopts, NULL)) != -1)
switch (c) {
case 'h':
usage(1);
case 'v':
if ((opts->victim_ip = malloc(sizeof(struct in_addr))) == NULL) {
syslog(LOG_ERR, "Error allocating memory for victim"
"IP address");
return -1;
}
if (inet_aton(optarg, opts->victim_ip) == 0) {
syslog(LOG_ERR, "Bad victim IP address");
return -1;
}
break;
case 'w':
if ((opts->victim_eth = malloc(sizeof(struct ether_addr))
) == NULL) {
syslog(LOG_ERR, "Error allocating memory for victim"
"ETH address");
return -1;
}
if ((eth = ether_aton(optarg)) == NULL) {
syslog(LOG_ERR, "Bad victim ETH address");
return -1;
}
memcpy(opts->victim_eth, eth, sizeof(struct ether_addr));
break;
case 'r':
if ((opts->relayer_ip = malloc(sizeof(struct in_addr))) == NULL) {
syslog(LOG_ERR, "Error allocating memory for relayer"
"IP address");
return -1;
}
if (inet_aton(optarg, opts->relayer_ip) == 0) {
syslog(LOG_ERR, "Bad relayer IP address");
return -1;
}
break;
case 's':
if ((opts->relayer_eth = malloc(sizeof(struct ether_addr))
) == NULL) {
syslog(LOG_ERR, "Error allocating memory for relayer ETH"
"address");
return -1;
}
if ((eth = ether_aton(optarg)) == NULL) {
syslog(LOG_ERR, "Bad relayer ETH address");
return -1;
}
memcpy(opts->relayer_eth, eth, sizeof(struct ether_addr));
break;
case 'i':
if ((opts->device = malloc(min(strlen(optarg), DEV_STRLEN) + 1)
) == NULL) {
syslog(LOG_ERR, "Error allocating memory for the device"
"name");
return -1;
}
snprintf(opts->device, min(strlen(optarg), DEV_STRLEN) + 1,
"%s", optarg);
break;
default :
usage(-1);
}
argc -= optind;
argv += optind;
if (memcmp(opts->victim_ip, opts->relayer_ip, sizeof(struct in_addr)) == 0) {
syslog(LOG_ERR, "Victim IP and relayer IP should not be identical");
return -1;
}
#ifdef DISALLOW_SAME_ETH
if (memcmp(opts->victim_eth, opts->relayer_eth, sizeof(struct ether_addr)
) == 0) {
syslog(LOG_ERR, "Victim ETH and relayer ETH should not be identical");
return -1;
}
#endif
#ifdef DISALLOW_SAME_IP
if (opts->victim_ip == NULL || opts->victim_eth == NULL ||
opts->relayer_ip == NULL || opts->relayer_eth == NULL) {
syslog(LOG_ERR, "Some mandatory options are missing");
return -1;
}
#endif
return 1;
}
/*
* Builds an ARP reply given source/target hardware/protocol addresses.
*/
void
l_ary (u_int8_t * sha, u_int8_t * spa, u_int8_t * tha, u_int8_t * tpa)
{
if (libnet_build_arp( ARPHRD_ETHER, ETHERTYPE_IP,
ETHER_ADDR_LEN, IP_ADDR_LEN, ARPOP_REPLY,
sha, spa,
tha, tpa,
NULL, 0, l, 0) == -1) {
syslog(LOG_ERR, "Error creating the spoofed ARP packet, %s",
libnet_geterror(l));
exit(1);
}
}
/*
* Builds an ethernet frame given target/source hardware address and
* the ethernet type.
*/
void
l_eth (u_int8_t * tha, u_int8_t * sha, u_int16_t type,
u_int8_t * payload, u_int32_t payload_s)
{
if (libnet_build_ethernet(
tha,
sha,
type,
payload,
payload_s,
l,
0) == -1) {
syslog(LOG_ERR, "Error creating the ETH layer, %s",
libnet_geterror(l));
exit(1);
}
}
/*
* Writes the current packet to the wire.
*/
void
l_wr()
{
/* Put the packet on the wire */
if (libnet_write(l) == -1) {
syslog(LOG_ERR, "Error writing the packet to the link layer"
", %s", libnet_geterror(l));
libnet_diag_dump_context(l);
libnet_diag_dump_pblock(l);
exit(1);
}
}
/*
* Reflects an IP packet back to the attacker spoofing the victim or the
* relayer accordting to the value of "who".
*/
void
rflc_reflect (int who, const struct pcap_pkthdr * pkthdr, const u_char * packet)
{
const struct libnet_ethernet_hdr * eth_hdr;
const struct libnet_ipv4_hdr * ip_hdr;
const struct libnet_tcp_hdr * tcp_hdr;
u_int8_t * tcp_pld;
u_int8_t * eth_pld;
u_int32_t eth_pld_s;
size_t ip_len; /* IP packet total length */
size_t ip_hl; /* IP header length */
size_t tcp_len; /* TCP packet total length */
size_t tcp_hl; /* TCP header length */
size_t tcp_pl; /* TCP payload length */
u_int32_t spoofed_ip;
u_int8_t * spoofed_eth;
/* -------------------------------------------------------------------- */
libnet_clear_packet(l);
eth_hdr = (struct libnet_ethernet_hdr *)(packet);
ip_hdr = (struct libnet_ipv4_hdr *)(packet +
sizeof(struct libnet_ethernet_hdr));
spoofed_ip = *(u_int32_t *)(who == VICTIM ? opts->victim_ip :
opts->relayer_ip);
spoofed_eth = (u_int8_t *)(who == VICTIM ? opts->victim_eth :
opts->relayer_eth);
ip_hl = ip_hdr->ip_hl * 4;
ip_len = ntohs(ip_hdr->ip_len);
tcp_hdr = (struct libnet_tcp_hdr *)((u_int8_t *)ip_hdr + ip_hl);
tcp_len = ip_len - ip_hl;
tcp_hl = tcp_hdr->th_off * 4;
tcp_pl = tcp_len - tcp_hl;
memcpy( /* Reflection */
(struct in_addr *)&(ip_hdr->ip_dst),
(struct in_addr *)&(ip_hdr->ip_src),
sizeof(struct in_addr)
);
memcpy( /* Spoofing */
(struct in_addr *)&(ip_hdr->ip_src),
(struct in_addr *)&spoofed_ip,
sizeof(struct in_addr)
);
tcp_pld = ((u_int8_t *)tcp_hdr + tcp_hl);
/* Libnet <= 1.1.2 bug */
if (ip_hdr->ip_p == IPPROTO_TCP)
if (tcp_len % 2 == 1)
tcp_pld[tcp_pl] = 0;
/* The IP payload has the same length regardless of the upper protocol */
if (libnet_do_checksum(l, (u_int8_t *)ip_hdr, ip_hdr->ip_p, tcp_len) < 0) {
syslog(LOG_ERR, "Error calculating IP checksum, %s",
libnet_geterror(l));
exit(1);
}
/* IP checksum */
if (libnet_do_checksum(l, (u_int8_t *)ip_hdr, IPPROTO_IP, ip_hl) < 0) {
syslog(LOG_ERR, "Error calculating TCP checksum, %s",
libnet_geterror(l));
exit(1);
}
/* Incapsulate the packet as ethernet payload */
eth_pld_s = pkthdr->caplen - sizeof(struct libnet_ethernet_hdr);
eth_pld = (u_int8_t *)(packet + sizeof(struct libnet_ethernet_hdr));
/* Create the packet */
l_eth((u_int8_t *)eth_hdr->ether_shost, spoofed_eth,
ETHERTYPE_IP, eth_pld, eth_pld_s);
/* Put it on wire */
l_wr();
}
/*
* Spoof an ARP reply based on the content of the ARP request's target
* protocol address.
*/
void
rflc_arpoof (int who, const u_char * packet)
{
const struct libnet_ethernet_hdr * eth_hdr;
const struct libnet_arp_hdr * arp_hdr;
const struct rflc_arp_pld * arp_pld;
u_int8_t * spoofed_ip;
u_int8_t * spoofed_eth;
/* -------------------------------------------------------------------- */
eth_hdr = (struct libnet_ethernet_hdr *)(packet);
arp_hdr = (struct libnet_arp_hdr *)(packet +
sizeof(struct libnet_ethernet_hdr));
arp_pld = (struct rflc_arp_pld *)(packet +
sizeof(struct libnet_ethernet_hdr) +
sizeof(struct libnet_arp_hdr));
spoofed_ip = (u_int8_t *)(who == VICTIM ? opts->victim_ip :
opts->relayer_ip);
spoofed_eth = (u_int8_t *)(who == VICTIM ? opts->victim_eth :
opts->relayer_eth);
libnet_clear_packet(l);
l_ary(spoofed_eth, spoofed_ip, (u_int8_t *)arp_pld->ar_sha,
(u_int8_t *)arp_pld->ar_spa);
l_eth((u_int8_t *)arp_pld->ar_sha, spoofed_eth,
ETHERTYPE_ARP, NULL, 0);
l_wr();
}
/*
* Dispatches according to the IP.
*/
void
rflc_ip4_handler (u_char * args, const struct pcap_pkthdr * pkthdr,
const u_char * packet)
{
const struct libnet_ipv4_hdr * ip_hdr;
const struct libnet_ethernet_hdr * eth_hdr;
/* -------------------------------------------------------------------- */
eth_hdr = (struct libnet_ethernet_hdr *)(packet);
ip_hdr = (struct libnet_ipv4_hdr *)(packet +
sizeof(struct libnet_ethernet_hdr));
/* If the packet is to the victim/relayer */
if (CAREOF(ip_hdr))
rflc_reflect(MIRROR(ip_hdr), pkthdr, packet);
}
/*
* Dispatches according to the ARP.
*/
void
rflc_arp_handler (u_char * args, const struct pcap_pkthdr * pkthdr,
const u_char * packet)
{
const struct libnet_arp_hdr * arp_hdr;
const struct rflc_arp_pld * arp_pld;
/* -------------------------------------------------------------------- */
arp_hdr = (struct libnet_arp_hdr *)(packet +
sizeof(struct libnet_ethernet_hdr));
arp_pld = (struct rflc_arp_pld *)(packet +
sizeof(struct libnet_ethernet_hdr) +
sizeof(struct libnet_arp_hdr));
/* If the ARP REQUEST is for victim/relayer */
if (ntohs(arp_hdr->ar_op) == ARPOP_REQUEST)
if (AR_CAREOF(arp_pld))
rflc_arpoof(AR_WHO(arp_pld), packet);
}
/*
* Dispatches according to the ETHERTYPE
*/
void
rflc_eth_handler (u_char * args, const struct pcap_pkthdr * pkthdr,
const u_char * packet)
{
u_int16_t ether_type;
/* -------------------------------------------------------------------- */
ether_type = ntohs(((struct libnet_ethernet_hdr *)(packet))->ether_type);
if (ether_type == ETHERTYPE_IP)
rflc_ip4_handler(args, pkthdr, packet);
else if (ether_type == ETHERTYPE_ARP)
rflc_arp_handler(args, pkthdr, packet);
}
/*
* The main
*/
int
main (int argc, char * argv[], char * envp[])
{
/** Pcap handle */
pcap_t * p;
/** Pcap error buffer */
char p_eb[PCAP_ERRBUF_SIZE];
char l_eb[LIBNET_ERRBUF_SIZE];
/** Arguments passed to the callback */
u_char * pcap_args = NULL;
/* -------------------------------------------------------------------- */
/* Syslog */
openlog(LOG_ID, LOG_CONS | LOG_NDELAY | LOG_PERROR, LOG_LOCAL1);
/* Enough stuff? */
if (argc < 9)
usage(1);
/* Root privilegies 0 */
if (getuid()) {
syslog(LOG_ERR, "Must be r00t!");
exit(1);
}
/* Alloc memory for command line options */
if ((opts = malloc(sizeof(opts_t))) == NULL) {
syslog(LOG_ERR, "Error allocating memory for command line options");
exit(1);
}
/* Parsing the command line */
if (optparse(argc, argv) == -1) {
syslog(LOG_ERR, "Invalid values passed to command line");
usage(-1);
}
/* Lookup the default device if needed */
if (opts->device == DEFAULT_DEV) {
if((opts->device = pcap_lookupdev(p_eb)) == NULL) {
syslog(LOG_ERR, "Error looking up the default network interface"
", %s",
pcap_geterr(p));
exit(1);
}
}
/* Give the user some feedback */
if (opts->device != DEFAULT_DEV)
syslog(LOG_INFO, "Interface: '%s'", opts->device);
else
syslog(LOG_INFO, "Interface: default (%s)", opts->device);
syslog(LOG_INFO, "Victim: %s (Ether: %s)",
inet_ntoa(*(opts->victim_ip)),
ether_ntoa(opts->victim_eth)
);
syslog(LOG_INFO, "Relayer: %s (Ether: %s)",
inet_ntoa(*(opts->relayer_ip)),
ether_ntoa(opts->relayer_eth)
);
/* Open device for sniffing */
if ((p = pcap_open_live(opts->device, PCAP_BUF_LEN,
1, 1000, p_eb)) == NULL) {
syslog(LOG_ERR, "Error opening the device for sniffing, %s",
pcap_geterr(p));
exit(1);
}
/* Validate the interface - Suggestion from tcpdump.org/sniffex.c */
if (pcap_datalink(p) != DLT_EN10MB) {
syslog(LOG_ERR, "Invalid Ethernet device, %s", pcap_geterr(p));
exit(1);
}
/* Initialize the libnet context */
if ((l = libnet_init(LIBNET_LINK, opts->device, l_eb)) == NULL) {
syslog(LOG_ERR, "Error initializing the libnet environment, %s",
libnet_geterror(l));
exit(1);
}
/* Grab packets */
pcap_loop(p, -1, rflc_eth_handler, pcap_args);
/* Closing the reader */
pcap_close(p);
/* Close libnet */
libnet_destroy(l);
/* Close syslog */
closelog();
/* Quit */
exit(0);
}
/* EOF */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment