
在普通程序中普遍用ioctl函数来设置,该函数很值得大家好好的了解,因为它的使用非常的广泛。下面
给出设置网卡混杂模式的实现代码:
#include
#include
#include
#include
int set_all_promisc()
{ struct ifreq ifaces[16]
struct ifconf param
int sock, i
param.ifc_len = sizeof(ifaces)
param.ifc_req = ifaces
sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)
if (sock <= 0)
return 0
if (ioctl(sock, SIOCGIFCONF, ¶m))
return 0
for (i = 0i <param.ifc_len / sizeof(struct ifreq)i++) {
if (ioctl(sock, SIOCGIFFLAGS, ifaces + i))
return 0
ifaces[i].ifr_flags |= IFF_PROMISC/*如果恢复网卡模式,把|= 改成 &=~ */
if (ioctl(sock, SIOCSIFFLAGS, ifaces + i))
return 0
}
return 1
}
二、在核心空间中设置混杂模式
1.在kernel-2.2.x 中
static struct device *sniffer_dev = NULL
static unsigned short old_flags, old_gflags
int init_module ( void ) /* 模块初始化 */
{
......
sniffer_dev = dev_get("eth0")
if ( sniffer_dev != NULL )
{
/* thanks for difeijing of whnet's Security */
old_flags = sniffer_dev->flags
old_gflags = sniffer_dev->gflags
/*
* 参看net/core/dev.c里的dev_change_flags()
* ->gflags的作用是避免多次重复设置混杂模式,没有其他特别含义
*/
/* 设置混杂模式 */
sniffer_dev->flags |= IFF_PROMISC
sniffer_dev->gflags |= IFF_PROMISC
start_bh_atomic()
/* 注意,这个回调函数还是会报告 eth0: Setting promiscuous mode. */
sniffer_dev->set_multicast_list( sniffer_dev )
end_bh_atomic()
}
......
return 0
}
void cleanup_module(void)
{
......
if (sniffer_dev != NULL)
{
/* 恢复原有模式 */
sniffer_dev>flags = old_flags
sniffer_dev>gflags = old_gflags
start_bh_atomic()
sniffer_dev>set_multicast_list( sniffer_dev )
end_bh_atomic()
}
......
}
2.在kernel-2.4.x 中
在2.4中有了许多变化,首先struct device结构改为struct net_device, 再者dev_get
功能改为测试网络设备是否存在,真正的设置网络混杂模式的函数改为
void dev_set_promiscuity(struct net_device *dev, int inc);
其中根据inc的值来设置混杂模式还是恢复原来设置模式,通过计数来恢复原来模式,这样的好处就是:不会和其他的程序冲突,不在像上述两种实现方式中恢复原来模式就全恢复了,不管还有没有其他的程序是否也设置了混杂模式。现在就通过计数来恢复原来的模式,只要当计数相加为零才设置成普通模式。
linux源代码的注释如下:
/**
* dev_set_promiscuity - update promiscuity count on a device
* @dev: device
* @inc: modifier
*
* Add or remove promsicuity from a device. While the count in the device
* remains above zero the interface remains promiscuous. Once it hits zero
* the device reverts back to normal filtering operation. A negative inc
* value is used to drop promiscuity on the device.
*/
设置网卡混杂模式的实现代码如下:
struct net_device *sniffer_dev = NULL
int dev_flags = 0
int init_module ( void ) /* 模块初始化 */
{
......
sniffer_dev = dev_get_by_name("eth0")
if (sniffer_dev != NULL)
{
dev_flags = 1
dev_set_promiscuity(sniffer_dev, 1)
dev_put(sniffer_dev)
sniffer_dev = NULL
}
......
return 0
}
void cleanup_module(void)
{
......
if (dev_flags)
{
sniffer_dev = dev_get_by_name("eth0")
if (sniffer_dev != NULL)
{
dev_flags = 0
dev_set_promiscuity(sniffer_dev, -1)/*注意此处的第二个参数*/
dev_put(sniffer_dev)
sniffer_dev = NULL
}
}
......
}
你可以用ARP探测网络中的混杂模式节点根据sniffer的基本工作原理,其核心就是设置网卡模式为 promiscuous(混杂模式),如果能够检测到网络有是混杂模式的网卡,那么就可以判断可能存在一个sniffer。ARP协议在深入嗅探中很有作用,同时也可以用于进行嗅探器的侦测。
在混杂模式中,网卡进行包过滤不同于普通模式。本来在普通模式下,只有本地地址的数据包或者广播(多播等)才会被网卡提交给系统核心,否则的话,这些数据包就直接被网卡抛弃。现在,混合模式让所有经过的数据包都传递给系统核心,然后被sniffer等程序利用。因此,如果能利用中间的“系统核心”,就能有效地进行是否混杂模式的检测。系统核心也会对一些数据包进行过滤,但是,和网卡的标准不一样的是。
以Windows系统为例:
FF-FF-FF-FF-FF-FF:这个是一个正规的广播地址,不管是正常模式还是其他模式,都会被网卡接收并传递给系统核心。
FF-FF-FF-FF-FF-00:这个地址对于网卡来说,不是一个广播地址,在正常模式下会被网卡抛弃,但是系统核心是认为这个地址同FF-FF-FF-FF-FF-FF是完全一样的。如果处于混杂模式,将被系统核心接收,并认为是一个广播地址。所有的Windows *** 作系统都是如此。
FF-FF-00-00-00-00:Windows核心只对前面两字节作判断,核心认为这是一个同FF-FF-FF-FF-FF-FF一样的广播地址。这就是为什么FF-FF-FF-FF-FF-00也是广播地址的原因。
FF-00-00-00-00-00:对于Win9x或WinME,则是检查前面的一个字节。因此会认为这个是一个广播地址。
而对于LINUX内核,我则不清楚,不过从一些资料得到会判断一个group bit,不清楚具体什么意思,但是基本上就是认为FF-00-00-00-00-00,是FF-FF-FF-FF-FF-FF一个类别的吧。(望熟悉LINUX者指点)
所以,目的就要让正常模式的网卡抛弃掉探测包,而让混杂模式的系统核心能够处理探测。发送一个目的地址为:FF-FF-FF-FF-FF-FE(系统会认为属于广播地址)的ARP请求,对于普通模式(广播等)的网卡,这个地址不是广播地址,就会直接抛弃,而如果处于混杂模式,那么ARP请求就会被系统核心当作广播地址处理,然后提交给sniffer程序。系统核心就会应答这个ARP请求。
antisniffer也采用了这样的策略进行检测。
下面这个例子就是FF-FF-FF-FF-FF-FE的ARP请求,可以对网络中的每个节点都发送这样的ARP请求。如果有一般的sniffer存在,并设置网卡为混杂模式,那么系统核心就会作出应答,可以判断这些节点是否存在嗅探器了。这种检测办法也是有局限的,对于那些修改内核的sniffer,就没有办法了,不过这种Sniffer毕竟属于少数还有就是Win2k中一些动态加载的包捕获驱动(WinPcap就是),可能会让没有在混杂模式的网卡也作出响应。
///////////////////////////////////////////////////////////////////////////////
//
//Detect Promiscuous Node In Network
//
// Author: suchasplus
// Email: suchasplus@gmail.com
// Home Page: spaces.msn.com/suchasplus
//
// 2006/02/02
//
////////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "Mac.h"//GetMacAddr(),我写的把字符串转换为MAC地址的函数,就不列在这里了
#include <stdio.h>
#include <conio.h>
#include <Packet32.h>
#include <Winsock2.h>
#include <process.h>
#include <ntddndis.h>
#pragma comment (lib, "packet.lib")
#pragma comment (lib, "ws2_32.lib")
#define EPT_IP0x0800/* type: IP*/
#define EPT_ARP0x0806/* type: ARP */
#define EPT_RARP0x8035/* type: RARP */
#define ARP_HARDWARE0x0001/* Dummy type for 802.3 frames */
#defineARP_REQUEST0x0001/* ARP request */
#defineARP_REPLY0x0002/* ARP reply */
#define Max_Num_Adapter 10
#pragma pack(push, 1)
typedef struct ehhdr
{
unsigned chareh_dst[6] /* destination ethernet addrress */
unsigned chareh_src[6] /* source ethernet addresss */
unsigned shorteh_type /* ethernet pachet type*/
}EHHDR, *PEHHDR
typedef struct arphdr
{
unsigned shortarp_hrd /* format of hardware address */
unsigned shortarp_pro /* format of protocol address */
unsigned chararp_hln /* length of hardware address */
unsigned chararp_pln /* length of protocol address */
unsigned shortarp_op /* ARP/RARP operation */
unsigned chararp_sha[6] /* sender hardware address */
unsigned longarp_spa /* sender protocol address */
unsigned chararp_tha[6] /* target hardware address */
unsigned longarp_tpa /* target protocol address */
}ARPHDR, *PARPHDR
typedef struct arpPacket
{
EHHDRehhdr
ARPHDRarphdr
} ARPPACKET, *PARPPACKET
#pragma pack(pop)
//the thread for listening
void ListenThread(void* Adapter)
//the function of sending packet
void SendARPPacket(void* Adapter)
BOOL DetectIsSniffer(LPPACKET lpPacket)
char g_szMyMacAddr[] = "AAAAAAAAAAAA"
char g_szMyIP[] = "192.168.1.1"
char g_szTargetIP[] = "192.168.1.2"
int main(int argc, char* argv[])
{
static char AdapterList[Max_Num_Adapter][1024]
LPADAPTERlpAdapter
WCHARAdapterName[2048]
WCHAR*temp,*temp1
ULONG AdapterLength = 1024
int AdapterNum = 0
int nRetCode, i
//Get The list of Adapter
if(PacketGetAdapterNames((char*)AdapterName, &AdapterLength) == FALSE)
{
printf("Unable to retrieve the list of the adapters!\n")
return 0
}
temp = AdapterName
temp1 = AdapterName
i = 0
while ((*temp != '\0')||(*(temp-1) != '\0'))
{
if (*temp == '\0')
{
memcpy(AdapterList[i],temp1,(temp-temp1)*2)
temp1 = temp+1
i++
}
temp++
}
AdapterNum = i
for (i = 0i <AdapterNumi++)
wprintf(L"\n%d- %s\n", i+1, AdapterList[i])
printf("\n")
//Default open the 0
lpAdapter = (LPADAPTER) PacketOpenAdapter((LPTSTR) AdapterList[0])
if (!lpAdapter || (lpAdapter->hFile == INVALID_HANDLE_VALUE))
{
nRetCode = GetLastError()
printf("Unable to open the driver, Error Code : %lx\n", nRetCode)
return 0
}
//begin listening
_beginthread(ListenThread, 0, (void*) lpAdapter)
Sleep(500)
//send the packet
_beginthread(SendARPPacket, 0, (void*) lpAdapter)
Sleep(2000)
printf ("\n\nDetecting end.\n")
// close the adapter and exit
PacketCloseAdapter(lpAdapter)
return 0
}
void SendARPPacket(void* Adapter)
{
char MacAddr[6]
char szPacketBuf[600]
LPADAPTERlpAdapter = (LPADAPTER) Adapter
LPPACKETlpPacket
ARPPACKET ARPPacket
lpPacket = PacketAllocatePacket()
if(lpPacket == NULL)
{
printf("\nError:failed to allocate the LPPACKET structure.\n")
return
}
ZeroMemory(szPacketBuf, sizeof(szPacketBuf))
// the fake mac of multicast
if (!GetMacAddr("FFFFFFFFFFFE", MacAddr))
{
printf ("Get Mac address error!\n")
goto Exit0
}
memcpy(ARPPacket.ehhdr.eh_dst, MacAddr, 6)
//the MAC of sender
if (!GetMacAddr(g_szMyMacAddr, MacAddr))
{
printf ("Get Mac address error!\n")
goto Exit0
}
memcpy(ARPPacket.ehhdr.eh_src, MacAddr, 6)
ARPPacket.ehhdr.eh_type = htons(EPT_ARP)
//arp header
ARPPacket.arphdr.arp_hrd = htons(ARP_HARDWARE)
ARPPacket.arphdr.arp_pro = htons(EPT_IP)
ARPPacket.arphdr.arp_hln = 6
ARPPacket.arphdr.arp_pln = 4
ARPPacket.arphdr.arp_op = htons(ARP_REQUEST)
if (!GetMacAddr("00E04C6A21DF", MacAddr))
{
printf ("Get Mac address error!\n")
goto Exit0
}
memcpy(ARPPacket.arphdr.arp_sha, MacAddr, 6)
ARPPacket.arphdr.arp_spa = inet_addr(g_szMyIP)
if (!GetMacAddr("000000000000", MacAddr))
{
printf ("Get Mac address error!\n")
goto Exit0
}
memcpy(ARPPacket.arphdr.arp_tha , MacAddr, 6)
ARPPacket.arphdr.arp_tpa = inet_addr(g_szTargetIP)
memcpy(szPacketBuf, (char*)&ARPPacket, sizeof(ARPPacket))
PacketInitPacket(lpPacket, szPacketBuf, 60)
if(PacketSetNumWrites(lpAdapter, 1)==FALSE)
{
printf("warning: Unable to send more than one packet in a single write!\n")
}
if(PacketSendPacket(lpAdapter, lpPacket, TRUE)==FALSE)
{
printf("Error sending the packets!\n")
goto Exit0
}
printf ("Send ok!\n\n")
Exit0:
PacketFreePacket(lpPacket)
_endthread()
}
void ListenThread(void* Adapter)
{
LPPACKET lpPacket
LPADAPTER lpAdapter = (LPADAPTER) Adapter
char buffer[256000]
if((lpPacket = PacketAllocatePacket())==NULL){
printf("\nError: failed to allocate the LPPACKET structure.")
return
}
PacketInitPacket(lpPacket,(char*)buffer,256000)
// set the network adapter in promiscuous mode
if(PacketSetHwFilter(lpAdapter, NDIS_PACKET_TYPE_DIRECTED)==FALSE){
printf("Warning: unable to set promiscuous mode!\n")
}
// set buffer in the driver
if(PacketSetBuff(lpAdapter,512000)==FALSE){
printf("Unable to set the kernel buffer!\n")
return
}
// set second read timeout
if(PacketSetReadTimeout(lpAdapter, 200)==FALSE){
printf("Warning: unable to set the read tiemout!\n")
}
//main capture loop
printf("Listen....\n")
while(true)
{
// capture the packets
if(PacketReceivePacket(lpAdapter, lpPacket, TRUE)==FALSE){
printf("Error: PacketReceivePacket failed")
return
}
//
DetectIsSniffer(lpPacket)
}
PacketFreePacket(lpPacket)
// close the adapter and exit
PacketCloseAdapter(lpAdapter)
_endthread()
}
BOOL DetectIsSniffer(LPPACKET lpPacket)
{
BOOL bFlag = FALSE
PARPHDR pARPHeader
PARPPACKET pARPPacket
char MacAddr[6]
GetMacAddr(g_szMyMacAddr, MacAddr)
pARPPacket = (PARPPACKET) ((char*)lpPacket->Buffer + 20)
if (pARPPacket->ehhdr.eh_type == htons(EPT_IP))
return FALSE
if (strcmp((char*)(pARPPacket->ehhdr.eh_dst), MacAddr) == 0
&&pARPPacket->ehhdr.eh_type == htons(EPT_ARP))
{
char szTemp[10]
pARPHeader = (PARPHDR)((char*)lpPacket->Buffer + 20 + sizeof(EHHDR))
memcpy(szTemp, &pARPHeader->arp_spa, sizeof(pARPHeader->arp_spa))
printf ("A PROMISCUOUS NODE EXISTS!!\n")
printf ("\tIP:%s\n\n", inet_ntoa(*((struct in_addr *)(szTemp))))
return TRUE
}
return FALSE
}
拿vc6.0调试通过
Sniffer,中文可以翻译为嗅探器,是一种威胁性极大的被动攻击工具。使用这种工具,可以监视网络的状态、数据流动情况以及网络上传输的信息。当信息以明文的形式在网络上传输时,便可以使用网络监听的方式来进行攻击。将网络接口设置在监听模式,便可以将网上传输的源源不断的信息截获。黑客们常常用它来截获用户的口令。据说某个骨干网络的路由器曾经被黑客攻人,并嗅探到大量的用户口令。本文将详细介绍Sniffer的原理和应用。 一、Sniffer 原理 1.网络技术与设备简介 在讲述Sni计er的概念之前,首先需要讲述局域网设备的一些基本概念。 数据在网络上是以很小的称为帧(Frame)的单位传输的,帧由几部分组成,不同的部分执行不同的功能。帧通过特定的称为网络驱动程序的软件进行成型,然后通过网卡发送到网线上,通过网线到达它们的目的机器,在目的机器的一端执行相反的过程。接收端机器的以太网卡捕获到这些帧,并告诉 *** 作系统帧已到达,然后对其进行存储。就是在这个传输和接收的过程中,嗅探器会带来安全方面的问题。 每一个在局域网(LAN)上的工作站都有其硬件地址,这些地址惟一地表示了网络上的机器(这一点与Internet地址系统比较相似)。当用户发送一个数据包时,这些数据包就会发送到LAN上所有可用的机器。 在一般情况下,网络上所有的机器都可以“听”到通过的流量,但对不属于自己的数据包则不予响应(换句话说,工作站A不会捕获属于工作站B的数据,而是简单地忽略这些数据)。如果某个工作站的网络接口处于混杂模式(关于混杂模式的概念会在后面解释),那么它就可以捕获网络上所有的数据包和帧。 2.网络监听原理 Sniffer程序是一种利用以太网的特性把网络适配卡(NIC,一般为以太网卡)置为杂乱(promiscuous)模式状态的工具,一旦网卡设置为这种模式,它就能接收传输在网络上的每一个信息包。 普通的情况下,网卡只接收和自己的地址有关的信息包,即传输到本地主机的信息包。要使Sniffer能接收并处理这种方式的信息,系统需要支持BPF,Linux下需要支持SOCKET一PACKET。但一般情况下,网络硬件和TCP/IP堆栈不支持接收或者发送与本地计算机无关的数据包,所以,为了绕过标准的TCP/IP堆栈,网卡就必须设置为我们刚开始讲的混杂模式。一般情况下,要激活这种方式,内核必须支持这种伪设备Bpfilter,而且需要root权限来运行这种程序,所以sniffer需要root身份安装,如果只是以本地用户的身份进人了系统,那么不可能唤探到root的密码,因为不能运行Sniffer。 基于Sniffer这样的模式,可以分析各种信息包并描述出网络的结构和使用的机器,由于它接收任何一个在同一网段上传输的数据包,所以也就存在着捕获密码、各种信息、秘密文档等一些没有加密的信息的可能性。这成为黑客们常用的扩大战果的方法,用来夺取其他主机的控制权 3 Snifffer的分类 Sniffer分为软件和硬件两种,软件的Sniffer有 NetXray、Packetboy、Net monitor等,其优点是物美价廉,易于学习使用,同时也易于交流;缺点是无法抓取网络上所有的传输,某些情况下也就无法真正了解网络的故障和运行情况。硬件的Sniffer通常称为协议分析仪,一般都是商业性的,价格也比较贵。 实际上本文中所讲的Sniffer指的是软件。它把包抓取下来,然后打开并查看其中的内容,可以得到密码等。Sniffer只能抓取一个物理网段内的包,就是说,你和监听的目标中间不能有路由或其他屏蔽广播包的设备,这一点很重要。所以,对一般拨号上网的用户来说,是不可能利用Sniffer来窃听到其他人的通信内容的。 4.网络监听的目的 当一个黑客成功地攻陷了一台主机,并拿到了root权限,而且还想利用这台主机去攻击同一网段上的其他主机时,他就会在这台主机上安装Sniffer软件,对以太网设备上传送的数据包进行侦听,从而发现感兴趣的包。如果发现符合条件的包,就把它存到一个LOg文件中去。通常设置的这些条件是包含字“username”或“password”的包,这样的包里面通常有黑客感兴趣的密码之类的东西。一旦黑客截获得了某台主机的密码,他就会立刻进人这台主机。 如果Sniffer运行在路由器上或有路由功能的主机上,就能对大量的数据进行监控,因为所有进出网络的数据包都要经过路由器。 Sniffer属于第M层次的攻击。就是说,只有在攻击者已经进入了目标系统的情况下,才能使用Sniffer这种攻击手段,以便得到更多的信息。 Sniffer除了能得到口令或用户名外,还能得到更多的其他信息,比如一个重要的信息、在网上传送的金融信息等等。Sniffer几乎能得到任何在以太网上传送的数据包。 Sniffer是一种比较复杂的攻击手段,一般只有黑客老手才有能力使用它,而对于一个网络新手来说,即使在一台主机上成功地编译并运行了Sniffer,一般也不会得到什么有用的信息,因为通常网络上的信息流量是相当大的,如果不加选择地接收所有的包,然后从中找到所需要的信息非常困难;而且,如果长时间进行监听,还有可能把放置Sniffer的机器的硬盘撑爆。欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)