交換型網絡環境嗅探原理及LINUX下的實現
1. 以太網嗅探原理
以太網環境下的嗅探本身是比較簡單的,只要網卡能設置成混雜模式且有數據包到達網卡,則可用多種方法捕獲數據包并進行各種協議分析。在LINUX下可用RAW套接字,SOCK_PACKET套接字, LIBPCAP函數包等方法捕獲數據包,典型的應用程序如TCPDUMP, LINUX_SNIFFER等。
在共享型以太網中,上述兩個條件顯然是滿足的。所有的主機都連接到HUB,而HUB對數據包傳輸形式是廣播。這意味著發給某個主機的數據包也會被其它所有主機的網卡所收到。因此在這樣的環境中,任何設置成混雜模式的主機,都可以捕獲發送給其它主機的數據包,從而竊聽網絡上的所有通信。
在交換型以太網中,上述條件2是不滿足的。所有的主機連接到SWITCH,SWITCH比HUB更聰明,它知道每臺計算機的MAC地址信息和與之相連的特定端口,發給某個主機的數據包會被SWITCH從特定的端口送出,而不是象HUB那樣,廣播給網絡上所有的機器。這種傳輸形式使交換型以太網的性能大大提高,同時還有一個附加的作用:使傳統的嗅探器無法工作。
綜上所述,交換型網絡環境嗅探的核心問題是:如何使本不應到達的數據包到達本地。通常的方法有MAC洪水包和ARP欺騙。其中MAC洪水包是向交換機發送大量含有虛構MAC地址和IP地址的IP包,使交換機無法處理如此多的信息,致使交換機就進入了所謂的"打開失效"模式,也就是開始了類似于集線器的工作方式,向網絡上所有的機器廣播數據包。(具體實現請參閱Dsniff中的macof)本文中,我們將要詳細分析ARP欺騙模式。
2. 相關協議數據包格式
以太數據包格式:
類型0800 :IP數據包
類型0806 :ARP數據包
ARP數據包格式:
ARP數據包簡化格式
為了論述的簡潔性,我們把ARP數據包格式做一些簡化。 目的端MAC地址 源MAC地址 ARP包類型 發送端MAC地址 發送端IP地址 目的端MAC地址 目的端IP地址
3. 實驗環境
為了更清楚的描述交換網絡的嗅探原理,我們建立一個虛構的交換網絡環境, 在下面的論述中將用到這些數據.
4. ARP協議原理
在以太網中傳輸的數據包是以太包,而以太包的尋址是依據其首部的物理地址(MAC地址)。僅僅知道某主機的邏輯地址(IP地址)并不能讓內核發送一幀數據給此主機,內核必須知道目的主機的物理地址才能發送數據。ARP協議的作用就是在于把邏輯地址變換成物理地址,也既是把32bit的IP地址變換成48bit的以太地址。
每一個主機都有一個ARP高速緩存,此緩存中記錄了最近一段時間內其它IP地址與其MAC地址的對應關系。如果本機想與某臺主機通信,則首先在ARP高速緩存中查找此臺主機的IP和MAC信息,如果存在,則直接利用此MAC地址構造以太包;如果不存在,則向本網絡上每一個主機廣播一個ARP請求包,其意義是"如果你有此IP地址,請告訴我你的MAC地址",目的主機收到此請求包后,發送一個ARP響應包,本機收到此響應包后,把相關信息記錄在ARP高速緩存中,以下的步驟同上。
可以看出,ARP協議是有缺點的,第三方主機可以構造一個ARP欺騙包,而源主機卻無法分辨真假。
5. ARP欺騙原理
假設B(2.2.2.2)要與A(1.1.1.1)通信,且B的ARP高速緩存中沒有關于A的MAC信息,則B發出ARP請求包。
此時,B的ARP高速緩存中關于A的記錄為(1.1.1.1 <-- --> 04:04:04),則B向A發IP包實際上是發到我的主機(4.4.4.4,04:04:04)。同理,如果我進一步欺騙A,讓A的ARP高速緩存中關于B的記錄為(2.2.2.2 <-- --> 04:04:04), 則A向B發IP包實際上也是發到我的主機(4.4.4.4,04:04:04)。最后,我讓本機打開數據包轉發,也既是充當路由器,則A,B之間能正常通信,但我能全部捕獲到相關數據。
以上討論的是欺騙兩臺主機,如果我能讓局域網中每一臺主機的ARP高速緩存中關于其它任意一個主機所對應的MAC地址都為我的MAC地址(04:04:04:04),則本局域網中所有數據包我都能捕獲到!
6. 程序設計思路
使用到的函數包
libpcap : 捕獲ARP數據包。
libnet : 獲得本機的MAC地址和IP地址;構造和發送ARP欺騙包。
這兩個的函數包的使用在網上資料很多,本文中不介紹。
主要數據結構
程序中有兩個全局變量,MYIP代表本機的IP地址,MYMAC代表本機的MAC地址。
程序中維護一個存放主機信息的鏈表:
typedef struct host HOST;
struct host
{
unsigned long ip; // IP地址
unsigned char mac[6]; // MAC地址
int mac_flag; // 0:MAC為空,1:MAC不為空
HOST * next;
};
#p#掌握本局域網中每一臺主機的IP地址和MAC地址信息。
利用libpcap捕獲網絡中的ARP請求/應答包,最大限度的提取相關信息。如在第五節中的B對A的ARP請求包,我們可以提取出關于B的完整信息(2.2.2.2,02:02:02),也獲得了關于A的部分信息(1.1.1.1,null)。在知道網絡中有主機A的情況下,我們可以構造并發送對A的ARP請求包,捕獲A的ARP應答包,從而完整掌握A的信息。同理,我們也可以捕獲TCP/UDP等數據包,從中提取信息。
創建一個向鏈表增加主機信息的函數:add_host(ip,mac), 每收到一個ARP請求/應答包,都執行add_host( )兩次:add_host(發送端IP,發送端MAC),add_host(目的端IP,目的端MAC)。
在收到ARP應答包時,首先檢查發送端的IP和MAC,如果IP不是自己的,但MAC是自己的,則說明此應答包是本機構造的ARP欺騙包,程序忽略。
對于正常的ARP請求包和應答包,add_host(ip, mac )中IP或MAC只要有一個是自己的(ip == MYIP || mac ==MYMAC),則程序忽略。顯然,沒有必要自己欺騙自己。
add_host(ip,mac)遍歷主機鏈表,如果IP存在,且MAC不空,則把MAC地址寫入;如果不存在,則增加一個HOST節點,寫入IP地址,如果MAC不空,則也把MAC地址寫入。 注意到這樣一個情況:在ARP請求包中,目的MAC地址是沒有意義的,所以我們只寫入IP地址,而MAC地址用NULL來表示。這是我們收集網絡拓樸結構的一種被動方法。
函數add_host( )邏輯設計MYIP = IP(d),MYMAC = MAC(d)
代碼如下:
void add_host(u_long ip, u_char * mac)
{
HOST * new = NULL;
HOST * cur = NULL;
if( (ip == MYIP) || (mac && mac_equal(mac, MYMAC)) )
return;
//遍歷鏈表查詢IP地址
for(cur = head; cur; cur = cur->next)
{
if( ip == cur->ip )
{
if( mac ) // MAC地址不空,則寫入
{
memcpy(cur->mac, mac, ETHER_ADDR_LEN);
cur->mac_flag = 1;
}
return;
}
}
if(cur == NULL) // 鏈表中沒有此IP地址
{
new = (HOST *)malloc(sizeof(HOST));
new->ip = ip;
if( mac )
{
memcpy(new->mac, mac, ETHER_ADDR_LEN);
new->mac_flag = 1;
}
else
new->mac_flag = 0;
new->next = NULL;
if(! head) // 把新節點加入鏈表
{
head = new;
tail = new;
}
else
{
tail->next = new;
tail = new;
}
}
return;
}
周期性的向局域網中每一臺主機發送ARP欺騙包。
創建一個發送ARP欺騙包的函數send_fake_arp_packet(),遍歷主機鏈表的每一個IP地址,如果此IP地址的MAC地址已知,則遍歷主機鏈表中其它IP地址,以其它IP地址和本機的MAC地址為發送端,以選中的IP地址和MAC地址為目的端,構造并發送ARP應答欺騙包;如果此IP地址的MAC地址未知,則以本機IP地址和MAC地址為發送端,以選中的IP地址為目的端,構造并發送正常的ARP請求包。注意,這是我們收集網絡拓樸結構的一種主動方法。
【編輯推薦】