中文版 | English

网站首页 | 个人作品 | 博客 | 给我留言 | 经典分享 | 友情链接 | 黑白人生


用ARP探测网络中的混杂模式节点[转]

创建时间:2002-04-16
文章属性:原创
文章来源:www.opengram.com
文章提交:refdom (refdom_at_263.net)

Author:     Refdom
Email:     refdom@263.net
HomePage:  www.opengram.com
2002/4/14


     由于sniffer的危害,检测网络中是否存在sniffer也非常重要。Anti-Sniff就相应地产生,来检测网络
中的sniffer。

     检测sniffer的办法有很多,比如有些功能强大的sniffer会对IP地址进行解析获得机器名,那么可以通
过发送畸形数据包等待sniffer进行DNS解析等等,但是这些办法局限太大了。

     根据sniffer的基本工作原理,其核心就是设置网卡模式为 promiscuous(混杂模式),如果能够检测
到网络有是混杂模式的网卡,那么就可以判断可能存在一个sniffer。ARP协议在深入嗅探中很有作用,同时
也可以用于进行嗅探器的侦测。

     在混杂模式中,网卡进行包过滤不同于普通模式。本来在普通模式下,只有本地地址的数据包或者广播
(多播等)才会被网卡提交给系统核心,否则的话,这些数据包就直接被网卡抛弃。现在,混合模式让所有
经过的数据包都传递给系统核心,然后被sniffer等程序利用。因此,如果能利用中间的“系统核心”,就能
有效地进行是否混杂模式的检测。系统核心也会对一些数据包进行过滤,但是,和网卡的标准不一样的是。

     以Windows系统为例(实验可得):

FF-FF-FF-FF-FF-FF:这个是一个正规的广播地址,不管是正常模式还是其他模式,都会被网卡接收并传递给
系统核心。
FF-FF-FF-FF-FF-00:这个地址对于网卡来说,不是一个广播地址,在正常模式下会被网卡抛弃,但是系统核
心是认为这个地址同FF-FF-FF-FF-FF-FF是完全一样的。如果处于混杂模式,将被系统核心接收,并认为是一
个广播地址。所有的Windows操作系统都是如此。
FF-FF-00-00-00-00:Windows核心只对前面两字节作判断,核心认为这是一个同FF-FF-FF-FF-FF-FF一样的广
播地址。这就是为什么FF-FF-FF-FF-FF-00也是广播地址的原因。
FF-00-00-00-00-00:对于Win9x或WinME,则是检查前面的一个字节。因此会认为这个是一个广播地址。
    
     而对于LINUX内核,我则不清楚,不过从一些资料得到会判断一个group bit,不清楚具体什么意思,但是
基本上就是认为FF-00-00-00-00-00,是FF-FF-FF-FF-FF-FF一个类别的吧。(望熟悉LINUX者指点)

     所以,目的就要让正常模式的网卡抛弃掉探测包,而让混杂模式的系统核心能够处理探测。发送一个目的
地址为:FF-FF-FF-FF-FF-FE(系统会认为属于广播地址)的ARP请求,对于普通模式(广播等)的网卡,这个
地址不是广播地址,就会直接抛弃,而如果处于混杂模式,那么ARP请求就会被系统核心当作广播地址处理,然
后提交给sniffer程序。系统核心就会应答这个ARP请求。

     antisniffer也采用了这样的策略进行检测。

     下面这个例子就是FF-FF-FF-FF-FF-FE的ARP请求,可以对网络中的每个节点都发送这样的ARP请求。如果有
一般的sniffer存在,并设置网卡为混杂模式,那么系统核心就会作出应答,可以判断这些节点是否存在嗅探器
了。这种检测办法也是有局限的,对于那些修改内核的sniffer,就没有办法了,不过这种Sniffer毕竟属于少数
还有就是Win2k中一些动态加载的包捕获驱动(WinPcap就是),可能会让没有在混杂模式的网卡也作出响应。


///////////////////////////////////////////////////////////////////////////////
//
//                 Detect Promiscuous Node In Network
//
//           Author:     Refdom
//           Email:       refdom@263.net
//           Home Page:  www.opengram.com
//
//           2002/4/14
//
////////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Mac.h"     //GetMacAddr(),我写的把字符串转换为MAC地址的函数,就不列在这里了
#include <stdio.h>
#include <conio.h>
#include <Packet32.h>
#include <Winsock2.h>
#include <process.h>
#include <ntddndis.h>

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

#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 */

#define Max_Num_Adapter 10

#pragma pack(push, 1)

typedef struct ehhdr
{
     unsigned char     eh_dst[6];         /* destination ethernet addrress */
     unsigned char     eh_src[6];         /* source ethernet addresss */
     unsigned short     eh_type;         /* ethernet pachet type     */
}EHHDR, *PEHHDR;


typedef struct arphdr
{
     unsigned short     arp_hrd;             /* format of hardware address */
     unsigned short     arp_pro;             /* format of protocol address */
     unsigned char     arp_hln;             /* length of hardware address */
     unsigned char     arp_pln;             /* length of protocol address */
     unsigned short     arp_op;                 /* ARP/RARP operation */

     unsigned char     arp_sha[6];             /* sender hardware address */
     unsigned long     arp_spa;             /* sender protocol address */
     unsigned char     arp_tha[6];             /* target hardware address */
     unsigned long     arp_tpa;             /* target protocol address */
}ARPHDR, *PARPHDR;


typedef struct arpPacket
{
     EHHDR     ehhdr;
     ARPHDR     arphdr;
} ARPPACKET, *PARPPACKET;

#pragma pack(pop)

//the thread for listening
void ListenThread(void* Adapter);
//the function of sending packet
void SendARPPacket(void* Adapter);
BOOL DetectIsSniffer(LPPACKET lpPacket);

char g_szMyMacAddr[] = "AAAAAAAAAAAA";
char g_szMyIP[]       = "192.168.1.1";
char g_szTargetIP[]   = "192.168.1.2";

int main(int argc, char* argv[])
{
     static char AdapterList[Max_Num_Adapter][1024];    
     LPADAPTER     lpAdapter;
     WCHAR         AdapterName[2048];
     WCHAR         *temp,*temp1;

     ULONG AdapterLength = 1024;
    
     int AdapterNum = 0;
     int nRetCode, i;

     //Get The list of Adapter
     if(PacketGetAdapterNames((char*)AdapterName, &AdapterLength) == FALSE)
     {
         printf("Unable to retrieve the list of the adapters!\n");
         return 0;
     }

     temp = AdapterName;
     temp1 = AdapterName;
     i = 0;
     while ((*temp != '\0')||(*(temp-1) != '\0'))
     {
         if (*temp == '\0')
         {
             memcpy(AdapterList[i],temp1,(temp-temp1)*2);
             temp1 = temp+1;
             i++;
         }
        
         temp++;
     }
    
     AdapterNum = i;
     for (i = 0; i < AdapterNum; i++)
         wprintf(L"\n%d- %s\n", i+1, AdapterList[i]);
     printf("\n");
    
     //Default open the 0
     lpAdapter = (LPADAPTER) PacketOpenAdapter((LPTSTR) AdapterList[0]);
     if (!lpAdapter || (lpAdapter->hFile == INVALID_HANDLE_VALUE))
     {
         nRetCode = GetLastError();
         printf("Unable to open the driver, Error Code : %lx\n", nRetCode);
         return 0;
     }

     //begin listening
     _beginthread(ListenThread, 0, (void*) lpAdapter);

     Sleep(500);

     //send the packet
     _beginthread(SendARPPacket, 0, (void*) lpAdapter);

     Sleep(2000);

     printf ("\n\nDetecting end.\n");

     // close the adapter and exit
     PacketCloseAdapter(lpAdapter);

     return 0;
}


void SendARPPacket(void* Adapter)
{
     char MacAddr[6];
     char szPacketBuf[600];
     LPADAPTER     lpAdapter = (LPADAPTER) Adapter;
     LPPACKET     lpPacket;
     ARPPACKET ARPPacket;

     lpPacket = PacketAllocatePacket();
     if(lpPacket == NULL)
     {
         printf("\nError:failed to allocate the LPPACKET structure.\n");
         return;
     }

     ZeroMemory(szPacketBuf, sizeof(szPacketBuf));

     // the fake mac of multicast
     if (!GetMacAddr("FFFFFFFFFFFE", MacAddr))
     {
         printf ("Get Mac address error!\n");
         goto Exit0;
     }
     memcpy(ARPPacket.ehhdr.eh_dst, MacAddr, 6);

     //the MAC of sender
     if (!GetMacAddr(g_szMyMacAddr, MacAddr))
     {
         printf ("Get Mac address error!\n");
         goto Exit0;
     }
     memcpy(ARPPacket.ehhdr.eh_src, MacAddr, 6);

     ARPPacket.ehhdr.eh_type = htons(EPT_ARP);

     //arp header
     ARPPacket.arphdr.arp_hrd = htons(ARP_HARDWARE);
     ARPPacket.arphdr.arp_pro = htons(EPT_IP);
     ARPPacket.arphdr.arp_hln = 6;
     ARPPacket.arphdr.arp_pln = 4;
     ARPPacket.arphdr.arp_op = htons(ARP_REQUEST);

     if (!GetMacAddr("00E04C6A21DF", MacAddr))
     {
         printf ("Get Mac address error!\n");
         goto Exit0;
     }
     memcpy(ARPPacket.arphdr.arp_sha, MacAddr, 6);
     ARPPacket.arphdr.arp_spa = inet_addr(g_szMyIP);

     if (!GetMacAddr("000000000000", MacAddr))
     {
         printf ("Get Mac address error!\n");
         goto Exit0;
     }
     memcpy(ARPPacket.arphdr.arp_tha , MacAddr, 6);
     ARPPacket.arphdr.arp_tpa = inet_addr(g_szTargetIP);

     memcpy(szPacketBuf, (char*)&ARPPacket, sizeof(ARPPacket));
     PacketInitPacket(lpPacket, szPacketBuf, 60);

     if(PacketSetNumWrites(lpAdapter, 1)==FALSE)
     {
         printf("warning: Unable to send more than one packet in a single write!\n");
     }
    
     if(PacketSendPacket(lpAdapter, lpPacket, TRUE)==FALSE)
     {
         printf("Error sending the packets!\n");
         goto Exit0;
     }

     printf ("Send ok!\n\n");

Exit0:
     PacketFreePacket(lpPacket);
     _endthread();
}

void ListenThread(void* Adapter)
{
     LPPACKET lpPacket;
     LPADAPTER lpAdapter = (LPADAPTER) Adapter;
     char buffer[256000];

     if((lpPacket = PacketAllocatePacket())==NULL){
         printf("\nError: failed to allocate the LPPACKET structure.");
         return;
     }
     PacketInitPacket(lpPacket,(char*)buffer,256000);

     // set the network adapter in promiscuous mode
    
     if(PacketSetHwFilter(lpAdapter, NDIS_PACKET_TYPE_DIRECTED)==FALSE){
             printf("Warning: unable to set promiscuous mode!\n");
     }

     // set buffer in the driver
     if(PacketSetBuff(lpAdapter,512000)==FALSE){
             printf("Unable to set the kernel buffer!\n");
             return;
     }

     // set second read timeout
     if(PacketSetReadTimeout(lpAdapter, 200)==FALSE){
             printf("Warning: unable to set the read tiemout!\n");
     }
     //main capture loop
     printf("Listen....\n");
     while(true)
     {
         // capture the packets
         if(PacketReceivePacket(lpAdapter, lpPacket, TRUE)==FALSE){
             printf("Error: PacketReceivePacket failed");
             return ;
         }
         //
         DetectIsSniffer(lpPacket);
     }

     PacketFreePacket(lpPacket);

     // close the adapter and exit
     PacketCloseAdapter(lpAdapter);
     _endthread();
}

BOOL DetectIsSniffer(LPPACKET lpPacket)
{
     BOOL bFlag = FALSE;
     PARPHDR pARPHeader;
     PARPPACKET pARPPacket;
     char MacAddr[6];

     GetMacAddr(g_szMyMacAddr, MacAddr);
     pARPPacket = (PARPPACKET) ((char*)lpPacket->Buffer + 20);

     if (pARPPacket->ehhdr.eh_type == htons(EPT_IP))
         return FALSE;

     if (strcmp((char*)(pARPPacket->ehhdr.eh_dst), MacAddr) == 0
         && pARPPacket->ehhdr.eh_type == htons(EPT_ARP))
     {
         char szTemp[10];

         pARPHeader = (PARPHDR)((char*)lpPacket->Buffer + 20 + sizeof(EHHDR));

         memcpy(szTemp, &pARPHeader->arp_spa, sizeof(pARPHeader->arp_spa));
         printf ("A PROMISCUOUS NODE EXISTS!!\n");
         printf ("\tIP:%s\n\n", inet_ntoa(*((struct in_addr *)(szTemp))));
         return TRUE;
     }
     return FALSE;
}



Reference:

1、Securiteam 《Detecting sniffers on your network》、
   《AntiSniff - find sniffers on your local network》
2、l0pht.com的Antisniffer说明书

上一篇: D段保留地址含义
下一篇: 电影<<立春>>