百科解釋
嗅探 sniff。嗅探器可以竊聽網(wǎng)絡(luò)上流經(jīng)的數(shù)據(jù)包。
用集線器hub組建的網(wǎng)絡(luò)是基于共享的原理的,
局域網(wǎng)內(nèi)所有的計算機(jī)都接收相同的數(shù)據(jù)包,
而網(wǎng)卡構(gòu)造了硬件的“過濾器“
通過識別MAC地址過濾掉和自己無關(guān)的信息,
嗅探程序只需關(guān)閉這個過濾器,
將網(wǎng)卡設(shè)置為“混雜模式“就可以進(jìn)行嗅探
用交換機(jī)switch組建的網(wǎng)絡(luò)是基于“交換“原理的
,交換機(jī)不是把數(shù)據(jù)包發(fā)到所有的端口上,
而是發(fā)到目的網(wǎng)卡所在的端口。
這樣嗅探起來會麻煩一些,嗅探程序一般利用“ARP欺騙“的方法
,通過改變MAC地址等手段,欺騙交換機(jī)將數(shù)據(jù)包發(fā)給自己,
嗅探分析完畢再轉(zhuǎn)發(fā)出去
一 前言
SNIFF真是一個古老的話題,關(guān)于在網(wǎng)絡(luò)上采用SNIFF來獲取敏感信息已經(jīng)不是什么新鮮事,也不乏很多成功的案例,那么,SNIFF究竟是什么呢?SNIFF就是嗅探器,就是竊聽器,SNIFF靜悄悄的工作在網(wǎng)絡(luò)的底層,把你的秘密全部記錄下來。看過威爾史密斯演的《全民公敵》嗎?SNIFF就象里面精巧的竊聽器一樣,讓你防不勝防。
SNIFF可以是軟件,也可以是硬件,既然是軟件那就要分平臺,有WINDOWS下的、UNXI下的等,硬件的SNIFF稱為網(wǎng)絡(luò)分析儀,反正不管硬件軟件,目標(biāo)只有一個,就是獲取在網(wǎng)絡(luò)上傳輸?shù)母鞣N信息。本文僅僅介紹軟件的SNIFF。
當(dāng)你舒適的坐在家里,愜意的享受網(wǎng)絡(luò)給你帶來的便利,收取你的EMAIL,購買你喜歡的物品的時候,你是否會想到你的朋友給你的信件,你的信用卡帳號變成了一個又一個的信息包在網(wǎng)絡(luò)上不停的傳送著,你是否曾經(jīng)這些信息包會通過網(wǎng)絡(luò)流入別人的機(jī)器呢?你的擔(dān)憂不是沒有道理的,因為SNIFF可以讓你的擔(dān)憂變成實實在在的危險。就好像一個人躲在你身后偷看一樣。。。。。。
二 網(wǎng)絡(luò)基礎(chǔ)知識
“網(wǎng)絡(luò)基礎(chǔ)知識”,是不是聽起來有點跑題了?雖然聽起來這和我們要談的SNIFF沒什么關(guān)系,可是還是要說一說的,萬丈高樓平地起,如果連地基都沒打好,怎么蓋樓?!如果你對網(wǎng)絡(luò)還不是十分清楚的話,最好能靜下心來好好看看,要知道,這是基礎(chǔ)的基礎(chǔ),在這里我只是簡單的說一下,免得到時候有人迷糊,詳細(xì)的最好能夠自己去找書看看。
。1)TCP/IP體系結(jié)構(gòu)
開放系統(tǒng)互連(OSI)模型將網(wǎng)絡(luò)劃分為七層模型,分別用以在各層上實現(xiàn)不同的功能,這七層分別為:應(yīng)用層、表示層、會話層、傳輸層、網(wǎng)絡(luò)層、數(shù)據(jù)鏈路層及物理層。而TCP/IP體系也同樣遵循這七層標(biāo)準(zhǔn),只不過在某些OSI功能上進(jìn)行了壓縮,將表示層及會話層合并入應(yīng)用層中,所以實際上我們打交道的TCP/IP僅僅有5層而已,網(wǎng)絡(luò)上的分層結(jié)構(gòu)決定了在各層上的協(xié)議分布及功能實現(xiàn),從而決定了各層上網(wǎng)絡(luò)設(shè)備的使用。實際上很多成功的系統(tǒng)都是基于OSI模型的,如:如幀中繼、ATM、ISDN等。
TCP/IP的網(wǎng)絡(luò)體系結(jié)構(gòu)(部分)
從上面的圖中我們可以看出,第一層物理層和第二層數(shù)據(jù)鏈路層是TCP/IP的基礎(chǔ),而TCP/IP本身并不十分關(guān)心低層,因為處在數(shù)據(jù)鏈路層的網(wǎng)絡(luò)設(shè)備驅(qū)動程序?qū)⑸蠈拥膮f(xié)議和實際的物理接口隔離開來。網(wǎng)絡(luò)設(shè)備驅(qū)動程序位于介質(zhì)訪問子層(MAC)。2)網(wǎng)絡(luò)上的設(shè)備 中繼器:中繼器的主要功能是終結(jié)一個網(wǎng)段的信號并在另一個網(wǎng)段再生該信號,一句話,就是簡單的放大而已,工作在物理層上!
網(wǎng) 橋:網(wǎng)橋使用MAC物理地址實現(xiàn)中繼功能,可以用來分隔網(wǎng)段或連接部分異種網(wǎng)絡(luò),工作在數(shù)據(jù)鏈路層。
路由器:路由器使用網(wǎng)絡(luò)層地址(IP,X.121,E.164等),主要負(fù)責(zé)數(shù)據(jù)包的路由尋徑,也能處理物理層和數(shù)據(jù)鏈路層上的工作。
網(wǎng) 關(guān):主要工作在網(wǎng)絡(luò)第四層以上,主要實現(xiàn)收斂功能及協(xié)議轉(zhuǎn)換,不過很多時候網(wǎng)關(guān)都被用來描述任何網(wǎng)絡(luò)互連設(shè)備。
。3)TCP/IP與以太網(wǎng)
以太網(wǎng)和TCP/IP可以說是相互相成的,可以說兩者的關(guān)系幾乎是密不可分,以太網(wǎng)在一二層提供物理上的連線,而TCP/IP工作在上層,使用32位的IP地址,以太網(wǎng)則使用48位的MAC地址,兩者間使用ARP和RARP協(xié)議進(jìn)行相互轉(zhuǎn)換。從我們上面TCP/IP的模型圖中可以清楚的看到兩者的關(guān)系。
載波監(jiān)聽/沖突檢測(CSMA/CD)技術(shù)被普遍的使用在以太網(wǎng)中,所謂載波監(jiān)聽是指在以太網(wǎng)中的每個站點都具有同等的權(quán)利,在傳輸自己的數(shù)據(jù)時,首先監(jiān)聽信道是否空閑,如果空閑,就傳輸自己的數(shù)據(jù),如果信道被占用,就等待信道空閑。而沖突檢測則是為了防止發(fā)生兩個站點同時監(jiān)測到網(wǎng)絡(luò)沒有被使用時而產(chǎn)生沖突。以太網(wǎng)采用廣播機(jī)制,所有與網(wǎng)絡(luò)連接的工作站都可以看到網(wǎng)絡(luò)上傳遞的數(shù)據(jù)。
為了加深你的理解,我們來看看下面的圖,一個典型的在以太網(wǎng)中客戶與服務(wù)器使用TCP/IP協(xié)議的通信
以太網(wǎng)
唆唆了這么多,有人煩了吧?相信我,這是基礎(chǔ)的基礎(chǔ),可以說是說得是很簡單拉,如果需要,拿出個幾十萬字來說上面的內(nèi)容,我想也不嫌多,好了,讓我們進(jìn)入下一節(jié),sniff的原理。
三 SNIFF的原理
要知道在以太網(wǎng)中,所有的通訊都是廣播的,也就是說通常在同一個網(wǎng)段的所有網(wǎng)絡(luò)接口都可以訪問在物理媒體上傳輸?shù)乃袛?shù)據(jù),而每一個網(wǎng)絡(luò)接口都有一個唯一的硬件地址,這個硬件地址也就是網(wǎng)卡的MAC地址,大多數(shù)系統(tǒng)使用48比特的地址,這個地址用來表示網(wǎng)絡(luò)中的每一個設(shè)備,一般來說每一塊網(wǎng)卡上的MFC地址都是不同的,每個網(wǎng)卡廠家得到一段地址,然后用這段地址分配給其生產(chǎn)的每個網(wǎng)卡一個地址。在硬件地址和IP地址間使用ARP和RARP協(xié)議進(jìn)行相互轉(zhuǎn)換。
在正常的情況下,一個網(wǎng)絡(luò)接口應(yīng)該只響應(yīng)這樣的兩種數(shù)據(jù)幀:
1.與自己硬件地址相匹配的數(shù)據(jù)幀!2.發(fā)向所有機(jī)器的廣播數(shù)據(jù)幀。
在一個實際的系統(tǒng)中,數(shù)據(jù)的收發(fā)是由網(wǎng)卡來完成的,網(wǎng)卡接收到傳輸來的數(shù)據(jù),網(wǎng)卡內(nèi)的單片程序接收數(shù)據(jù)幀的目的MAC地址,根據(jù)計算機(jī)上的網(wǎng)卡驅(qū)動程序設(shè)置的接收模式判斷該不該接收,認(rèn)為該接收就接收后產(chǎn)生中斷信號通知CPU,認(rèn)為不該接收就丟掉不管,所以不該接收的數(shù)據(jù)網(wǎng)卡就截斷了,計算機(jī)根本就不知道。CPU得到中斷信號產(chǎn)生中斷,操作系統(tǒng)就根據(jù)網(wǎng)卡的驅(qū)動程序設(shè)置的網(wǎng)卡中斷程序地址調(diào)用驅(qū)動程序接收數(shù)據(jù),驅(qū)動程序接收數(shù)據(jù)后放入信號堆棧讓操作系統(tǒng)處理。而對于網(wǎng)卡來說一般有四種接收模式:
廣播方式:該模式下的網(wǎng)卡能夠接收網(wǎng)絡(luò)中的廣播信息!〗M播方式:設(shè)置在該模式下的網(wǎng)卡能夠接收組播數(shù)據(jù)。
直接方式:在這種模式下,只有目的網(wǎng)卡才能接收該數(shù)據(jù);祀s模式:在這種模式下的網(wǎng)卡能夠接收一切通過它的數(shù)據(jù),而不管該數(shù)據(jù)是否是傳給它的。
好了,現(xiàn)在我們總結(jié)一下,首先,我們知道了在以太網(wǎng)中是基于廣播方式傳送數(shù)據(jù)的,也就是說,所有的物理信號都要經(jīng)過我的機(jī)器,再次,網(wǎng)卡可以置于一種模式叫混雜模式(promiscuous),在這種模式下工作的網(wǎng)卡能夠接收到一切通過它的數(shù)據(jù),而不管實際上數(shù)據(jù)的目的地址是不是他。這實際上就是我們SNIFF工作的基本原理:讓網(wǎng)卡接收一切他所能接收的數(shù)據(jù)。
我們來看一個簡單的例子,如圖一所示,機(jī)器A、B、C與集線器HUB相連接,集線器HUB通過路由器Router訪問外部網(wǎng)絡(luò)。這是一個很簡單也很常見的情況,比如說在公司大樓里,我所在的網(wǎng)絡(luò)部辦公室里的幾臺機(jī)器通過集線器連接,而網(wǎng)絡(luò)部、開發(fā)部、市場部也是同樣如此,幾個部門的集線器通過路由器連接。還是回到我們的圖一上來,值得注意的一點是機(jī)器A、B、C使用一個普通的HUB連接的,不是用SWITCH,也不是用ROUTER,使用SWITCH和ROUTER的情況要比這復(fù)雜得多。
我們假設(shè)一下機(jī)器A上的管理員為了維護(hù)機(jī)器C,使用了一個FTP命令向機(jī)器C進(jìn)行遠(yuǎn)程登陸,那么在這個用HUB連接的網(wǎng)絡(luò)里數(shù)據(jù)走向過程是這樣的。首先機(jī)器A上的管理員輸入的登陸機(jī)器C的FTP口令經(jīng)過應(yīng)用層FTP協(xié)議、傳輸層TCP協(xié)議、網(wǎng)絡(luò)層IP協(xié)議、數(shù)據(jù)鏈路層上的以太網(wǎng)驅(qū)動程序一層一層的包裹,最后送到了物理層,我們的網(wǎng)線上。接下來數(shù)據(jù)幀送到了HUB上,現(xiàn)在由HUB向每一個接點廣播由機(jī)器A發(fā)出的數(shù)據(jù)幀,機(jī)器B接收到由HUB廣播發(fā)出的數(shù)據(jù)幀,并檢查在數(shù)據(jù)幀中的地址是否和自己的地址相匹配,發(fā)現(xiàn)不是發(fā)向自己的后把這數(shù)據(jù)幀丟棄,不予理睬。而機(jī)器C也接收到了數(shù)據(jù)幀,并在比較之后發(fā)現(xiàn)是發(fā)現(xiàn)自己的,接下來他就對這數(shù)據(jù)幀進(jìn)行分析處理。
在上面這個簡單的例子中,機(jī)器B上的管理員如果很好奇,他很想知道究竟登陸機(jī)器C上FTP口令是什么?那么他要做的很簡單,僅僅需要把自己機(jī)器上的網(wǎng)卡置于混雜模式,并對接收到的數(shù)據(jù)幀進(jìn)行分析,從而找到包含在數(shù)據(jù)幀中的口令信息。
四 做一個自己的sniff
在上一節(jié)里,我們已經(jīng)知道了SNIFF的基本原理是怎么一回事,這一節(jié)我們來親自動手做一個自己的sniff,畢竟,用程序代碼來說話比什么都要來得真實,也容易加深理解。
回頭想一想我們上面說的原理,我們要做的事情有幾件:
1. 把網(wǎng)卡置于混雜模式! 2. 捕獲數(shù)據(jù)包! 3.分析數(shù)據(jù)包。
注:下面的源代碼取至Chad Renfro的<< Basic Packet-SnifferConstruction from the Ground Up>>一文中
/************************Tcp_sniff_2.c********************/
1.#include
2.#include
3.#include
4.#include
5.#include
6.#include
7.#include
8.#include
9.#include "headers.h"
#define INTERFACE "eth0"
/*Prototype area*/
10.int Open_Raw_Socket(void);
11.int Set_Promisc(char *interface, intsock);
12.int main() {
13.int sock, bytes_recieved, fromlen;
14.char buffer[65535];
15.struct sockaddr_in from;
16.struct ip *ip;
17.struct tcp *tcp;
18.sock = Open_Raw_Socket();
19. Set_Promisc(INTERFACE, sock);
20. while(1)
22. {
23. fromlen = sizeof from;
24. bytes_recieved = recvfrom(sock, buffer, sizeofbuffer, 0, (struct sockaddr *)&from, &fromlen);
25. printf("
Bytes received :::%5d
",bytes_recieved);
26. printf("Source address :::%s
",inet_ntoa(from.sin_addr));
27. ip = (struct ip *)buffer;
/*See if this is a TCP packet*/
28. if(ip->ip_protocol == 6) {
29. printf("IP header length :::%d
",ip->ip_length);
30. printf("Protocol :::%d
",ip->ip_protocol);
31. tcp = (struct tcp *)(buffer +(4*ip->ip_length));
32. printf("Source port :::%d
",ntohs(tcp->tcp_source_port));
33. printf("Dest port :::%d
",ntohs(tcp->tcp_dest_port));
34. }
35. }
36.}
37.int Open_Raw_Socket() {
38. int sock;
39. if((sock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) < 0){
/*Then the socket was not created properly and must die*/
40. perror("The raw socket was not created");
41. exit(0);
42. };
43. return(sock);
44. }
45.int Set_Promisc(char *interface, int sock ) {
46. struct ifreq ifr;
47. strncpy(ifr.ifr_name, interface,strnlen(interface)+1);
48. if((ioctl(sock, SIOCGIFFLAGS, &ifr) == -1)) {
/*Could not retrieve flags for the interface*/
49. perror("Could not retrive flags for the interface");
50. exit(0);
51. }
52. printf("The interface is ::: %s
", interface);
53. perror("Retrieved flags from interface successfully");
54. ifr.ifr_flags |= IFF_PROMISC;
55. if (ioctl (sock, SIOCSIFFLAGS, &ifr) == -1 ) {
/*Could not set the flags on the interface */
56. perror("Could not set the PROMISC flag:");
57. exit(0);
58. }
59. printf("Setting interface ::: %s ::: to promisc",interface);
60. return(0);
61. }
/***********************EOF**********************************/
上面這段程序中有很詳細(xì)的注解,不過我想還是有必要說一說,首先第10行--intOpen_Raw_Socket(void); 是我們的自定義函數(shù),具體內(nèi)容如下:
37.int Open_Raw_Socket() {
38. int sock;
39. if((sock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) < 0){
/*Then the socket was not created properly and must die*/
40. perror("The raw socket was not created");
41. exit(0);
42. };
43. return(sock);
44. }
第39行 if((sock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) < 0) {
這里我們調(diào)用了socket函數(shù),使創(chuàng)建了了一個原始套接口,使之收到TCP/IP信息包。
接下來第11行-int Set_Promisc(char *interface, intsock),這也是我們的自定義函數(shù),目的是把網(wǎng)卡置于混雜模式,具體內(nèi)容如下:
45.int Set_Promisc(char *interface, int sock ) {
46. struct ifreq ifr;
47. strncpy(ifr.ifr_name, interface,strnlen(interface)+1);
48. if((ioctl(sock, SIOCGIFFLAGS, &ifr) == -1)) {
/*Could not retrieve flags for the interface*/
49. perror("Could not retrive flags for the interface");
50. exit(0);
51. }
52. printf("The interface is ::: %s
", interface);
53. perror("Retrieved flags from interface successfully");
54. ifr.ifr_flags |= IFF_PROMISC;
55. if (ioctl (sock, SIOCSIFFLAGS, &ifr) == -1 ) {
/*Could not set the flags on the interface */
56. perror("Could not set the PROMISC flag:");
57. exit(0);
58. }
59. printf("Setting interface ::: %s ::: to promisc",interface);
60. return(0);
61. }
首先 struct ifreq ifr; 定一了一個ifrreg的結(jié)構(gòu)ifr,接下來strncpy(ifr.ifr_name,interface,strnlen(interface)+1);,就是把我們網(wǎng)絡(luò)設(shè)備的名字填充到ifr結(jié)構(gòu)中,在這里#define INTERFACE "eth0" ,讓我們再往下看,ioctl(sock, SIOCGIFFLAGS,&ifr),SIOCGIFFLAGS請求表示需要獲取接口標(biāo)志,現(xiàn)在到了第54行,在我們成功的獲取接口標(biāo)志后把他設(shè)置成混雜模式,ifr.ifr_flags|= IFF_PROMISC;ioctl (sock, SIOCSIFFLAGS,&ifr)。OK,現(xiàn)在我們所說的第一步已經(jīng)完成--------把網(wǎng)卡置于混雜模式。
現(xiàn)在進(jìn)入第二步,捕獲數(shù)據(jù)包。從第20行開始,我們進(jìn)入了一個死循環(huán),while(1),在第24行,recvfrom(sock,buffer, sizeof buffer, 0, (struct sockaddr *)&from,&fromlen),這個函數(shù)要做的就是接收數(shù)據(jù),冰把接收到的數(shù)據(jù)放入buffer中。就是這么簡單,已經(jīng)完成了我們要捕獲數(shù)據(jù)包的任務(wù)。
到了第三步,分析數(shù)據(jù)包。27行,ip = (struct ip*)buffer,使我們在頭文件中的IP結(jié)構(gòu)對應(yīng)于所接收到的數(shù)據(jù),接下來判斷在網(wǎng)絡(luò)層中是否使用的是TCP協(xié)議,if(ip->ip_protocol== 6) ,如果答案是,tcp信息包從整個IP/TCP包 buffer +(4*ip->ip_length) 地址處開始,所以31行 tcp = (struct tcp*)(buffer +(4*ip->ip_length)),然后對應(yīng)結(jié)構(gòu)把你所需要的信息輸出。
/*************************headers.h**************************/
/*structure of an ip header*/
struct ip {
unsigned int ip_length:4; /*little-endian*/
unsigned int ip_version:4;
unsigned char ip_tos;
unsigned short ip_total_length;
unsigned short ip_id;
unsigned short ip_flags;
unsigned char ip_ttl;
unsigned char ip_protocol;
unsigned short ip_cksum;
unsigned int ip_source; unsigned int ip_dest;
};
/* Structure of a TCP header */
struct tcp {
unsigned short tcp_source_port;
unsigned short tcp_dest_port;
unsigned int tcp_seqno;
unsigned int tcp_ackno;
unsigned int tcp_res1:4, /*little-endian*/
tcp_hlen:4,
tcp_fin:1,
tcp_syn:1,
tcp_rst:1,
tcp_psh:1,
tcp_ack:1,
tcp_urg:1,
tcp_res2:2;
unsigned short tcp_winsize;
unsigned short tcp_cksum;
unsigned short tcp_urgent;
};
/*********************EOF***********************************/
從上面的分析我們可以清楚的認(rèn)識到,認(rèn)識一個SNIFF需要對TCP/IP協(xié)議有著詳細(xì)的了解,否則你根本無法找到你需要的信息。有了上面的基礎(chǔ),你可以自己來做一個你需要的SNIFF了。