《电子技术应用》
您所在的位置:首页 > 通信与网络 > 业界动态 > 网络安全编程:嗅探技术

网络安全编程:嗅探技术

2021-07-31
来源:计算机与网络安全
关键词: 网络安全 嗅探技术

  嗅探器可以神不知鬼不觉地去获得局域网中用户访问网络的数据,可谓是隐藏在黑暗中的偷窥者。嗅探技术可以分为主动嗅探和被动嗅探。主动嗅探主要是依赖ARP欺骗或MAC欺骗诱导被攻击者将数据发送给攻击者;被动嗅探主要是将网卡设置为混杂模式,然后接收通过网卡的所有数据。本文主要介绍被动嗅探的工作方式。

  1. 嗅探器的编写思路

  共享方式下的以太网会将数据发送给同一网段内的所有计算机网卡,接收到数据的网卡会将与自己MAC地址不匹配的数据丢弃。因为共享以太网会将别人的数据也发送给自己计算机的网卡,所以嗅探器就是利用共享以太网的原理进行嗅探的。网卡可以工作在多种方式下,当网卡工作在混杂模式下时,可接收所有的数据而不丢弃。当接收到数据以后,就需要自己解析IP头、TCP头、UDP头等信息。因此,开发一个嗅探器的简单思路就是改变网卡的工作方式为混杂模式,并解析收到的数据包。

  设置网卡的工作方式为混杂模式,该功能通过ioctlsocket()函数即可改变。代码如下:

  // 设置 SIO_RCVALL 控制代码,以便接收所有的 IP 包

  DWORD dwValue = 1;

  if( ioctlsocket(sRaw, SIO_RCVALL, &dwValue) != 0 )

  {

  return -1;

  }

  SIO_RCVALL定义在mstcpip.h头文件中,因此要编译它,必须包含该头文件及库文件,代码如下:

  #include <mstcpip.h>

  #pragma comment(lib, “Advapi32.lib”)

  为了收到数据包以便自己解析数据包,就要使用原始套接字,而不能单纯地使用TCP或UDP套接字。对于解析数据包,必须了解和清楚数据包的格式。这里给出TCP和UDP数据包的格式,定义如下:

  typedef struct _TCPHeader // 20 字节的 TCP 头

  {

  USHORT sourcePort; // 16 位源端口号

  USHORT destinationPort; // 16 位目的端口号

  ULONG sequenceNumber; // 32 位序列号

  ULONG acknowledgeNumber; // 32 位确认号

  UCHAR dataoffset; // 高 4 位表示数据偏移

  UCHAR flags; // 6 位标志位

  USHORT windows; // 16 位窗口大小

  USHORT checksum; // 16 位校验和

  USHORT urgentPointer; // 16 位紧急数据偏移量

  } TCPHeader, *PTCPHeader;

  typedef struct _UDPHeader

  {

  USHORT sourcePort; // 源端口号

  USHORT destinationPort; // 目的端口号

  USHORT len; // 封包长度

  USHORT checksum; // 校验和

  } UDPHeader, *PUDPHeader;

  2. 嗅探器的实现代码

  有了上面的内容,剩下的部分就简单了。代码如下:

  void DecodeTCPPacket(char *pData, char *szSrcIP, char *szDestIp)

  {

  TCPHeader *pTCPHdr = (TCPHeader *)pData;

  printf(“%s:%d -> %s:%d\r\n”,szSrcIP,

  ntohs(pTCPHdr->sourcePort),szDestIp,

  ntohs(pTCPHdr->destinationPort));

  // 下面还可以根据目的端口号进一步解析应用层协议

  switch(::ntohs(pTCPHdr->destinationPort))

  {

  case 21:

  // 解析 FTP 的用户名和密码

  printf(“FTP========================================\r\n”);

  pData = pData + sizeof(TCPHeader);

  if ( strncmp(pData, “USER ”, 5) == 0 )

  {

  printf(“Ftp UserName : %s \r\n”, pData + 4);

  }

  if ( strncmp(pData, “PASS ”, 5) == 0 )

  {

  printf(“Ftp Password : %s \r\n”, pData + 4);

  }

  printf(“FTP========================================\r\n”);

  break;

  case 80:

  case 8080:

  // 直接输出浏览器获取到的内容

  printf(“WEB========================================\r\n”);

  printf(“%s\r\n”, pData + sizeof(TCPHeader));

  printf(“WEB========================================\r\n”);

  break;

  }

  }

  void DecodeUDPPacket(char *pData, char *szSrcIP, char *szDestIp)

  {

  UDPHeader *pUDPHdr = (UDPHeader *)pData;

  printf(“%s:%d -> %s:%d\r\n”,szSrcIP,

  ntohs(pUDPHdr->sourcePort),szDestIp,

  ntohs(pUDPHdr->destinationPort));

  }

  void DecodeIPPacket(char *pData)

  {

  IPHeader *pIPHdr = (IPHeader*)pData;

  in_addr source, dest;

  char szSourceIp[32], szDestIp[32];

  printf(“-------------------------------\r\n”);

  // 从 IP 头中取出源 IP 地址和目的 IP 地址

  source.S_un.S_addr = pIPHdr->ipSource;

  dest.S_un.S_addr = pIPHdr->ipDestination;

  strcpy(szSourceIp, inet_ntoa(source));

  strcpy(szDestIp, inet_ntoa(dest));

  // IP 头长度

  int nHeaderLen = (pIPHdr->iphVerLen & 0xf) * sizeof(ULONG);

  switch( pIPHdr->ipProtocol )

  {

  case IPPROTO_TCP: // TCP 协议

  DecodeTCPPacket(pData + nHeaderLen, szSourceIp, szDestIp);

  break;

  case IPPROTO_UDP:

  DecodeUDPPacket(pData + nHeaderLen, szSourceIp, szDestIp);

  break;

  case IPPROTO_ICMP:

  break;

  }

  }

  int main()

  {

  WSADATA wsa;

  WSAStartup(MAKEWORD(2, 2), &wsa);

  // 创建原始套节字

  SOCKET sRaw = socket(AF_INET, SOCK_RAW, IPPROTO_IP);

  // 获取本地 IP 地址

  char szHostName[56];

  SOCKADDR_IN addr_in;

  struct hostent *pHost;

  gethostname(szHostName, 56);

  if( (pHost = gethostbyname((char*)szHostName)) == NULL )

  {

  return -1;

  }

  // 在调用 ioctl 之前,必须绑定套节字

  addr_in.sin_family = AF_INET;

  addr_in.sin_port = htons(0);

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

  printf(“Binding to interface : %s \r\n”, ::inet_ntoa(addr_in.sin_addr));

  if( bind(sRaw, (PSOCKADDR)&addr_in, sizeof(addr_in)) == SOCKET_ERROR )

  {

  return -1;

  }

  // 设置 SIO_RCVALL 控制代码,以便接收所有的 IP 包

  DWORD dwValue = 1;

  if( ioctlsocket(sRaw, SIO_RCVALL, &dwValue) != 0 )

  {

  return -1;

  }

  // 开始接收封包

  char buff[1024];

  int nRet;

  while(TRUE)

  {

  nRet = recv(sRaw, buff, 1024, 0);

  if( nRet > 0 )

  {

  DecodeIPPacket(buff);

  }

  }

  closesocket(sRaw);

  WSACleanup();

  return 0;

  }




电子技术图片.png

本站内容除特别声明的原创文章之外,转载内容只为传递更多信息,并不代表本网站赞同其观点。转载的所有的文章、图片、音/视频文件等资料的版权归版权所有权人所有。本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如涉及作品内容、版权和其它问题,请及时通过电子邮件或电话通知我们,以便迅速采取适当措施,避免给双方造成不必要的经济损失。联系电话:010-82306118;邮箱:aet@chinaaet.com。