zoukankan      html  css  js  c++  java
  • 作业实践

    作业实践

    一、 每个人找一个抓包软件,分析其功能,设计的模块等,着重使用和分析,不建议用wireshark,编译过程可能比较难,也可挑战 。

    当我面对这份题目的时候,我开头可以说是无从下手啊!源代码....SOS....但是我还是想着慢慢磨,一点点的了解吧!多种因素导致我只是肤浅的了解,代码研究并不是很通透。之后有时间的话这篇博客我会再次打造。

    我再次看了下《网络攻防技术与实践》这本书,书中只进行了一部分的介绍。其他部分模块的代码是从网上搜集的!

    Libpcap是类UNIX平台用户态下的抓包工具库,与内核态的BPF包嗅探与过滤机制相配合,为类UNIX平台上的应用程序提供标准的网络嗅探接口。Libpcap提供了独立于不同操作系统类型的标准接口,除了支持常用的C语言之外,还为其他多种高级编程语言包装了接口,包括Perl、Python、Ruby、Java等。Libpcap与BPF作为类UNIX平台下的网络嗅探标准接口支持,被广泛应用于大量网络相关的应用软件。Linux 下著名的 tcpdump 就是以它为基础的。

    • libpcap主要的作用:

    1)捕获各种数据包(网络流量统计)

    2)过滤网络数据包(过滤掉本地上的一些数据,类似防火墙)

    3)分析网络数据包(分析网络协议,数据的采集)

    4)存储网络数据包(保存捕获的数据以为将来进行分析)

    • libpcap 的抓包框架

    pcap_lookupdev():函数用于查找网络设备,返回可被 pcap_open_live() 函数调用的网络设备名指针。

    pcap_lookupnet():函数获得指定网络设备的网络号和掩码。

    pcap_open_live(): 函数用于打开网络设备,并且返回用于捕获网络数据包的数据包捕获描述字。对于此网络设备的操作都要基于此网络设备描述字。

    pcap_compile(): 函数用于将用户制定的过滤策略编译到过滤程序中。

    pcap_setfilter():函数用于设置过滤器。

    pcap_loop():函数 pcap_dispatch() 函数用于捕获数据包,捕获后还可以进行处理,此外 pcap_next() 和 pcap_next_ex() 两个函数也可以用来捕获数据包。

    pcap_close():函数用于关闭网络设备,释放资源。

    • Libpcap 抓包详细步骤

    1、获取网络接口设备名 char *pcap_lookupdev(char *errbuf);得到可用的网络设备名指针

    参数:errbuf:存放出错信息字符串,里面有个宏定义:PCAP_ERRBUF_SIZE,为错误缓冲区大小

    返回值:成功返回设备名指针(第一个合适的网络接口的字符串指针);失败返回 NULL,同时,errbuf 存放出错信息字符串。

    char *dev = pcap_lookupdev(error_content);
    if(NULL == dev)
    {
    	printf(error_content);
    	exit(-1);
    }
    

    2、获取网络号(ip 地址)和掩码int pcap_lookupnet(char *device,bpf_u_int32 *netp, bpf_u_int32 *maskp,char *errbuf );获取指定网卡的 ip 地址,子网掩码

    参数:

    device:网络设备名,为第一步获取的网络接口字符串(pcap_lookupdev() 的返回值 ),也可人为指定,如“eth0”。

    netp:存放 ip 地址的指针,bpf_u_int32 为 32 位无符号整型

    maskp:存放子网掩码的指针,bpf_u_int32 为 32 位无符号整型

    errbuf:存放出错信息

    返回值:成功返回 0,失败返回 -1

    
    char *dev = pcap_lookupdev(error_content);
    if(NULL == dev)
    {
    	printf(error_content);
    	exit(-1);
    }
     
     
    bpf_u_int32 netp = 0, maskp = 0;
    pcap_t * pcap_handle = NULL;
    int ret = 0;
     
    //获得网络号和掩码
    ret = pcap_lookupnet(dev, &netp, &maskp, error_content);
    if(ret == -1)
    {
    	printf(error_content);
    	exit(-1);
    }
    
    

    3、打开网络接口 pcap_t *pcap_open_live( const char *device,int snaplen,int promisc,int to_ms,char *ebuf );打开一个用于捕获数据的网络接口

    参数:

    device:网络接口的名字,为第一步获取的网络接口字符串(pcap_lookupdev() 的返回值 ),也可人为指定,如“eth0”。

    snaplen:捕获数据包的长度,长度不能大于 65535 个字节。

    promise:“1” 代表混杂模式,其它非混杂模式。

    to_ms:指定需要等待的毫秒数,超过这个数值后,获取数据包的函数就会立即返回(这个函数不会阻塞,后面的抓包函数才会阻塞)。0 表示一直等待直到有数据包到来。

    ebuf:存储错误信息。

    返回值:返回 pcap_t 类型指针,后面的所有操作都要使用这个指针。

    char error_content[PCAP_ERRBUF_SIZE] = {0};	// 出错信息
    char *dev = pcap_lookupdev(error_content);	// 获取网络接口
    if(NULL == dev)
    {
    	printf(error_content);
    	exit(-1);
    }
     
    // 打开网络接口
    pcap_t * pcap_handle = pcap_open_live(dev, 1024, 1, 0, error_content);
    if(NULL == pcap_handle)
    {
    	printf(error_content);
    	exit(-1);
    }
    

    4、获取数据包
    const u_char *pcap_next(pcap_t *p, struct pcap_pkthdr *h);

    int pcap_loop(pcap_t *p,int cnt,pcap_handler callback,u_char *user );

    int pcap_dispatch(pcap_t * p, int cnt, pcap_handler callback, u_char * user);

    • const u_char *pcap_next(pcap_t *p, struct pcap_pkthdr *h);捕获一个网络数据包,收到一个数据包立即返回

    参数:
    p:pcap_open_live()返回的 pcap_t 类型的指针

    h:数据包头

    返回值:

    成功返回捕获数据包的地址,失败返回 NULL

    • pcap_pkthdr 类型的定义如下:
    struct pcap_pkthdr
    {
    	struct timeval ts; // 抓到包的时间
    	bpf_u_int32 caplen; // 表示抓到的数据长度
    	bpf_u_int32 len; // 表示数据包的实际长度
    }
    
    const unsigned char *p_packet_content = NULL; // 保存接收到的数据包的起始地址
    pcap_t *pcap_handle = NULL;
    struct pcap_pkthdr protocol_header;
     
    pcap_handle = pcap_open_live("eth0", 1024, 1, 0,NULL);
     
    p_packet_content = pcap_next(pcap_handle, &protocol_header); 
    //p_packet_content  所捕获数据包的地址
    		
    printf("Capture Time is :%s",ctime((const time_t *)&protocol_header.ts.tv_sec)); // 时间
    printf("Packet Lenght is :%d
    ",protocol_header.len);	// 数据包的实际长度
     
    // 分析以太网中的 源mac、目的mac
    struct ether_header *ethernet_protocol = NULL;
    unsigned char *p_mac_string = NULL;			// 保存mac的地址,临时变量
     
    ethernet_protocol = (struct ether_header *)p_packet_content;  //struct ether_header 以太网帧头部
     
    p_mac_string = (unsigned char *)ethernet_protocol->ether_shost;//获取源mac
    printf("Mac Source Address is %02x:%02x:%02x:%02x:%02x:%02x
    ",*(p_mac_string+0),*(p_mac_string+1),*(p_mac_string+2),*(p_mac_string+3),*(p_mac_string+4),*(p_mac_string+5));
     
    p_mac_string = (unsigned char *)ethernet_protocol->ether_dhost;//获取目的mac
    printf("Mac Destination Address is %02x:%02x:%02x:%02x:%02x:%02x
    ",*(p_mac_string+0),*(p_mac_string+1),*(p_mac_string+2),*(p_mac_string+3),*(p_mac_string+4),*(p_mac_string+5));
    

    -int pcap_loop(pcap_t *p,int cnt,pcap_handler callback,u_char *user ); 循环捕获网络数据包,直到遇到错误或者满足退出条件。每次捕获一个数据包就会调用 callback 指定的回调函数,所以,可以在回调函数中进行数据包的处理操作。

    参数:

    p:pcap_open_live()返回的 pcap_t 类型的指针。

    cnt:指定捕获数据包的个数,一旦抓到了 cnt 个数据包,pcap_loop 立即返回。如果是 -1,就会永无休止的捕获,直到出现错误。

    callback:回调函数,名字任意,根据需要自行起名。

    user:向回调函数中传递的参数。
    返回值:成功返回0,失败返回负数

    • callback 回调函数的定义:

    void callback(  u_char *userarg, const struct pcap_pkthdr * pkthdr, const u_char * packet )

    userarg:pcap_loop() 的最后一个参数,当收到足够数量的包后 pcap_loop 会调用callback 回调函数,同时将pcap_loop()的user参数传递给它

    pkthdr:是收到数据包的 pcap_pkthdr 类型的指针,和 pcap_next() 第二个参数是一样的。

    packet :收到的数据包数据

    if( pcap_loop(pcap_handle, -1, ethernet_protocol_callback, NULL) < 0 )
    {
    	perror("pcap_loop");
    }
     
    /*******************************回调函数************************************/
    void ethernet_protocol_callback(unsigned char *argument,const struct pcap_pkthdr *packet_heaher,const unsigned char *packet_content)
    {
    	unsigned char *mac_string;				//
    	struct ether_header *ethernet_protocol;
    	unsigned short ethernet_type;			//以太网类型
    	printf("----------------------------------------------------
    ");
    	printf("%s
    ", ctime((time_t *)&(packet_heaher->ts.tv_sec))); //转换时间
    	ethernet_protocol = (struct ether_header *)packet_content;
    	
    	mac_string = (unsigned char *)ethernet_protocol->ether_shost;//获取源mac地址
    	printf("Mac Source Address is %02x:%02x:%02x:%02x:%02x:%02x
    ",*(mac_string+0),*(mac_string+1),*(mac_string+2),*(mac_string+3),*(mac_string+4),*(mac_string+5));
    	
    	mac_string = (unsigned char *)ethernet_protocol->ether_dhost;//获取目的mac
    	printf("Mac Destination Address is %02x:%02x:%02x:%02x:%02x:%02x
    ",*(mac_string+0),*(mac_string+1),*(mac_string+2),*(mac_string+3),*(mac_string+4),*(mac_string+5));
    	
    	ethernet_type = ntohs(ethernet_protocol->ether_type);//获得以太网的类型
    	printf("Ethernet type is :%04x
    ",ethernet_type);
    	switch(ethernet_type)
    	{
    		case 0x0800:printf("The network layer is IP protocol
    ");break;//ip
    		case 0x0806:printf("The network layer is ARP protocol
    ");break;//arp
    		case 0x0835:printf("The network layer is RARP protocol
    ");break;//rarp
    		default:break;
    	}
    	usleep(800*1000);
    }
    
    
    • int pcap_dispatch(pcap_t * p, int cnt, pcap_handler callback, u_char * user);

    这个函数和 pcap_loop() 非常类似,只是在超过 to_ms 毫秒后就会返回( to_ms 是pcap_open_live() 的第4个参数 )

    5、释放网络接口void pcap_close(pcap_t *p);关闭 pcap_open_live() 打开的网络接口(即其返回值,pcap_t 类型指针),并释放相关资源。注意,操作完网络接口,应该释放其资源。

    参数:p:需要关闭的网络接口,pcap_open_live() 的返回值(pcap_t 类型指针)

    返回值:无

    // 打开网络接口
    pcap_t * pcap_handle = pcap_open_live("eth0", 1024, 1, 0, error_content);
    if(NULL == pcap_handle)
    {
    	printf(error_content);
    	exit(-1);
    }
     
    //// ……
    //// ……
     
    pcap_close(pcap_handle); //释放网络接口
    
    
    • 接收一个数据包:
    
    #include <stdio.h>
    #include <pcap.h>
    #include <arpa/inet.h>
    #include <time.h>
    #include <stdlib.h>
    struct ether_header
    {
    	unsigned char ether_dhost[6];	//目的mac
    	unsigned char ether_shost[6];	//源mac
    	unsigned short ether_type;		//以太网类型
    };
    #define BUFSIZE 1514
     
    int main(int argc,char *argv[])
    {
    	pcap_t * pcap_handle = NULL;
    	char error_content[100] = "";	// 出错信息
    	const unsigned char *p_packet_content = NULL;		// 保存接收到的数据包的起始地址
    	unsigned char *p_mac_string = NULL;			// 保存mac的地址,临时变量
    	unsigned short ethernet_type = 0;			// 以太网类型
    	char *p_net_interface_name = NULL;		// 接口名字
    	struct pcap_pkthdr protocol_header;
    	struct ether_header *ethernet_protocol;
     
    	//获得接口名
    	p_net_interface_name = pcap_lookupdev(error_content);
    	if(NULL == p_net_interface_name)
    	{
    		perror("pcap_lookupdev");
    		exit(-1);
    	}
    	
    	//打开网络接口
    	pcap_handle = pcap_open_live(p_net_interface_name,BUFSIZE,1,0,error_content);
    	p_packet_content = pcap_next(pcap_handle,&protocol_header);
    	
    	printf("------------------------------------------------------------------------
    ");
    	printf("capture a Packet from p_net_interface_name :%s
    ",p_net_interface_name);
    	printf("Capture Time is :%s",ctime((const time_t *)&protocol_header.ts.tv_sec));
    	printf("Packet Lenght is :%d
    ",protocol_header.len);
    	
    	/*
    	*分析以太网中的 源mac、目的mac
    	*/
    	ethernet_protocol = (struct ether_header *)p_packet_content;
    	p_mac_string = (unsigned char *)ethernet_protocol->ether_shost;//获取源mac
    	printf("Mac Source Address is %02x:%02x:%02x:%02x:%02x:%02x
    ",*(p_mac_string+0),*(p_mac_string+1),*(p_mac_string+2),*(p_mac_string+3),*(p_mac_string+4),*(p_mac_string+5));
    	p_mac_string = (unsigned char *)ethernet_protocol->ether_dhost;//获取目的mac
    	printf("Mac Destination Address is %02x:%02x:%02x:%02x:%02x:%02x
    ",*(p_mac_string+0),*(p_mac_string+1),*(p_mac_string+2),*(p_mac_string+3),*(p_mac_string+4),*(p_mac_string+5));
     
    	/*
    	*获得以太网的数据包的地址,然后分析出上层网络协议的类型
    	*/
    	ethernet_type = ntohs(ethernet_protocol->ether_type);
    	printf("Ethernet type is :%04x	",ethernet_type);
    	switch(ethernet_type)
    	{
    		case 0x0800:printf("The network layer is IP protocol
    ");break;//ip
    		case 0x0806:printf("The network layer is ARP protocol
    ");break;//arp
    		case 0x0835:printf("The network layer is RARP protocol
    ");break;//rarp
    		default:printf("The network layer unknow!
    ");break;
    	}
    	
    	pcap_close(pcap_handle);
    	return 0;
    }
    
    
    • 接收多个数据包:
    #include <stdio.h>
    #include <pcap.h>
    #include <arpa/inet.h>
    #include <time.h>
    #include <stdlib.h>
     
    #define BUFSIZE 1514
     
    struct ether_header
    {
    	unsigned char ether_dhost[6];	//目的mac
    	unsigned char ether_shost[6];	//源mac
    	unsigned short ether_type;		//以太网类型
    };
     
    /*******************************回调函数************************************/
    void ethernet_protocol_callback(unsigned char *argument,const struct pcap_pkthdr *packet_heaher,const unsigned char *packet_content)
    {
    	unsigned char *mac_string;				//
    	struct ether_header *ethernet_protocol;
    	unsigned short ethernet_type;			//以太网类型
    	printf("----------------------------------------------------
    ");
    	printf("%s
    ", ctime((time_t *)&(packet_heaher->ts.tv_sec))); //转换时间
    	ethernet_protocol = (struct ether_header *)packet_content;
    	
    	mac_string = (unsigned char *)ethernet_protocol->ether_shost;//获取源mac地址
    	printf("Mac Source Address is %02x:%02x:%02x:%02x:%02x:%02x
    ",*(mac_string+0),*(mac_string+1),*(mac_string+2),*(mac_string+3),*(mac_string+4),*(mac_string+5));
    	mac_string = (unsigned char *)ethernet_protocol->ether_dhost;//获取目的mac
    	printf("Mac Destination Address is %02x:%02x:%02x:%02x:%02x:%02x
    ",*(mac_string+0),*(mac_string+1),*(mac_string+2),*(mac_string+3),*(mac_string+4),*(mac_string+5));
    	
    	ethernet_type = ntohs(ethernet_protocol->ether_type);//获得以太网的类型
    	printf("Ethernet type is :%04x
    ",ethernet_type);
    	switch(ethernet_type)
    	{
    		case 0x0800:printf("The network layer is IP protocol
    ");break;//ip
    		case 0x0806:printf("The network layer is ARP protocol
    ");break;//arp
    		case 0x0835:printf("The network layer is RARP protocol
    ");break;//rarp
    		default:break;
    	}
    	usleep(800*1000);
    }
     
    int main(int argc, char *argv[])
    {
    	char error_content[100];	//出错信息
    	pcap_t * pcap_handle;
    	unsigned char *mac_string;				
    	unsigned short ethernet_type;			//以太网类型
    	char *net_interface = NULL;					//接口名字
    	struct pcap_pkthdr protocol_header;
    	struct ether_header *ethernet_protocol;
    	
    	//获取网络接口
    	net_interface = pcap_lookupdev(error_content);
    	if(NULL == net_interface)
    	{
    		perror("pcap_lookupdev");
    		exit(-1);
    	}
     
    	pcap_handle = pcap_open_live(net_interface,BUFSIZE,1,0,error_content);//打开网络接口
    		
    	if(pcap_loop(pcap_handle,-1,ethernet_protocol_callback,NULL) < 0)
    	{
    		perror("pcap_loop");
    	}
    	
    	pcap_close(pcap_handle);
    	return 0;
    }
    

    过滤数据包 (过滤数据包的方法主要都是基于 BSD Packet Filter( BPF ) 结构的。libpcap 利用 BPF 来过滤数据包。)

    • 设置过滤条件
      BPF 使用一种类似于汇编语言的语法书写过滤表达式,不过 libpcap 和 tcpdump 都把它封装成更高级且更容易的语法了,具体可以通过 man tcpdump查看:
    src host 192.168.1.177 //只接收源 ip 地址是 192.168.1.177 的数据包
    
    dst port 80 //只接收 tcp/udp 的目的端口是 80 的数据包
    
    not tcp //只接收不使用 tcp 协议的数据包
    
    tcp[13] == 0x02 and (dst port 22 or dst port 23) //只接收 SYN 标志位置位且目标端口是 22 或 23 的数据包( tcp 首部开始的第 13 个字节)
    
    icmp[icmptype] == icmp-echoreply or icmp[icmptype] == icmp-echo //只接收 icmp 的 ping 请求和 ping 响应的数据包
    
    ehter dst 00:e0:09:c1:0e:82 //只接收以太网 mac 地址是 00:e0:09:c1:0e:82 的数据包
    
    ip[8] == 5 //只接收 ip 的 ttl=5 的数据包(ip首部开始的第8个字节)
    
    • 应用 BPF 过滤规则

    int pcap_setfilter( pcap_t * p,  struct bpf_program * fp );应用 BPF 过滤规则,简单理解为让过滤生效

    参数:

    p:pcap_open_live() 返回的 pcap_t 类型的指针

    fp:pcap_compile() 的第二个参数

    返回值:成功返回 0,失败返回 -1

    下面的程序演示了如何过滤数据包,我们只接收目的端口是 80 的数据包:

    
    #include <pcap.h>
    #include <time.h>
    #include <stdlib.h>
    #include <stdio.h>
     
    void getPacket(u_char * arg, const struct pcap_pkthdr * pkthdr, const u_char * packet)
    {
      int * id = (int *)arg;
      
      printf("id: %d
    ", ++(*id));
      printf("Packet length: %d
    ", pkthdr->len);
      printf("Number of bytes: %d
    ", pkthdr->caplen);
      printf("Recieved time: %s", ctime((const time_t *)&pkthdr->ts.tv_sec)); 
      
      int i;
      for(i=0; i<pkthdr->len; ++i)
      {
        printf(" %02x", packet[i]);
        if( (i + 1) % 16 == 0 )
        {
          printf("
    ");
        }
      }
      
      printf("
    
    ");
    }
     
    int main()
    {
      char errBuf[PCAP_ERRBUF_SIZE], * devStr;
      
      /* get a device */
      devStr = pcap_lookupdev(errBuf);
      
      if(devStr)
      {
        printf("success: device: %s
    ", devStr);
      }
      else
      {
        printf("error: %s
    ", errBuf);
        exit(1);
      }
      
      /* open a device, wait until a packet arrives */
      pcap_t * device = pcap_open_live(devStr, 65535, 1, 0, errBuf);
      
      if(!device)
      {
        printf("error: pcap_open_live(): %s
    ", errBuf);
        exit(1);
      }
      
      /* construct a filter */
      struct bpf_program filter;
      pcap_compile(device, &filter, "dst port 80", 1, 0);
      pcap_setfilter(device, &filter);
      
      /* wait loop forever */
      int id = 0;
      pcap_loop(device, -1, getPacket, (u_char*)&id);
      
      pcap_close(device);
     
      return 0;
    }
    
    

    二、2)找一个网站或者搭建一个本地网站,登录网站,并嗅探,分析出账号和密码,结果截图1-2张。(3分)(可以用邮箱、各类博客、云班课,只能分析自己的账号,严禁做各类攻击,否则后果自负。)

    首先,启动Wireshark,进入本地一个网站(http://www.wshangq.com/ ),注册并登录。

    用dig查看一下该网站的IP

    查看Wireshark,使用命令http.request.method== "POST"筛选,可以完完整整的看到我的用户名和密码。。。(密码千万不要设一个,否则不法分子撞库破解后可能会干坏事哦!)

    三、加分项2分:注意本次加分项不加到额外10分里,加到本次实验中。例如,本次实验7分,算上加分可得9分。(抓取手机App的登录过程数据包,分析账号和密码。可以用邮箱、各类博客、云班课,只能分析自己的账号,严禁做各类攻击,否则后果自负。)

    此次,我用手机连接电脑热点,登录云班课APP时,Wireshark捕获到的结果,同样用http.request.method== "POST筛选,发现我的用户名和密码是一些乱七八糟的字符,但是他一定是经过加密之后结果,也就是说根据这些只要我费点时间把他一一解密,完全是可以得到用户名和密码的!哇偶

    抱着试一试的心情,我打开了某加密算法反向查询网站(https://www.cmd5.com/ ), 本来打算自己查查看,最后没查到。。。(下面是它支持的密文类型及格式)

    温馨提示:以后千万不要连接陌生WLAN,有可能会使不法分子有机可乘!!

    四、参考文献

    使用WireShark嗅探网站登陆密码
    wireshark密码嗅探侵入后台管理系统
    wireshark的基本学习
    Linux 网络编程—— libpcap 详解

  • 相关阅读:
    Power BI for Office 365(八)共享查询
    Power BI for Office 365(七) Power BI站点
    Power BI for Office 365(六)Power Map简介
    Power BI for Office 365(五)Power View第二部分
    Power BI for Office 365(四)Power View第一部分
    Power BI for Office 365(三)Power Pivot
    Power BI for Office 365(二)Power Query
    java 继承、重载、重写与多态
    Android 热修复方案Tinker(一) Application改造
    阿里最新热修复Sophix与QQ超级补丁和Tinker的实现与总结
  • 原文地址:https://www.cnblogs.com/dsqblog/p/12589595.html
Copyright © 2011-2022 走看看