arp欺骗原理以及实现方式

2023-12-14 23:31:47

我们知道了arp的作用,那么此时我们怎么可以用他来进行攻击呢?在一个局域网中,我们怎么实现呢?

原理:

这样B就可以做到中间人了,可以接受到两个主机的数据了。换句话来说,在同一个局域网内,我们要黑掉一个主机,只需要构建大量的arp应答,把自己的mac地址发送给要黑掉的主机,这样他发送的所有数据都会经过你的主机,如果你不管,也不转发,那么,恭喜你,成功让他的主机无法上网了。但是其实现在就算是黑掉也没什么用,因为https中经过加密,还有认证,一改数据就会被发现。所以没有什么意义。但是你可以黑掉同一个局域网中的另一台主机,让他无法上网。

说来说去,原理我知道了,但是我们应该怎么实现呢?此时我们就要回忆一下套接字类型了,有三种。流式套接字,数据报套接字,原始套接字。流式套接字对应的是tcp,数据包套接字是udp,那么答案已经出来了吧,不错,我们可以用原始套接字来实现伪造arp数据包。那么怎么实现呢?代码如下:

#include <iostream>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ether.h>
#include <cstring>
#include <unistd.h>
#define BUF_SIZE 1024
#define DST_SIZE 7
#define SRC_SIZE 7
int main()
{
    int sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ARP));
    if (sockfd < 0)
    {
        std::cout << "socket fail" << std::endl;
        exit(1);
    }
    unsigned char buffer[1024];
    memset(buffer, 0, 1024);
    while (true)
    {
        ssize_t s = recvfrom(sockfd, buffer, 1024, 0, nullptr, nullptr);
        if (s < 0)
        {
            std::cout << "recvfrom fail" << std::endl;
            exit(2);
        }
        // 以太网数据包头
        std::cout << "以太网数据包报头" << std::endl;
        unsigned short type = 0;
        unsigned char dst[DST_SIZE] = "";
        unsigned char src[SRC_SIZE] = "";
        type = ntohs(*(unsigned short *)(buffer + 12));
        for (size_t i = 0; i < 6; i++)
            dst[i] = buffer[i];
        for (size_t i = 6; i < 12; i++)
            src[i - 6] = buffer[i];
        printf("目的mac:%x%x%x%x%x%x", dst[0], dst[1], dst[2], dst[3], dst[4], dst[5]);
        printf("源mac:%x%x%x%x%x%x", src[0], src[1], src[2], src[3], src[4], src[5]);
        printf("类型:%x", type);
        std::cout << std::endl;
        // arp协议数据报头
        std::cout << "arp数据包报头" << std::endl;
        // 硬件类型
        unsigned short hardware;
        // 协议类型
        unsigned short pro;
        // 硬件地址长度
        unsigned char hardware_len;
        // 协议长度
        unsigned char pro_len;
        // op
        unsigned short op;
        // 发送方mac地址
        unsigned char src_mac[7] = "\0";
        // 发送方ip地址
        std::string src_ip;
        // 目的mac地址
        unsigned char dst_mac[7] = "\0";
        // 目的ip地址
        std::string dst_ip;
        ///
        hardware = ntohs(*(unsigned short *)(buffer + 14));

        pro = ntohs(*(unsigned short *)(buffer + 16));

        hardware_len = buffer[18];

        pro_len = buffer[19];

        op = ntohs(*(unsigned short *)(buffer + 20));

        for (size_t i = 22; i < 28; i++)
            src_mac[i - 22] = buffer[i];

        src_ip = inet_ntoa(*(in_addr *)(buffer + 28));

        for (size_t i = 32; i < 38; i++)
            dst_mac[i - 32] = buffer[i];

        dst_ip = inet_ntoa(*(in_addr *)(buffer + 38));
        /
        printf("硬件类型:%x ", hardware);
        printf("协议类型:%x ", pro);
        printf("硬件长度:%x ", hardware_len);
        printf("协议长度:%x ", pro_len);
        printf("op:%x ", op);
        printf("源mac:%x%x%x%x%x%x ", src_mac[0], src_mac[1], src_mac[2], src_mac[3], src_mac[4], src_mac[5]);
        std::cout << "源ip" << src_ip << " ";
        printf("目的mac:%x%x%x%x%x%x ", dst_mac[0], dst_mac[1], dst_mac[2], dst_mac[3], dst_mac[4], dst_mac[5]);
        std::cout << "目的ip" << dst_ip << " ";
        std::cout << std::endl;
    }
    // 完成之后关闭文件
    close(sockfd);
    return 0;
}

以上是我实现的一个类似于抓包工具(不是抓包工具,就是类似于)。他可以获取我们局域网中的所有数据包。并且可以解析。这个代码只有读取,没有发送,因为我用的是云服务器,这个云服务器所在局域网不是我所在的(害怕弄出麻烦来)。所以我就只进行了读取,但是如果你想测试的话,可以试试,用sendto就可以,但是在用sendto时,我们有几个地方与udp中使用的不一样,这个我就不在这里详细说了,想知道的小伙伴可以私信问或是上网查查。那么此时我们应该怎么用呢?测试如下:

我开了两个端口,一个是用来删除arp缓存中的默认网关的地址的,一个来运行。我们可以清楚的看见,这个我删除了之后,有一个arp的应答,所以我们可以得知,在这之前,肯定有一个请求。

所以这里也证明了网络中是有Arp请求和应答的,你可以等一会,你会看见另一个arp请求,这个就证明了他是有时间限制的。(时间可能有点长)

最后最后,小伙伴们千万不要胡乱试,这个如果出了差错的话,额......不过可以在虚拟机上进行试试。最后,如果大家看完本章内容有所收获的话,希望点一下赞吧!谢谢!!

如果有小伙伴对网络的数据包怎么发送与接收不清楚的,也不要太着急,下一次会发整个网络中的数据包是怎么发和怎么收的。

文章来源:https://blog.csdn.net/huichaochao/article/details/135005425
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。