用ARP探測網路中的混雜模式節點
Author: Refdom
Email: refdom@263.net
HomePage: www.opengram.com
由於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(g_szMyMacAddr, 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說明書