信息安全 SEED Lab10 Packet Sniffing and Spoofing Lab

这个实验是关于数据包的嗅探与伪造

1. Task Set 1

这部分主要是利用工具来嗅探数据包,这里用的是 scapy。 可以用下面的命令进行安装。

sudo pip3 install scapy

简单测试一下,构造了一个IP数据包并打印其的一些信息

[07/02/21]seed@VM:~/.../Lab10$ sudo python3
Python 3.5.2 (default, Nov 17 2016, 17:05:23) 
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from scapy.all import *
>>> a = IP()
>>> a.show()
###[ IP ]### 
  version   = 4
  ihl       = None
  tos       = 0x0
  len       = None
  id        = 1
  flags     = 
  frag      = 0
  ttl       = 64
  proto     = hopopt
  chksum    = None
  src       = 127.0.0.1
  dst       = 127.0.0.1
  \options   \

Task 1.1 嗅探数据包

下面是使用 scapy来嗅探数据包的一个例子

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

def print_pkt(pkt):
    pkt.show()

pkt = sniff(filter="icmp",prn=print_pkt)
Task 1.1A

先使用 chmod a+x sniffer.py 添加执行权限
先使用root权限运行上面的程序 sudo ./sniffer.py, 结果如下,可以看到其成功嗅探到了不同协议的数据包,图中只包括ICMP包。
在这里插入图片描述
然后使用普通权限运行该程序 ./sniffer.py。结果如下,可以看到报错了,提示无权限。
在这里插入图片描述
这说明嗅探包是一件拥有高权限才能做的事情,没有高权限,系统是不让你嗅探数据包的。

Task 1.1B

一般在嗅探包时我们只对特定类型的数据包感兴趣,所以我们需要对数据包进行一些过滤。scapy的过滤机制使用BPF的语法,这部分我们需要实现几个过滤的方法。

  1. 只捕捉ICMP数据包

    上面的代码就是只捕捉icmp的数据包,略修改如下:

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

def print_pkt(pkt):
    return pkt.summary()

pkt = sniff(filter="icmp",prn=print_pkt)
print(pkt)

运行结果如下,可以看到捕获到了7个ICMP数据包
在这里插入图片描述

  1. 只捕捉来自特定IP,且目标端口号为23的TCP数据包
    查看自己的IP地址如下:
    在这里插入图片描述
    这里随意拿个IP来测试, 我们使用 10.0.2.11 , 嗅探代码如下:
#!/usr/bin/python3
from scapy.all import *

def print_pkt(pkt):
    return pkt.summary()

pkt = sniff(filter="tcp and src host 10.0.2.11 and dst port 23",prn=print_pkt)
print(pkt)

发送数据包的代码如下:

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

ip = IP()
ip.src = "10.0.2.11"
ip.dst = "10.0.2.1"
tcp = TCP()
tcp.dport = 23
send(ip/tcp)

运行嗅探的程序,再运行发送数据包的程序(可以多试几次), 结果如下:
在这里插入图片描述
3. 捕捉来自或发送到特定子网的数据包
这里我们使用的子网为128.230.0.0/16.嗅探代码如下:

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

def print_pkt(pkt):
    return pkt.summary()

pkt = sniff(filter="net 128.230.0.0/16",prn=print_pkt)
print(pkt)

发送包的代码如下:

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

ip = IP()
ip.src = "10.0.2.11"
ip.dst = "128.230.0.1"
tcp = TCP()
tcp.dport = 23
send(ip/tcp)
ip.src = "128.230.0.1"
ip.dst = "10.0.2.11"
send(ip/tcp)

嗅探结果如下,可以看到嗅探到了发送给子网128.230.0.0/16 和 该子网发送过来的数据包
在这里插入图片描述

Task 1.2

这部分主要是伪造任意的IP地址发IP包,这里我们用的是ICMP协议,使用的IP地址为 10.0.2.3 , 注意 在task 1.1B2中,我们查看了自己的IP地址为10.0.2.4,也就是这里我们伪造成ip地址为 10.0.2.3 进行发包。

先启动wireshark,选择网卡,再运行发包的程序

发送的代码如下:

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

ip = IP()
ip.src = "10.0.2.3"
ip.dst = "128.230.0.1"
icmp = ICMP()
send(ip/icmp)

在wireshark中可看到记录,伪造的包有了回复。
在这里插入图片描述

Task 1.3

这部分主要是实现traceroute来估计本机到指定IP之间的路由器的个数。

代码如下:

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


def traceroute(target, minttl=1, maxttl=30, dport=80):
    print("target: %s(port=%s)" % (target, dport))
    ans, unans = sr(IP(dst=target, ttl=(minttl,maxttl),id=RandShort())/TCP(flags=0x2, dport=dport), timeout=10)
    for snd,rcv in ans:
        print(snd.ttl, rcv.src)

if __name__ == '__main__':
    if len(sys.argv) <= 1:
        traceroute("baidu.com")
    else:
        traceroute(sys.argv[1])

运行效果如下, 可以看到打印除了不同TTL对应的IP
在这里插入图片描述
注意如果出现,没有回复包,或者回复包过少,可能与环境优点关系,可以尝试VPS运行

Task 1.4

这部分主要是准备两个在同一个局域网的虚拟机,一个机器ping任意IP x,另一个机器伪造ICMP回复请求,使得其有回复,而IP x所对应的机器可能根本不存在。

我们准备的A机器 IP 地址为10.0.2.4,B机器IP地址为10.0.2.5. 我们用A机器去发送请求,B机器伪造响应。

代码如下:

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

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

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

测试ping baidu.com结果如下,ttl=64为我们伪造的回复包,ttl=52的为正常的相应包。
在这里插入图片描述
在断网情况下,仍然可以ping通其他网段的IP
在这里插入图片描述

2. Task Set 2

这部分主要是使用pcap库写程序来嗅探和伪造包

Task 2.1

Task 2.1A

这部分主要是写一个打印捕获的包的源IP和目的IP地址。

代码如下:

#include <pcap.h>
#include <stdio.h>
#include <arpa/inet.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;     /* protocol 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
};

void got_packet(u_char *args, const struct pcap_pkthdr *header,
                              const u_char *packet)
{
  struct ethheader *eth = (struct ethheader *)packet;

  if (ntohs(eth->ether_type) == 0x0800) { // 0x0800 is IP type
    struct ipheader * ip = (struct ipheader *)
                           (packet + sizeof(struct ethheader)); 

    printf("       From: %s\n", inet_ntoa(ip->iph_sourceip));   
    printf("         To: %s\n", inet_ntoa(ip->iph_destip));    

    /* determine protocol */
    switch(ip->iph_protocol) {                                 
        case IPPROTO_TCP:
            printf("   Protocol: TCP\n\n");
            return;
        case IPPROTO_UDP:
            printf("   Protocol: UDP\n\n");
            return;
        case IPPROTO_ICMP:
            printf("   Protocol: ICMP\n\n");
            return;
        default:
            printf("   Protocol: others\n\n");
            return;
    }
  }
}

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

  // Step 1: Open live pcap session on NIC with name enp0s3
  handle = pcap_open_live("enp0s3", 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;
}

运行,并尝试ping baidu.com,可以看到发送的包出现在结果中
在这里插入图片描述

Q1: 描述在你的嗅探程序中的库函数的调用
A1: 主要就是第一步,启动pcap监听网卡,第二步就是编译BPF过滤器并设置过滤器,第三步就是设置嗅探的处理函数,最后关闭嗅探即可。

**Q2: 为什么需要root权限才能运行嗅探程序?不使用root权限运行该程序会在哪里报错?
A2: 嗅探数据包是一个高权限的操作,因为涉及到隐私,安全相关问题。如果普通用户也能嗅探数据包,那么他就能窃取别人的隐私,甚至盗取账号密码等等。不使用root权限运行该程序。对比如下
在这里插入图片描述
可以看到在没有权限时第一步监听网卡就失败了。

**Q3: 打开嗅探程序的混杂模式。打开和关闭这个模式有什么区别?
A3: 使用混杂模式可以监听所在网段下其他机器的数据包,关闭则不能。如下所示,打开混杂模式,监听到了本网段另一机器 10.0.2.5 ping baidu.com的数据包,关闭后则嗅探不到。
在这里插入图片描述

Task 2.1B

这部分主要是写一些过滤器。这部分还是复用 task 2.1A的代码,只是修改其中的过滤器而已

  1. 只捕捉两个特定主机之间的ICMP包

    使用的过滤器为 icmp and src host 10.0.2.4 and dst host 10.0.2.5, 只捕捉从 10.0.2.4 发送到 10.0.2.5的ICMP包。结果如下,可以看到全是从 10.0.2.4 发送到 10.0.2.5的ICMP包,没有其他类型的包。
    在这里插入图片描述

  2. 捕捉目的端口在10到100之间的TCP包

    使用的过滤器为 tcp and dst portrange 10-100, 只捕捉从 10.0.2.4 发送到 10.0.2.5的ICMP包。结果如下,可以看到全是从 10.0.2.4 发送到 10.0.2.5的ICMP包,没有其他类型的包。
    结果如下,用浏览器访问baidu.com的包出现在结果中,用浏览器访问baidu.com:111的包没有出现在结果中。
    在这里插入图片描述

Task 2.1C

这部分是用嗅探去捕捉telent协议中的密码。我们使用scapy会更方便一些。
代码如下:

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

def print_pkt(pkt):
    pkt.show()

print(sniff(filter="tcp port 23", prn=print_pkt))

然后 使用telnet 10.0.2.5 ,并输入账户密码远程登录。嗅探到的密码如下,其分成了几个包发送,如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
所以输入的密码就是dees。获得telnet输入的用户名同理。

Task 2.2

这部分主要是伪造包。用到的一些代码文件如下:
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
};

/* 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
};

/* 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 */
};

/* 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];
};

checksum.c内容如下:

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <arpa/inet.h>

#include "myheader.h"


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);
}

/****************************************************************
  TCP checksum is calculated on the pseudo header, which includes
  the TCP header and data, plus some part of the IP header.
  Therefore, we need to construct the pseudo header first.
*****************************************************************/


unsigned short calculate_tcp_checksum(struct ipheader *ip)
{
   struct tcpheader *tcp = (struct tcpheader *)((u_char *)ip +
                            sizeof(struct ipheader));

   int tcp_len = ntohs(ip->iph_len) - sizeof(struct ipheader);

   /* pseudo tcp header for the checksum computation */
   struct pseudo_tcp p_tcp;
   memset(&p_tcp, 0x0, sizeof(struct pseudo_tcp));

   p_tcp.saddr  = ip->iph_sourceip.s_addr;
   p_tcp.daddr  = ip->iph_destip.s_addr;
   p_tcp.mbz    = 0;
   p_tcp.ptcl   = IPPROTO_TCP;
   p_tcp.tcpl   = htons(tcp_len);
   memcpy(&p_tcp.tcp, tcp, tcp_len);

   return  (unsigned short) in_cksum((unsigned short *)&p_tcp,
                                     tcp_len + 12);
}

spoof.c内容如下:

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <arpa/inet.h>

#include "myheader.h"

/*************************************************************
  Given an IP packet, send it out using a raw socket.
**************************************************************/
void send_raw_ip_packet(struct ipheader* ip)
{
    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);
}
Task 2.2A

这部分主要是伪造IP包。这里伪造是UDP包, 代码如下:

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <arpa/inet.h>

#include "myheader.h"

void   send_raw_ip_packet (struct ipheader* ip);

/******************************************************************
  Spoof a UDP packet using an arbitrary source IP Address and port
*******************************************************************/
int main() {
   char buffer[1500];

   memset(buffer, 0, 1500);
   struct ipheader *ip = (struct ipheader *) buffer;
   struct udpheader *udp = (struct udpheader *) (buffer +
                                          sizeof(struct ipheader));

   /*********************************************************
      Step 1: Fill in the UDP data field.
    ********************************************************/
   char *data = buffer + sizeof(struct ipheader) +
                         sizeof(struct udpheader);
   const char *msg = "Hello Server!\n";
   int data_len = strlen(msg);
   strncpy (data, msg, data_len);

   /*********************************************************
      Step 2: Fill in the UDP header.
    ********************************************************/
   udp->udp_sport = htons(12345);
   udp->udp_dport = htons(9090);
   udp->udp_ulen = htons(sizeof(struct udpheader) + data_len);
   udp->udp_sum =  0; /* Many OSes ignore this field, so we do not
                         calculate it. */

   /*********************************************************
      Step 3: Fill in the IP header.
    ********************************************************/
   ip->iph_ver = 4;
   ip->iph_ihl = 5;
   ip->iph_ttl = 20;
   ip->iph_sourceip.s_addr = inet_addr("1.1.1.1");
   ip->iph_destip.s_addr = inet_addr("8.8.8.8");
   ip->iph_protocol = IPPROTO_UDP; // The value is 17.
   ip->iph_len = htons(sizeof(struct ipheader) +
                       sizeof(struct udpheader) + data_len);

   /*********************************************************
      Step 4: Finally, send the spoofed packet
    ********************************************************/
   send_raw_ip_packet (ip);

   return 0;
}

使用gcc -o task22A task22A.c spoof.c -lpcap编译,sudo ./task22A运行,查看后台wireshark,可以看到我们伪造的UDP包
在这里插入图片描述

Task 2.2B

这部分是伪造ICMP Echo请求。伪造的代码如下, 其中源IP10.0.2.5是局域网内另一个虚拟机的IP,

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <arpa/inet.h>

#include "myheader.h"

unsigned short in_cksum (unsigned short *buf, int length);
void send_raw_ip_packet(struct ipheader* ip);

/******************************************************************
  Spoof an ICMP echo request using an arbitrary source IP Address
*******************************************************************/
int main() {
   char buffer[1500];

   memset(buffer, 0, 1500);

   /*********************************************************
      Step 1: Fill in the ICMP header.
    ********************************************************/
   struct icmpheader *icmp = (struct icmpheader *)
                             (buffer + sizeof(struct ipheader));
   icmp->icmp_type = 8; //ICMP Type: 8 is request, 0 is reply.

   // Calculate the checksum for integrity
   icmp->icmp_chksum = 0;
   icmp->icmp_chksum = in_cksum((unsigned short *)icmp,
                                 sizeof(struct icmpheader));

   /*********************************************************
      Step 2: Fill in the IP header.
    ********************************************************/
   struct ipheader *ip = (struct ipheader *) buffer;
   ip->iph_ver = 4;
   ip->iph_ihl = 5;
   ip->iph_ttl = 20;
   ip->iph_sourceip.s_addr = inet_addr("10.0.2.5");
   ip->iph_destip.s_addr = inet_addr("8.8.8.8");
   ip->iph_protocol = IPPROTO_ICMP;
   ip->iph_len = htons(sizeof(struct ipheader) +
                       sizeof(struct icmpheader));

   /*********************************************************
      Step 3: Finally, send the spoofed packet
    ********************************************************/
   send_raw_ip_packet (ip);

   return 0;
}

其中用到额外的文件,

使用gcc -o task22B task22B.c spoof.c checksum.c -lpcap 进行编译, sudo ./task22B运行,查看后台的wireshark,如下:
,可以看到我们发送的源IP为10.0.2.5, 目的IP为8.8.8.8的ICMP包,并且还有回复
在这里插入图片描述
Q4: 能把IP包的长度设置为任意数值,而不管实际的包的大小吗?
A4: 将代码中设置长度该成下面的代码,运行可知其为28B,修改长度为10B,wireshark没有捕捉到包,说明没有发出去。

ip->iph_len = htons(10);
    printf("iph_len: %d\n", sizeof(struct ipheader) +
                       sizeof(struct icmpheader));

修改成1000B,结果如下,可以看到正常发送出去,且收到了相应。说明可以调大length,不能调小length。
在这里插入图片描述

Q5: 使用 raw socket 编程, 我们要计算IP头部的checksum吗?
A5: 不用计算IP头部的checksum,但是需要计算ICMP头部的checksum。

Q6: 为什么使用raw socket 编程需要root权限?没有root权限执行时程序会在哪里报错?
**A6:**因为能任意读取发送包意味着很大的安全风险,所以需要root权限。使用普通权限运行结果如下:
在这里插入图片描述
可以看到返回的socket 描述符为-1, 说明创建raw socket失败了。

Task 2.3

准备两个在同一个局域网的虚拟机,这部分主要是同时嗅探和伪造包,实现一个机器ping任意IP x,另一个机器伪造ICMP回复请求,使得其有回复,而IP x所对应的机器可能根本不存在。

代码如下:

#include <pcap.h>
#include <stdio.h>
#include <arpa/inet.h>
#include "myheader.h"


void got_packet(u_char *args, const struct pcap_pkthdr *header,
                              const u_char *packet)
{
  struct ethheader *eth = (struct ethheader *)packet;

  if (ntohs(eth->ether_type) == 0x0800) { // 0x0800 is IP type
    struct ipheader * ip = (struct ipheader *)
                           (packet + sizeof(struct ethheader));

    printf("From: %s ", inet_ntoa(ip->iph_sourceip));   
    printf("To: %s ", inet_ntoa(ip->iph_destip));
    if (ip->iph_protocol == IPPROTO_ICMP)
        printf("protocal: ICMP\n");
    else
        printf("protocal: Others\n");
    
    struct icmpheader *icmp_pkt = (struct icmpheader *)(packet + sizeof(struct ethheader)
                                                               + sizeof(struct ipheader));

    if (ip->iph_protocol == IPPROTO_ICMP) {

        char buffer[1500];
        memset(buffer, 0, 1500);

        /*********************************************************
             Step 1: 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;
        printf("icmp id: %d, seq: %d\n", ntohs(icmp_pkt->icmp_id), ntohs(icmp_pkt->icmp_seq));

        // Calculate the checksum for integrity
        icmp->icmp_chksum = 0;
        icmp->icmp_chksum = in_cksum((unsigned short *)icmp,
                                        sizeof(struct icmpheader));

        /*********************************************************
             Step 2: Fill in the IP header.
            ********************************************************/
        struct ipheader *ipp = (struct ipheader *) buffer;
        ipp->iph_ver = 4;
        ipp->iph_ihl = 5;
        ipp->iph_ttl = 64;
        ipp->iph_sourceip.s_addr = ip->iph_destip.s_addr;
        ipp->iph_destip.s_addr = ip->iph_sourceip.s_addr;
        ipp->iph_protocol = IPPROTO_ICMP;
        ipp->iph_len = htons(sizeof(struct ipheader) +
                            sizeof(struct icmpheader));
        printf("send tt source :%s\n", inet_ntoa(ipp->iph_sourceip));
        printf("send tt dest: %s\n", inet_ntoa(ipp->iph_destip));

        /*********************************************************
             Step 3: Finally, send the spoofed packet
            ********************************************************/
        // icmp_pkt->icmp_type = 0;
        // icmp_pkt->icmp_code = 0;
        // icmp->icmp_chksum = 0;
        // icmp->icmp_chksum = in_cksum((unsigned short *)icmp,
        //                                 sizeof(struct icmpheader));
        send_raw_ip_packet (ipp);

    }
  }
}

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 enp0s3
  handle = pcap_open_live("enp0s3", 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;
}

使用 gcc -o task23 task23.c checksum.c spoof.c -lpcap编译程序,sudo ./task23运行
关闭网络,使用另一台机器ping 1.1.1.1,此机器运行上面的程序,结果如下:
在这里插入图片描述
程序输出如下:
在这里插入图片描述
要注意的是,程序中使用的inet_ntoa函数以字符串形式返回ip地址,该字符串存在函数内部的静态区域,下一次调用会刷新,之前的结果将会失效。

撒花完结。

  • 14
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值