科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网安全频道Sniffer-黑客们最常用的入侵手段

Sniffer-黑客们最常用的入侵手段

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

可以用它来发送和接收 IP 层以上的原始数据包, 如 ICMP, TCP, UDP...越来越发现 Sniffer 原来如此的简单了, 这么一个函数就已经完成抓取数据包的任务了.缺点: 数据包头不含帧信息, 不能接收到与 IP 同层的其它数据包,.

作者: 51cto 2008年4月14日

关键字: 嗅探 网络嗅探 Sniffer 端口扫描

  • 评论
  • 分享微博
  • 分享邮件

  可以用它来发送和接收 IP 层以上的原始数据包, 如 ICMP, TCP, UDP...

  int sockRaw = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);

  这样我们就创建了一个 Raw Socket

  Sniffer: 嗅探器

  关于嗅探器的原理我想大多数人可能都知道

  1. 把网卡置于混杂模式;

  2. 捕获数据包;

  3. 分析数据包.

  但具体的实现知道的人恐怕就不是那么多了. 好, 现在让我们用 Raw Socket 的做一个自已的 Sniffer.

  二. 把网卡置于混杂模式

  在正常的情况下,一个网络接口应该只响应两种数据帧:

  一种是与自己硬件地址相匹配的数据帧

  一种是发向所有机器的广播数据帧

  如果要网卡接收所有通过它的数据, 而不管是不是发给它的, 那么必须把网卡置于混杂模式. 也就是说让它的思维混乱, 不按正常的方式工作. 用 Raw Socket 实现代码如下:

  setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char*)&flag, sizeof(flag); //设置 IP 头操作选项

  bind(sockRaw, (PSOCKADDR)&addrLocal, sizeof(addrLocal); //把 sockRaw 绑定到本地网卡上

  ioctlsocket(sockRaw, SIO_RCVALL, &dwValue); //让 sockRaw 接受所有的数据

  flag 标志是用来设置 IP 头操作的, 也就是说要亲自处理 IP 头: bool flag = ture;

  addrLocal 为本地地址: SOCKADDR_IN addrLocal;

  dwValue 为输入输出参数, 为 1 时执行, 0 时取消: DWORD dwValue = 1;

  没想到这么简单吧?

  三. 捕获数据包

  你的 sockRaw 现在已经在工作了, 可以在局域网内其它的电脑上用 Sniffer 检测工具检测一下, 看你的网卡是否处于混杂模式(比如 DigitalBrain 的 ARPKiller).

  不能让他白白的浪费资源啊, 抓包!

  recv(sockRaw, RecvBuf, BUFFER_SIZE, 0); //接受任意数据包

  #define BUFFER_SIZE 65535

  char RecvBuf[BUFFER_SIZE];

  越来越发现 Sniffer 原来如此的简单了, 这么一个函数就已经完成抓取数据包的任务了.

  四. 分析数据包

  这回抓来的包和平常用 Socket 接受的包可就不是一回事儿了, 里面包含 IP, TCP 等原始信息. 要分析它首先得知道这些结构.

  数据包的总体结构:

  ----------------------------------------------

  | ip header | tcp header(or x header) | data |

  ----------------------------------------------

  IP header structure:

  4 8 16 32 bit

  |--------|--------|----------------|--------------------------------|

  | Ver | IHL |Type of service | Total length |

  |--------|--------|----------------|--------------------------------|

  | Identification | Flags | Fragment offset |

  |--------|--------|----------------|--------------------------------|

  | Time to live | Protocol | Header checksum |

  |--------|--------|----------------|--------------------------------|

  | Source address |

  |--------|--------|----------------|--------------------------------|

  | Destination address |

  |--------|--------|----------------|--------------------------------|

  | Option + Padding |

  |--------|--------|----------------|--------------------------------|

  | Data |

  |--------|--------|----------------|--------------------------------|

  TCP header structure:

  16 32 bit

  |--------------------------------|--------------------------------|

  | Source port | Destination port |

  |--------------------------------|--------------------------------|

  | Sequence number |

  |--------------------------------|--------------------------------|

  | Acknowledgement number |

  |--------------------------------|--------------------------------|

  | Offset | Resrvd |U|A|P|R|S|F| Window |

  |--------------------------------|--------------------------------|

  | Checksum | Urgent pointer |

  |--------------------------------|--------------------------------|

  | Option + Padding |

  |--------------------------------|--------------------------------|

  | Data |

  |--------------------------------|--------------------------------|

  五. 实现 Sniffer

  OK!

  现在都清楚了, 还等什么.

  下面是我用 BCB6 写的一个 Simple Sniffer 的代码, 仅供参考.

  (需要在工程文件里加入WS2_32.LIB这个文件)

  //*************************************************************************//

  //* CPP File: WMain.cpp

  //* Simple Sniffer by shadowstar

  //* http://shadowstar.126.com/

  //*************************************************************************//

  #include

  #pragma hdrstop

  #include

  #include

  #include

  #include

  #include "WMain.h"

  //---------------------------------------------------------------------------

  #pragma package(smart_init)

  #pragma resource "*.dfm"

  TMainForm *MainForm;

  //---------------------------------------------------------------------------

  __fastcall TMainForm::TMainForm(TComponent* Owner)

  : TForm(Owner)

  {

  WSADATA WSAData;

  BOOL flag = true;

  int nTimeout = 1000;

  char LocalName[16];

  struct hostent *pHost;

  //检查 Winsock 版本号

  if (WSAStartup(MAKEWORD(2, 2), &WSAData) != 0)

  throw Exception("WSAStartup error!");

  //初始化 Raw Socket

  if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == INVALID_SOCKET)

  throw Exception("socket setup error!");

  //设置IP头操作选项

  if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char*)&flag, sizeof(flag)) == SOCKET_ERROR)

  throw Exception("setsockopt IP_HDRINCL error!");

  //获取本机名

  if (gethostname((char*)LocalName, sizeof(LocalName)-1) == SOCKET_ERROR)

  throw Exception("gethostname error!");

  //获取本地 IP 地址

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

  throw Exception("gethostbyname error!");

  addr_in.sin_addr = *(in_addr *)pHost->h_addr_list[0]; //IP

  addr_in.sin_family = AF_INET;

  addr_in.sin_port = htons(57274);

  //把 sock 绑定到本地地址上

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

  throw Exception("bind error!");

  iSortDirection = 1;

  }

  //---------------------------------------------------------------------------

  __fastcall TMainForm::~TMainForm()

  {

  WSACleanup();

  }

  //---------------------------------------------------------------------------

  void __fastcall TMainForm::btnCtrlClick(TObject *Sender)

  {

  TListItem *Item;

  DWORD dwValue;

  int nIndex = 0;

  if (btnCtrl->Caption == "&Start")

  {

  dwValue = 1;

  //设置 SOCK_RAW 为SIO_RCVALL,以便接收所有的IP包

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

  throw Exception("ioctlsocket SIO_RCVALL error!");

  bStop = false;

  btnCtrl->Caption = "&Stop";

  lsvPacket->Items->Clear();

  }

  else

  {

  dwValue = 0;

  bStop = true;

  btnCtrl->Caption = "&Start";

  //设置SOCK_RAW为SIO_RCVALL,停止接收

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

  throw Exception("WSAIoctl SIO_RCVALL error!");

  }

  while (!bStop)

  {

  if (recv(sock, RecvBuf, BUFFER_SIZE, 0) >0)

  {

  nIndex++;

  ip = *(IP*)RecvBuf;

  tcp = *(TCP*)(RecvBuf + (ip.HdrLen &IP_HDRLEN_MASK));

  Item = lsvPacket->Items->Add();

  Item->Caption = nIndex;

  Item->SubItems->Add(GetProtocolTxt(ip.Protocol));

  Item->SubItems->Add(inet_ntoa(*(in_addr*)&ip.SrcAddr));

  Item->SubItems->Add(inet_ntoa(*(in_addr*)&ip.DstAddr));

  Item->SubItems->Add(tcp.SrcPort);

  Item->SubItems->Add(tcp.DstPort);

  Item->SubItems->Add(ntohs(ip.TotalLen));

  }

  Application->ProcessMessages();

  }

  }

  //---------------------------------------------------------------------------

  AnsiString __fastcall TMainForm::GetProtocolTxt(int Protocol)

  {

  switch (Protocol)

  {

  case IPPROTO_ICMP : //1 /* control message protocol */

  return PROTOCOL_STRING_ICMP_TXT;

  case IPPROTO_TCP : //6 /* tcp */

  return PROTOCOL_STRING_TCP_TXT;

  case IPPROTO_UDP : //17 /* user datagram protocol */

  return PROTOCOL_STRING_UDP_TXT;

  default :

  return PROTOCOL_STRING_UNKNOWN_TXT;

  }

  }

  //---------------------------------------------------------------------------

  //*************************************************************************//

  //* Header File: WMain.h for WMain.cpp class TMainForm

  //*************************************************************************//

  //---------------------------------------------------------------------------

  #ifndef WMainH

  #define WMainH

  //---------------------------------------------------------------------------

  #define BUFFER_SIZE 65535

  #include

  #include

  #include

  #include

  #include

  #include

  #include

  #include "netmon.h"

  //---------------------------------------------------------------------------

  class TMainForm : public TForm

  {

  __published: // IDE-managed Components

  TPanel *Panel1;

  TButton *btnCtrl;

  TListView *lsvPacket;

  TLabel *Label1;

  void __fastcall btnCtrlClick(TObject *Sender);

  void __fastcall lsvPacketColumnClick(TObject *Sender,

  TListColumn *Column);

  void __fastcall lsvPacketCompare(TObject *Sender, TListItem *Item1,

  TListItem *Item2, int Data, int &Compare);

  void __fastcall Label1Click(TObject *Sender);

  private: // User declarations

  AnsiString __fastcall GetProtocolTxt(int Protocol);

  public: // User declarations

  SOCKET sock;

  SOCKADDR_IN addr_in;

  IP ip;

  TCP tcp;

  PSUHDR psdHeader;

  char RecvBuf[BUFFER_SIZE];

  bool bStop;

  int iSortDirection;

  int iColumnToSort;

  __fastcall TMainForm(TComponent* Owner);

  __fastcall ~TMainForm();

  };

  //---------------------------------------------------------------------------

  extern PACKAGE TMainForm *MainForm;

  //---------------------------------------------------------------------------

  #endif

  偷了个懒, IP, TCP 头及一些宏定义用了 netmon.h 的头, 这个文件在 BCB6 的 include 目录下可以找得到, 其中与本程序相关内容如下:

  //*************************************************************************//

  //* Header File: netmon.h

  //*************************************************************************//

  //

  // IP Packet Structure

  //

  typedef struct _IP

  {

  union

  {

  BYTE Version;

  BYTE HdrLen;

  };

  BYTE ServiceType;

  WORD TotalLen;

  WORD ID;

  union

  {

  WORD Flags;

  WORD FragOff;

  };

  BYTE TimeToLive;

  BYTE Protocol;

  WORD HdrChksum;

  DWORD SrcAddr;

  DWORD DstAddr;

  BYTE Options[0];

  } IP;

  typedef IP * LPIP;

  typedef IP UNALIGNED * ULPIP;

  //

  // TCP Packet Structure

  //

  typedef struct _TCP

  {

  WORD SrcPort;

  WORD DstPort;

  DWORD SeqNum;

  DWORD AckNum;

  BYTE DataOff;

  BYTE Flags;

  WORD Window;

  WORD Chksum;

  WORD UrgPtr;

  } TCP;

  typedef TCP *LPTCP;

  typedef TCP UNALIGNED * ULPTCP;

  // upper protocols

  #define PROTOCOL_STRING_ICMP_TXT "ICMP"

  #define PROTOCOL_STRING_TCP_TXT "TCP"

  #define PROTOCOL_STRING_UDP_TXT "UDP"

  #define PROTOCOL_STRING_SPX_TXT "SPX"

  #define PROTOCOL_STRING_NCP_TXT "NCP"

  #define PROTOCOL_STRING_UNKNOW_TXT "UNKNOW"

  这个文件也有人声称没有.

  //*************************************************************************//

  //* Header File: mstcpip.h

  //*************************************************************************//

  // Copyright (c) Microsoft Corporation. All rights reserved.

  #if _MSC_VER >1000

  #pragma once

  #endif

  /* Argument structure for SIO_KEEPALIVE_VALS */

  struct tcp_keepalive {

  u_long onoff;

  u_long keepalivetime;

  u_long keepaliveinterval;

  };

  // New WSAIoctl Options

  #define SIO_RCVALL _WSAIOW(IOC_VENDOR,1)

  #define SIO_RCVALL_MCAST _WSAIOW(IOC_VENDOR,2)

  #define SIO_RCVALL_IGMPMCAST _WSAIOW(IOC_VENDOR,3)

  #define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4)

  #define SIO_ABSORB_RTRALERT _WSAIOW(IOC_VENDOR,5)

  #define SIO_UCAST_IF _WSAIOW(IOC_VENDOR,6)

  #define SIO_LIMIT_BROADCASTS _WSAIOW(IOC_VENDOR,7)

  #define SIO_INDEX_BIND _WSAIOW(IOC_VENDOR,8)

  #define SIO_INDEX_MCASTIF _WSAIOW(IOC_VENDOR,9)

  #define SIO_INDEX_ADD_MCAST _WSAIOW(IOC_VENDOR,10)

  #define SIO_INDEX_DEL_MCAST _WSAIOW(IOC_VENDOR,11)

  // Values for use with SIO_RCVALL* options

  #define RCVALL_OFF 0

  #define RCVALL_ON 1

  #define RCVALL_SOCKETLEVELONLY 2

  现在我们自已的 Sniffer 就做好了, Run, Start......哇, 这么多数据包, 都是从这一台机器上发出的, 它在干什么? 原来 Adminstrator 密码为空, 中了尼姆达病毒!

  六. 小结

  优点: 实现简单, 不需要做驱动程序就可实现抓包.

  缺点: 数据包头不含帧信息, 不能接收到与 IP 同层的其它数据包, 如 ARP, RARP...

  这里提供的程序仅仅是一个 Sniffer 的例子, 没有对数据包进行进一步的分析. 写此文的目的在于熟悉Raw Socket 编程方法, 了解 TCP/IP 协议结构原理以及各协议之间的关系.

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章