2012年2月6日 星期一

sniffer技術原理及應用,包括程式設計方法和工具使用


sniffer在性能測試中經常用到,特別對於不確定的問題,可以分析到協議提交過程中的問題,所以給大家看一下

sniffer中文翻譯過來就是嗅探器,在當前網路技術中使用得非常得廣泛。sniffer既可以做為網路故障的診斷工具,也可以作為駭客嗅探和監聽的工具。最近兩年,網路監聽(sniffer)技術出現了新的重要特徵。傳統的sniffer技術是被動地監聽網路通信、用戶名和口令。而新的sniffer技術出現了主動地控制通信資料的特點,把sniffer技術擴展到了一個新的領域。Sniffer技術除了目前在傳統的網路偵測管理外,也開始被應用在資訊保全的領域。可以這樣說,sniffer技術是一把雙刃劍,如何更好的利用它,瞭解它的一些特性,將能使這項技術更好的為我們帶來便利。

sniffer的程式設計方法比較通用的有以下幾種,1.winpcap 這是一個比較通用的庫,相信做過抓包的工具大多數人都不會太陌生 2.raw socket 2000以後的版本都支援此項功能,2000 server有個網路監視器就是基於raw socket . tdi,ndis,spi,hook socket技術,這種技術比較大的不同是可以將包截取而不是僅僅獲得包的一份拷貝。總的說來,一般以前兩者居多。我這裡提的都還比較片面,更多的需要大家來補充。我辦這個專題的目的是希望大家共同來瞭解,討論sniffer技術,讓更多的人參與進來,讓大家知道,這個板塊能夠給大家帶來真正想要的東西。

warton:
libpcap是個好東西,linux,windows下都能用,很多入侵偵測之類的安全系統都是以這為核心。不過我一直沒用過它,不知道它的跨平臺性如何?要用spi的話,看看xfilter的代碼和書,特別是那本書上講得不錯,可惜一直沒用它做出什麼東西來。raw socket寫的sniffer比較多,網上代碼也很多!
昨天見csdn首頁有幾篇關於sniffer的文章,保存了,還沒來得及看...
俺明天來說說目前常用的sniffer類工具和它們的技術實現!

csdn首頁的兩篇文章,大家可以看看,裡面好像還有幾篇,暫時找不到了
http://www.csdn.net/develop/article/21/21363.shtm
http://www.csdn.net/develop/article/21/21352.shtm
http://www.csdn.net/develop/article/15/15919.shtm

netsys2:

一)winpcap驅動簡介
  winpcap(windows packet capture)windows平臺下一個免費,公共的網路訪問系統。開發winpcap這個專案的目的在於為win32應用程式提供訪問網路底層的能力。它提供了以下的各項

功能:
  1> 捕獲原始資料包,包括在共用網路上各主機發送/接收的以及相互之間交換的資料包;
  2> 在資料包發往應用程式之前,按照自訂的規則將某些特殊的資料包過濾掉;
  3> 在網路上發送原始的資料包;
  4> 收集網路通信過程中的統計資訊。

winpcap的主要功能在於獨立於主機協議(如TCP-IP)而發送和接收原始資料包。也就是說,winpcap不能阻塞,過濾或控制其他應用程式資料包的發收,它僅僅只是監聽共用網路上傳送的資料包。因此,它不能用於QoS調度程式或個人防火牆。

  目前,winpcap開發的主要對象是windows NT/2000/XP,這主要是因為在使用winpcap的使用者中只有一小部分是僅使用windows 95/98/Me,並且M$也已經放棄了對win9x的開發。因此本文相關的程式T-ARP也是面向NT/2000/XP用戶的。其實winpcap中的面向9x系統的概念和NT系統的非常相似,只是在某些實現上有點差異,比如說9x只支援ANSI編碼,而NT系統則提倡使用Unicode編碼。

zzhong2:
有個軟體叫sniffer pro.可以作網管軟體用,有很多功能,可監視網路運行情況,每台網內機器的資料流量,即時反映每台機器所訪問IP以及它們之間的資料流程通情況,可以抓包,可對篩檢程式進行設置,以便只抓取想要的包,比如POP3,smtp,ftp包等,並可從中找到郵箱用戶名和密碼,還有ftp用戶名和密碼.它還可以在使用交換機的網路上監聽,不過要在交換機上裝它的一個軟體.還有一個簡單的監聽軟體叫 Passwordsniffer,可截獲郵箱用戶名和密碼,還有ftp用戶名和密碼,它只能用在用HUB網路上以上兩個軟體都可在小鳳居上下載到:http://www.chinesehack.org/


warton:
libpcap的最新版本是0.7.2,下載很多(基於linux/unixwinpcap的最新版本是3.0這裡有winpcap的原始程式碼:http://download.pchome.net/php/dl.php?sid=11474
著名軟體tcpdumpids snort都是基於libpcap編寫的,此外Nmap掃描器也是基於libpcap來捕獲目標主機返回的資料包的。

winpcap提供給使用者兩個不同級別的程式設計介面:一個基於libpcapwpcap.dl,另一個是較底層的packet.dll。對於一般的要與unix平臺上libpcap相容的開發來說,使用pacap.dll是當然的選擇。下面幾個庫是與lipcap相關的:
libnet1.0.2:資料包的發送個構造過程
libnids:實現了ids的一些 框架
libicmpicmp資料包處理


一些著名的嗅探器:
tcpdump/windump:支持多種unix,後者支持windows。基於libpcap Sniffit:unix,windows,libpcap
Ngrep:libpcap,unixwindows.可以用規則運算式,識別PPP,SLIPFDDI數據包
Snifferpro/NetXray:專業的協議分析工具,是NAI提供的網路分析方案中的一部分
其它:
Iris
LanExplorer
NetMOnitor
CommView

單一用途的噢探器
口令嗅:winsniffer,典型的駭客工具,嗅探並解析ftp,pop3,http,icq,smtp,telnet,IMAP,NNTP

等口令
password sniffer for NetHackerIII

專用 嗅探器:
SMB嗅探器:L0phtcrackSMPRelay
TCP連接會話嗅探器:CommView ,Iris,Juggernaut
SSL嗅探器:SSLDump--sslv3/tls網路協議分析工具
RIDIUS嗅控器:一個基於udp的論證記帳協議,Radiusniff是其代表
PPTP嗅 控器:Anger,PPTP-sniff(solaris)
SNMP嗅探器:Snmpsniff

切換式網路嗅探器:Ettercap
綜合:Dsniff
其它切換式網路嗅探器:
snarp,parasite

嗅探對策.........

netsys2:

網路上流傳的GUNIFFER是個基本的原型:

http://asp.6to23.com/nowcan/code/guniffer.zip

void main(int argc, char ** argv)

{

int iErrorCode;

char RecvBuf[MAX_PACK_LEN] = {0};

usage();

if(GetCmdLine(argc, argv)==CMD_PARAM_HELP) exit(0);

//初始化SOCKET

WSADATA wsaData;

iErrorCode = WSAStartup(MAKEWORD(2,1),&wsaData);

CheckSockError(iErrorCode, "WSAStartup");

SockRaw = socket(AF_INET , SOCK_RAW , IPPROTO_IP);

CheckSockError(SockRaw, "socket");

//獲取本機IP地址

char FAR name[MAX_HOSTNAME_LAN];

iErrorCode = gethostname(name, MAX_HOSTNAME_LAN);

CheckSockError(iErrorCode, "gethostname");

struct hostent FAR * pHostent; //注意下面這三句,這裡先對pHostent分配了一塊

pHostent = (struct hostent * )malloc(sizeof(struct hostent));

//記憶體,然後有讓它等於gethostbyname函數的返回

pHostent = gethostbyname(name); //值,但gethostbyname函數是自己在函數內部分配內

存的,因此上一句根本就是多餘,把上一句刪除後一切正常。但此程式用VC6編譯運行都沒有問題

,不知為何?也許是VC6的編譯器優化在起作用。

SOCKADDR_IN sa;

sa.sin_family = AF_INET;

sa.sin_port = htons(6000);

memcpy(&sa.sin_addr.S_un.S_addr, pHostent->h_addr_list[0], pHostent->h_length);

free(pHostent); //由於前面分配記憶體的語句已經刪除,所以這一句也要去掉,否則出錯。感謝網

Heyuming 發現這個問題。

iErrorCode = bind(SockRaw, (PSOCKADDR)&sa, sizeof(sa));

CheckSockError(iErrorCode, "bind");

//設置SOCK_RAWSIO_RCVALL,以便接收所有的IP

DWORD dwBufferLen[10] ;

DWORD dwBufferInLen = 1 ;

DWORD dwBytesReturned = 0 ;

iErrorCode=WSAIoctl(SockRaw, SIO_RCVALL,&dwBufferInLen,

sizeof(dwBufferInLen),

&dwBufferLen, sizeof(dwBufferLen),&dwBytesReturned , NULL , NULL );

CheckSockError(iErrorCode, "Ioctl");

//偵聽IP報文

while(1)

{

memset(RecvBuf, 0, sizeof(RecvBuf));

iErrorCode = recv(SockRaw, RecvBuf, sizeof(RecvBuf), 0);

CheckSockError(iErrorCode, "recv");

iErrorCode = DecodeIpPack(RecvBuf, iErrorCode);

CheckSockError(iErrorCode, "Decode");

}

}

它有2個不方便之處:
1)不能選擇網卡
2)採用閉環方式讀數據,改編到WINDOWS視窗模式下時有死機的感覺。

sevencat():
上次找了一些資料整理了一下,不過人氣不旺,而且最近比較忙,暫時還沒繼續下去。
http://expert.csdn.net/Expert/topic/2299/2299615.xml?temp=.2761499
WINDOWS網路包過濾技術
                    (原文:http://www.ndis.com/papers/winpktfilter.htm
一、user-mode網路包過濾
1winsock分層service provider
參照Microsoft Platform SDK上有關文檔和例子
http://www.microsoft.com/msdownload/platformsdk/sdkupdate/
這裡有好幾個microsoft lsp 例子,最新(可能最bug-free)的經常在這裡能找到。需要知道的是

可以通過TDI調用核心TCPIP驅動,而且可以完全繞開WINSOCK,在大多數情況下這不是一個問

題。例如:QOS的實現可以在WINSOCK LSP上。
然而,這樣做的話,程式必須察看和操作每個包,而不能依靠WINSOCK LSP,他們要以一種接

近核心態的方法來實現。
2win2000包過濾介面
  WIN2000包過濾介面提供了一種機制,這種機制允許使用者態程式或者服務指定一系列的"過濾

原則",這些過濾原則會被低層的TCPIP實現用來過濾包。這種過濾工主要是對IP原位址、目標位址、埠號(或者埠號範圍)進行pass或者drop操作。
Windows Developer's Journal
《用iphlpapi.dll進行包過濾》作者:Ton plooyOctober,2000,Volume 11, Number 10
  WIN2000提供了一個較好對TCPIP的可程式設計控制,其中包括包過濾。不幸的是,有關這個新

API的文檔並不是很容易能找到。這篇文章向你演示了怎樣對特定IP位址或者特定TCP埠的包

進行阻塞的程式設計。
連結:www.wdj.com
上面這個例子的下載:ftp://ftp.wdj.com/pub/webzip/1110/plooy.zip
Hollis 的解決方案:
  HTS W2K IpHook例子演示了IP過濾和它的HOOK API,包含原文件,而且是免費的,

需要HtsCpp運行時庫(免費),下載位址:http://www.hollistech.com/
3winsock替代DLL
  在使用WINSOCK LSP之前,唯一的辦法是用自己的DLL取代微軟的WINSOCK DLL,假

如實現順利的話,自己的DLL會接收用戶的WINSOCK調用請求,然後還可以調用原來的WINSOC

K DLL來處理。
  不過這樣的實現是比較費力的,其中有個困難就是微軟的WINSOCK DLL裡面經常有一些未

公開的內部使用的函數,一個WINSOCK代替DLL至少要處理其中的一些未公開函數。
  隨著WINDOWS系統結構的變化,有些方面得到了加強,比如系統檔案保護,這使得這種技術

變得不太可行。總的說來,使用WINSOCK DLL替換不是一個壞主意。(Xfilter就是用的這種技

術,原代碼可能在網上有流傳,我以前看到過的)
二、kernel-mode網路包過濾
1Transport Data Interface TDI
  這主要是一個直接在核心TCPIP驅動上面的一層過濾驅動。在WINXPTDI驅動是一種傳統的

NT風格的驅動,使用了基於IRPAPI,這裡有兩種方法來實現。
A、使用核心模式服務的IoAttachDeviceXYZ函數族在TDI上實現一個過濾。
B、對TDI驅動IRP DISPATCH表進行過濾。
  IoAttachDeviceXYZ函數在許多WINNT驅動開發的書上提到。這兩種技術都需要對WINNT

動開發程式設計技術十分瞭解,對TDI函數也要相當的瞭解。
2NDIS中間層(IM
具體請看NDIS IM FAQhttp://www.pcausa.com/resources/ndisimfaq.htm
3WIN2000 FILTERHOOK
  請參照有關DDK文檔,系統中只能有一個活動的Filter-Hook存在,這點使這種技術的使用有

嚴重的限制。(平時所見的drvipflt就是用的這個)
4WIN2000 FIREWALLHOOK 
  Firewall-Hook Driver函數在文檔裡介紹得很少,而且在有些win2000版本中不可用。請參

照微軟有關文檔:http://msdn.microsoft.com/library/default.asp?url=/library/en-us

/network/hh/network/firewall_3wfb.asp
5NDISHOOKING  (費爾防火牆就是用的這種技術吧,據我所知,雖然我沒看過原碼。)
NDIS-Hooking驅動攔截或者叫"HOOK"一些由NDIS封裝程式匯出的函數。雖然從實現手段上來

說有些不正規,但一個有系統的NDIS-Hooking過濾會非常有效。
另外:NDIS-Hooking過濾驅動有下麵的好處:
A、容易安裝(可以動態裝卸,不過有時候會出問題,裡面有些情況現在還未知。)
B、支持撥號-ppp適配器。
  Ndis-Hooking技術在98ME系統下非常有效和實用。在這些平臺上,DDK文檔和provide

d services都能很有用的幫你HOOKNdis wrapper匯出的函數。
  Ndis-Hooking技術在NT2000XP上同樣有效和實用。這種技術很像核心模式的調試器。

文檔支持較少,而且基本上不會被WHQL認證。
PCAUSA提供了一套NDIS PIM驅動例子,這些例子能在現有的WIN平臺上運行成功(從95X

P)。地址:http://www.pcausa.com/ndispim/Default.htm

其他:
Network操作和進程資訊:
  有許多人想知道網路上的操作和WIN進程(就是應用程式啦)之間怎樣聯繫起來,舉例來說,

可能會想知道是哪個進程在一個特定的IP埠上發送或接收資料。
  先不考慮這種技術是否有用,或者是否可靠,我們認為核心模式TCPIP驅動上層的過濾程式可

以處理這個問題。而TCPIP驅動下層的過濾程式根本看不到進程資訊。特別要注意的是有些網路服

務操作生成一個新的進程attach到系統進程上的。在這種情況下進程資訊並不能告訴我們原先是哪

個進程生成的。特別是單獨在核心模式下的WIN服務(TDI客戶)
  最後,有必要看看下面的資料United States Patent 5,987,611; "System and

methodology for managing internet access on a per application basis for client

computers connected to the internet "
  我們並不知道這項專利的價值,也不知道他是否能用在包過濾上。詳情請參閱:http://www.

uspto.gov/patft/index.html
www.pcausa.com

============================================
drvipflt具體解析,就是上面所提到的吧(23就是說的這東東)。
假定大家對驅動框架已經有了一定的理解。IRP分配程式如下:
NTSTATUS DrvDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
...
  switch (irpStack->MajorFunction)
  {
...
  case IRP_MJ_DEVICE_CONTROL:
    ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;

    switch (ioControlCode)
    {
  // ioctl code to start filtering
  //這裡可以從使用者模式程式發送這樣的請求。
  //直接用DeviceIoControl這個函數,就像下面這樣調用就可

以了吧,我想。


//DeviceIoControl(drivehandle,START_IP_HOOK,NULL,0,NULL,0,&bytereturned,NU

LL)
  case START_IP_HOOK:
  {
  //這個應該是最主要的函數了。
        SetFilterFunction(cbFilterFunction);

  break;
  }

  // ioctl to stop filtering
  case STOP_IP_HOOK:
  {
  SetFilterFunction(NULL);
      
  break;
  }

        // ioctl to add a filter rule
  case ADD_FILTER:
  {
  if(inputBufferLength == sizeof(IPFilter))
  {
  IPFilter *nf;

  nf = (IPFilter *)ioBuffer;

  AddFilterToList(nf);
  }

  break;
  }

  // ioctl to free filter rule list
  case CLEAR_FILTER:
  {
  ClearFilterList();

  break;
  }

  default:
  Irp->IoStatus.Status =

STATUS_INVALID_PARAMETER;


  break;
    }

    break;
...
}
SetFilterFunction(cbFilterFunction)可能是最重要的一個程式了。具體如下:
實際上這個做法相當在系統中註冊了一個回呼函數。
NTSTATUS SetFilterFunction(PacketFilterExtensionPtr filterFunction)
{
NTSTATUS status = STATUS_SUCCESS, waitStatus=STATUS_SUCCESS;
UNICODE_STRING filterName;
PDEVICE_OBJECT ipDeviceObject=NULL;
PFILE_OBJECT ipFileObject=NULL;

PF_SET_EXTENSION_HOOK_INFO filterData;

KEVENT event;
IO_STATUS_BLOCK ioStatus;
PIRP irp;

//首先獲得一個設備指標。
//first of all, we have to get a pointer to IpFilterDriver Device
RtlInitUnicodeString(&filterName, DD_IPFLTRDRVR_DEVICE_NAME);
status = IoGetDeviceObjectPointer(&filterName,STANDARD_RIGHTS_ALL,

&ipFileObject, &ipDeviceObject);
if(NT_SUCCESS(status))
{
//一些初始化工作,填充filterData
//initialize the struct with functions parameters
filterData.ExtensionPointer = filterFunction;

//we need initialize the event used later by the IpFilterDriver to

signal us
//when it finished its work
KeInitializeEvent(&event, NotificationEvent, FALSE);

//這個就是最重要的註冊回呼函數過程。DDK中具體講述是這樣的
//IOCTL_PF_SET_EXTENSION_POINTER registers filter-hook callback functions to

the IP filter driver
//to inform the IP filter driver to call those filter hook callbacks for every IP packet
//that is received or transmitted. Also, IOCTL_PF_SET_EXTENSION_POINTER

clears filter-hook
//callback functions from the IP filter driver. (看到了吧,最後一句話,註冊新的回呼函

數,就將原先的清除掉了,
//所以說系統中只存在一個這樣的驅動有用。)
//we build the irp needed to establish fitler function這個地方僅

僅是生成這樣的IRP,並沒有註冊
irp =

IoBuildDeviceIoControlRequest(IOCTL_PF_SET_EXTENSION_POINTER,
    

  ipDeviceObject,
    

(PVOID) &filterData,
    

sizeof(PF_SET_EXTENSION_HOOK_INFO),
    

NULL,
    

0,
    

FALSE,
    

&event,
    

&ioStatus);


if(irp != NULL)
{
  // we send the IRP
  //這個地方才是真正的註冊呀。
  status = IoCallDriver(ipDeviceObject, irp);

  //and finally, we wait for "acknowledge" of

IpDriverFilter
  if (status == STATUS_PENDING)
  {
  waitStatus = KeWaitForSingleObject(&event,

Executive, KernelMode, FALSE, NULL);

  if (waitStatus != STATUS_SUCCESS )

{}
  }

  status = ioStatus.Status;

  if(!NT_SUCCESS(status)){}
}

else
{
  //if we cant allocate the space, we return the

corresponding code error
  status = STATUS_INSUFFICIENT_RESOURCES;

}

if(ipFileObject != NULL)
  ObDereferenceObject(ipFileObject);

ipFileObject = NULL;
ipDeviceObject = NULL;
}

else

return status;
}
//真正的過濾函數是這個,在最早的IRPdispatch裡面傳遞的這個函數。
//這個函數就是系統傳遞了一個包頭和包內容和包長度之類的東西,你可以在裡面進行一些處理,
//假如你想讓這個包通過的話,就返回PF_FORWARD,或者你不想讓包通過的話,就返回PF_D

ROP就攔住了。是不是
//聽起來很簡單,
PF_FORWARD_ACTION cbFilterFunction(IN unsigned char *PacketHeader,IN

unsigned char *Packet, IN unsigned int PacketLength, IN unsigned int

RecvInterfaceIndex, IN unsigned int SendInterfaceIndex, IN unsigned long

RecvLinkNextHop, IN unsigned long SendLinkNextHop)
{
IPPacket *ipp;
TCPHeader *tcph;
UDPHeader *udph;

int countRule=0;

struct filterList *aux = first;

//we "extract" the ip Header
ipp=(IPPacket *)PacketHeader;

// dprintf("Source: %x\nDestination: %x\nProtocol: %d", ipp->ipSource,

ipp->ipDestination, ipp->ipProtocol);

//TCP-> protocol = 6
//we accept all packets of established connections
if(ipp->ipProtocol == 6)
{
tcph=(TCPHeader *)Packet;

// dprintf("FLAGS: %x\n", tcph->flags);

//if we havent the bit SYN activate, we pass the packets
if(!(tcph->flags & 0x02))
  return PF_FORWARD;
}

//otherwise, we compare the packet with our rules
while(aux != NULL)
{
// dprintf("Comparing with Rule %d", countRule);

//if protocol is the same....
if(aux->ipf.protocol == 0 || ipp->ipProtocol ==

aux->ipf.protocol)
{
  //we look in source Address
  if(aux->ipf.sourceIp != 0 && (ipp->ipSource &

aux->ipf.sourceMask) != aux->ipf.sourceIp)
  {
  aux=aux->next;

  countRule++;
  continue;
  }
    
  // we look in destination address
  if(aux->ipf.destinationIp != 0 && (ipp->ipDestination

& aux->ipf.destinationMask) != aux->ipf.destinationIp)
  {
  aux=aux->next;

  countRule++;
  continue;
  }

  //if we have a tcp packet, we look in ports
  //tcp, protocol = 6
  if(ipp->ipProtocol == 6)
  {
  if(aux->ipf.sourcePort == 0 ||

tcph->sourcePort == aux->ipf.sourcePort)
  {
  if(aux->ipf.destinationPort == 0

|| tcph->destinationPort == aux->ipf.destinationPort) //puerto tcp destino
  {
    //now we decided what

to do with the packet
    if(aux->ipf.drop)
    

return PF_DROP;
    else
  

return PF_FORWARD;
  }
  }
  }

  //udp, protocol = 17
  else if(ipp->ipProtocol == 17)
  {
  udph=(UDPHeader *)Packet;

  if(aux->ipf.sourcePort == 0 ||

udph->sourcePort == aux->ipf.sourcePort)
  {
  if(aux->ipf.destinationPort == 0

|| udph->destinationPort == aux->ipf.destinationPort)
  {
    //now we decided what

to do with the packet
    if(aux->ipf.drop)
    return

PF_DROP;
  
    else
    return

PF_FORWARD;
  }
  }
  }

  else
  {
  //for other packet we dont look more and

....
  //now we decided what to do with the

packet
  if(aux->ipf.drop)
  return PF_DROP;
  else
  return PF_FORWARD;
  }
}

//compare with the next rule
countRule++;
aux=aux->next;
}

//we accept all not registered
return PF_FORWARD;
}

winpcap也是用的NDIS,將自己註冊為一個協議處理驅動。(在原代碼的driverentry裡面能看到)

又:上面這個drvipflt這個代碼的過濾部分不知道大家是不是看起來很熟悉,是的,是抄的那個nu

mege的驅動開發包裡面的一個包過濾程式裡的,看來老外也是喜歡到處抄的。

ruike:
讀研的時候專門搞過nids,因此對winpcap可以說是情有獨鍾,這個東東確實好用,但也確實很煩

人,它有一個致命的缺陷就是只適用於共用式乙太網絡,對於交換式網路下的資料則無能為力,我

專門做過測試,在使用交換機連接的局域網下,只能監聽到本網段內的資料,而對於來自其他網段

的資料則無法監聽,除非你把probe接到交換機之前或者接到交換機的console口上,不過那樣的

弊端是顯而易見的。
所以,winpcap的應用還是很有局限性的!

kingzai:
實現切換式網路的嗅探也有不少方法的
1.將你的抓包程式放在閘道或代理伺服器上,這樣抓到整個局域網的包。
2.對交換機實行埠映射,將該埠的資料包全部映射到某個監控機器上。
3.在交換機和路由器之間連接一個HUB,這樣資料將以廣播的方式發送。
4.實行ARP欺騙,即在你的機器上實現整個包的轉發,不過會降低整個局域網的效率。

warton:
嗅探對策:
光說嗅探了,我說說反嗅探吧:)
1.檢查網內的主機上是否將網卡設置為混合模式(有很多工具可以做到,AntiSniff,Promiscan,S

entinel等)
2.EtterCap這樣的切換式網路嗅探器(進行ARP欺騙),可以採用防止ARP欺騙的方法來對待
3.SSH加密通道
4.SSL
5.VPN
6.PGP

目前這用利用網卡混合模式來進行sniffer的軟體看來作用不太大了,所以應該多考慮切換式網路的可

行辦法:

MAC Flooding,MAC Duplicating,ARP欺騙等等
這些方法實現起來就不怎麼容易了,歡迎有興趣的朋友提供相關的資料,呵呵!

netsys:
難道沒人用過RAW SOCKET 嗎?
雖然WINPCP功能很大,但RAW SOCKET可以讓你直接了SOCKET的原生機制。
實際上我提的那兩個問題是很容易解決的。。

netsys2:
對於一些混合模式的SNIFFER,大多採用發送特殊ARP包的方式,正確的網卡不會回應,而處於

混合模式的網卡則會回應。

當然,ARPIP處於同層,因此你不能用RAW SOCKET完成,你需WinPcap支援工作。

下面是部分代碼

AnsiString msgStatus;
extern TArpFuncParam wParams;

int BuildARPPacket(PArpPacket ArpPacket, unsigned char *dst_etheraddr,
  unsigned char *src_etheraddr, int ar_op, unsigned

char *ar_sha,
  unsigned char *ar_sip, unsigned char *ar_tha,
                unsigned char *ar_tip,unsigned short int ar_hw)
{
memcpy(&(ArpPacket->eth_dst_addr), dst_etheraddr, ETH_ADD_LEN);
memcpy(&(ArpPacket->eth_src_addr), src_etheraddr, ETH_ADD_LEN);
ArpPacket->eth_type = htons(ETH_TYPE_ARP);
ArpPacket->ar_hrd = htons(ar_hw);
ArpPacket->ar_pro = htons(ARP_PRO_IP);
ArpPacket->ar_hln = ARP_ETH_ADD_SPACE;
ArpPacket->ar_pln = ARP_IP_ADD_SPACE;
ArpPacket->ar_op = htons(ar_op);
memcpy(&(ArpPacket->ar_sha), ar_sha, ARP_ETH_ADD_SPACE);
memcpy(&(ArpPacket->ar_spa), ar_sip, ARP_IP_ADD_SPACE);
memcpy(&(ArpPacket->ar_tha), ar_tha, ARP_ETH_ADD_SPACE);
memcpy(&(ArpPacket->ar_tpa), ar_tip, ARP_IP_ADD_SPACE);
memset(ArpPacket->eth_pad, 32, ETH_PADDING_ARP);
return(EXIT_SUCCESS);
}
int OpenAdapter(LPADAPTER *lpAdapter)
{
*lpAdapter =

PacketOpenAdapter(wParams.AdapterList[wParams.SelectedAdapter]);

if(!(*lpAdapter) || ((*lpAdapter)->hFile == INVALID_HANDLE_VALUE))
{
  msgStatus = "Error : unable to open the driver.";
  SHOWSTAT(msgStatus);
  return(EXIT_FAILURE);
}
return(EXIT_SUCCESS);
}
void CloseAdapter(LPADAPTER lpAdapter)
{
PacketCloseAdapter(lpAdapter);

}
void GetLocalMAC(LPADAPTER lpAdapter, unsigned char *ether_addr)
{

ULONG IoCtlBufferLength = (sizeof(PACKET_OID_DATA) + sizeof(ULONG) - 1);
PPACKET_OID_DATA OidData;

OidData = (struct _PACKET_OID_DATA *)malloc(IoCtlBufferLength);
OidData->Oid = OID_802_3_CURRENT_ADDRESS;
OidData->Length = 6;
if(PacketRequest(lpAdapter, FALSE, OidData) == FALSE)
    memcpy(ether_addr, 0, 6);
else
    memcpy(ether_addr, OidData->Data, 6);
free(OidData);
}
int GetARPReply(LPPACKET lpPacket, unsigned char *iptarget, unsigned char

*result)
{
unsigned short int ether_type;
unsigned char     ipsender[4]; 
unsigned int     ?ff=0;
unsigned int     tlen;
struct bpf_hdr   *hdr;
char         *pChar;
char         *buf;

buf = (char *)lpPacket->Buffer;
hdr = (struct bpf_hdr *)(buf + off);
tlen = hdr->bh_caplen;
off += hdr->bh_hdrlen; 
pChar = (char*)(buf + off);
off = Packet_WORDALIGN(off + tlen);
memcpy(eer_type, pChar + 12, 2);
ether_type = ntohs(ether_type);
if(ether_type == ETH_TYPE_ARP)
{
  memcpy(ipsender, pChar + 28, 4);
  if((iptarget[0] == ipsender[0])&&(iptarget[1] == ipsender[1])&&
    (iptarget[2] == ipsender[2])&&(iptarget[3] == ipsender[3]))
    memcpy(result, pChar + 22, 6);
  else
    return(EXIT_FAILURE);
}
else
    return(EXIT_FAILURE);
return(EXIT_SUCCESS);
}
int CheckPROMode(LPADAPTER lpAdapter, unsigned char *iptarget, unsigned char

*remotemac)
{

LPPACKET lpPacketRequest;
LPPACKET lpPacketReply;
char   buffer[256000];

TArpPacket ArpPacket;
unsigned char magicpack[ETH_ADD_LEN]= {0xFF,0xFF,0xFF,0xFF,0xFF,0xFE};
unsigned char mactarget[ARP_ETH_ADD_SPACE];

DWORD timestamp = 0;
int numPacks = 0;
/* Init fields */
memset(mactarget, 0, 6);
/* Allocate PACKET structure for ARP Request packet */
if((lpPacketRequest = PacketAllocatePacket()) == NULL)
{
  msgStatus = "Error : failed to allocate the LPPACKET structure..";
  SHOWSTAT(msgStatus);
  return(EXIT_FAILURE);
}

/* Init packet structure */
memset(&ArpPacket, 0, sizeof(TArpPacket));

/* Build ARP Request packet */
BuildARPPacket(&ArpPacket, magicpack, wParams.srcMAC, ARP_OP_REQUEST,

wParams.srcMAC, wParams.srcIPAdd, mactarget, iptarget,wParams.ar_hw);

/* Init ARP Request packet */
PacketInitPacket(lpPacketRequest, &ArpPacket, sizeof(ArpPacket));

/* Set number of ARP Request packets to send */
if(PacketSetNumWrites(lpAdapter, 1) == FALSE)
{
  msgStatus = "Warning : unable to send more than one packet in a single write..";
  SHOWSTAT(msgStatus);
}
/* Set hardware filter to directed mode */
if(PacketSetHwFilter(lpAdapter, NDIS_PACKET_TYPE_DIRECTED) == FALSE)
{
  msgStatus ="Warning: unable to set directed mode..";
  SHOWSTAT(msgStatus);
}
/* Set a 512K buffer in the driver */
if(PacketSetBuff(lpAdapter, 512000) == FALSE)
{
  msgStatus = "Error: unable to set the kernel buffer..";
  SHOWSTAT(msgStatus);
  PacketFreePacket(lpPacketRequest);
  return(EXIT_FAILURE);
}
/* Set a 1 second read timeout */
if(PacketSetReadTimeout(lpAdapter, -1) == FALSE)
{
  msgStatus = "Warning: unable to set the read tiemout..";
  SHOWSTAT(msgStatus);
}

/* Allocate PACKET structure for ARP Reply packet */
if((lpPacketReply = PacketAllocatePacket()) == NULL)
{
  msgStatus = "Error: failed to allocate the LPPACKET structure..";
  SHOWSTAT(msgStatus);
  PacketFreePacket(lpPacketRequest);
  return(EXIT_FAILURE);
}
/* Init ARP Reply packet */
PacketInitPacket(lpPacketReply, (char*)buffer, 256000);
/* Allocate memory for remote MAC address */
timestamp = GetTickCount();

/* Main capture loop */
for(;;)
{
  if(numPacks < wParams.numPacks)
  {
  /* Send packet */
    if(PacketSendPacket(lpAdapter, lpPacketRequest, TRUE) == FALSE)
    {
    msgStatus ="Error : unable to send the packets..";
    SHOWSTAT(msgStatus);
    PacketFreePacket(lpPacketRequest);
    PacketFreePacket(lpPacketReply);
    return(EXIT_FAILURE);
    }
    /* Free packet */
    PacketFreePacket(lpPacketRequest);
    numPacks += 1;
  }
  /* Capture the packets */
  if(PacketReceivePacket(lpAdapter, lpPacketReply, TRUE) == FALSE)
  {
    msgStatus = "Error: PacketReceivePacket failed..";
    SHOWSTAT(msgStatus);
PacketFreePacket(lpPacketReply);
  return(EXIT_FAILURE);
  }
  if(lpPacketReply->ulBytesReceived > 0)
  if(GetARPReply(lpPacketReply, iptarget, remotemac) == EXIT_SUCCESS)
      break;
  if((GetTickCount() - timestamp) > wParams.delay)
  {
    PacketFreePacket(lpPacketReply);
    return(EXIT_FAILURE);
  }
}
/* Free packet */
PacketFreePacket(lpPacketReply);
return(EXIT_SUCCESS);
}
sunxufei:
哦,交換機是以MAC位址進行交換的,不是IP那一層的,要IP已經路由器了
現在交換機便宜了,因此以後你想用sniffer抓密碼概率不大了,不過還能多公司仍然是交換機和H

UB一起用的,這樣小範圍內是有效地,至於ADSLCABLE FTTB,我的FTTB是用華為設計的設備

,呵呵,不僅僅工網IP,只有我和交換機兩個MAC(這次中國人幹的不錯),沒希望找到第三者,很安全,

不都這樣安全,很多人的網路還是很糟糕的.
很多加密協議可以用來提高安全性,但老的POP3,SMTP,HTTP,FTP這種協議應用廣泛,不可能在短

時間內完全取代,而且加密也是有待價的,所以對於要求較高的場合,才會加密.
不過sniffer不是給大家偷密碼用的,我當初用來學習網路,看看包的樣子,後來就用來當作網管工具,

分析網路的健康與否,其實這樣的話,你知道,很有可能sniffer就是接在我需要探測的網路上,聽診器

,到處都聽聽,呵呵,因此即使用了交換機,sniffer仍然是有用處的,但不是抓密碼!!
Wincap很簡單,3的學生不要怕,去他的網站看看,有例子的,VC6編譯,BCB也行的,lib的格式轉

換一下,不過寫這種程式,你最好先熟悉協議,很多協議在linux裡有現成的原始程式碼,主要是一些struct

,移植時注意VC可不是gcc,有些c的高級語法,編譯選項要注意,否則差一個byte你就得不到正確的

結果.
如果你搞不到sniffer,Win2000 Server也有網路包檢視器的,不比sniffer強大,但簡單的東西入手

沒有留言: