我们知道了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;// opunsigned 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请求,这个就证明了他是有时间限制的。(时间可能有点长)
最后最后,小伙伴们千万不要胡乱试,这个如果出了差错的话,额......不过可以在虚拟机上进行试试。最后,如果大家看完本章内容有所收获的话,希望点一下赞吧!谢谢!!
如果有小伙伴对网络的数据包怎么发送与接收不清楚的,也不要太着急,下一次会发整个网络中的数据包是怎么发和怎么收的。