从入门到入土:[SEED-Lab]- Packet Sniffing and Spoofing Lab

2023-11-09

此博客仅用于记录个人学习进度,学识浅薄,若有错误观点欢迎评论区指出。欢迎各位前来交流。(部分材料来源网络,若有侵权,立即删除)
本人博客所有文章纯属学习之用,不涉及商业利益。不合适引用,自当删除!
若被用于非法行为,与我本人无关

实验环境

  • seed-ubuntu 20.04

PDF文件

实验步骤

环境配置

Labsetup

传送门

  • 解压后
    在这里插入图片描述

  • 导入虚拟机环境中

  • 关于docker的build和up就轻车熟路了

  • 先看看PDF的任务吧

操作步骤

  • 包嗅探和欺骗是网络安全中的两个重要概念;它们是网络通信中 的两大威胁。能够理解这两种威胁对于理解网络中的安全措施至关重 要。有许多包嗅探和欺骗工具,如 Wireshark、Tcpdump、Netwox 等。 其中一些工具被安全专家以及攻击者广泛使用。能够使用这些工具对 学生来说很重要,但对于网络安全课程的学生来说,更重要的是了解 这些工具是如何工作的,即包嗅探和欺骗是如何在软件中实现的。 本实验的目标是让学生掌握大多数嗅探和欺骗工具的基本技术。 学生们将使用一些简单的嗅探和欺骗程序,阅读它们的源代码,修改 它们,并最终对这些程序的技术方面有深入的了解。在本实验结束时, 学生应该能够编写自己的嗅探和欺骗程序。
  • 数据包嗅探和欺骗是网络安全中的两个重要概念;它们是网络通信中的两个主要威胁。能够理解这两种威胁对于理解网络中的安全措施至关重要。有许多数据包嗅探和欺骗工具,如线鲨,Tcpdump,Netwox,Scapy等。其中一些工具已被安全专家和攻击者广泛使用。能够使用这些工具对学生来说很重要,但对于网络安全课程中的学生来说,更重要的是了解这些工具是如何工作的,即数据包嗅探和欺骗是如何在软件中实现的。这个实验室的目标有两个方面:学习使用这些工具和理解这些工具背后的技术。对于第二个目标,学生将编写简单的嗅探器和欺骗程序,并获得一个深入的了解这些程序的技术方面。本实验室涵盖以下主题:
  • How the sniffing and spoofing work
  • Packet sniffing using the pcap library and Scapy
  • Packet spoofing using raw socket and Scapy
  • Manipulating packets using Scapy

Lab Task Set 1: Using Scapy to Sniff and Spoof Packets

  • 许多工具可以用来做嗅探和欺骗,但其中大多数只提供固定的功能。Scapy是不同的:它不仅可以作为一个工具,还可以作为一个构建块来构建其他的嗅探和欺骗工具,也就是说,我们可以将Scapy功能集成到我们自己的程序中。在这组任务中,我们将对每个任务使用Scapy。要使用Scapy,我们可以编写一个Python程序,然后使用Python执行这个程序。请参阅下面的示例。我们应该使用根权限运行Python,因为欺骗数据包需要该特权。在程序的开始(第➀行),我们应该导入所有的Scapy的模块。
Task 1.1: Sniffing Packets
  • 安装并启动docker

在这里插入图片描述

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

在这里插入图片描述

task1.1A
  • 下面是使用 scapy来嗅探数据包的一个例子:
  • 代码:
    在这里插入图片描述
  • 代码简单就上图了
  • 先使用如下命令添加执行权限:
chmod a+x sniffer.py 

在这里插入图片描述

  • ifconfig查看本机IP
    在这里插入图片描述
  • 手贱PING一下

在这里插入图片描述

  • 先使用root权限运行上面的程序 sudo ./sniffer.py, 结果如下,可以看到其成功嗅探到了不同协议的数据包,图中只包括ICMP包。
    在这里插入图片描述在这里插入图片描述
  • 然后使用普通权限运行该程序 ./sniffer.py。结果如下,可以看到报错了,提示无权限。
    在这里插入图片描述
  • 这说明嗅探包是一件拥有高权限才能做的事情,没有高权限,系统是不让你嗅探数据包的。
task1.1B
  • 一般在嗅探包时我们只对特定类型的数据包感兴趣,所以我们需要对数据包进行一些过滤。scapy的过滤机制使用BPF的语法,这部分我们需要实现几个过滤的方法。
  • 通常,当我们嗅探数据包时,我们只对某些类型的数据包感兴趣。我们可以通过在嗅探中设置过滤器来实现这一点。Scapy的过滤器使用BPF(伯克利数据包过滤器)语法;你可以找到SBPF手册从互联网上提供。请设置以下过滤器,并再次演示您的嗅探器程序(每个过滤器应单独设置)
  • 仅捕获ICMP包捕获来自特定IP和目标端口号为23的任何TCP包。•捕获数据包来自或转到一个特定的子网。您可以选择任何子网,如128.230.0.0/16;您不应该选择虚拟机连接到的子网。
  • 只捕捉ICMP数据包,代码修改如下:
    在这里插入图片描述
  • 手再PING试一下

在这里插入图片描述

  • 运行结果如下,可以看到捕获到了ICMP数据包:
    在这里插入图片描述
  • 只捕捉来自特定IP,且目标端口号为23的TCP数据包,查看自己的IP地址如下:
    在这里插入图片描述
  • 本机ip地址:10.0.2.1
  • 设定一个ip地址:10.0.2.2
  • 创建发送数据包的代码:datapak.py、并指定tcp端口是23
  • 修改sniffer.py文件:
    在这里插入图片描述
  • 运行

在这里插入图片描述

  • 捕获了前三次发的包

在这里插入图片描述

  • 捕获来自或去往特定子网的数据包。您可以选择任何子网,如128 . 230 . 0 . 0/16;您不应该选择虚拟机所连接的子网
    修改嗅探的过滤条件:
    在这里插入图片描述
#!/usr/bin/python3
from scapy.all import *

ip = IP()
ip.src ="10.0.2.4"
ip.dst ="192.169.0.1"

tcp=TCP()
tcp.dport =23
send(ip/tcp)
  • 修改datapak.py文件:
    在这里插入图片描述
    在这里插入图片描述
  • 嗅探结果如下:
    在这里插入图片描述
Task 1.2: Spoofing ICMP Packets
  • 作为一个数据包欺骗工具,Scapy允许我们将IP数据包的字段设置为任意值。此任务的目的是用任意的源IP地址来欺骗IP数据包。我们将欺骗ICMP回波请求包,并将它们发送到同一网络上的另一个虚拟机。我们将使用线鲨来观察我们的请求是否会被接收人接受。如果它被接受,一个回波回复包将被发送到欺骗的IP地址。下面的代码展示了如何欺骗ICMP数据包的一个示例。
>>> from scapy.all import *
>>> a = IP()>>> a.dst =10.0.2.3’ ➁
>>> b = ICMP()>>> p = a/b ➃
>>> send(p).
Sent 1 packets.
  • 在上面的代码中,行➀从IP类创建一个IP对象;为每个IP头字段定义一个类属性。我们可以使用ls(a)或ls(IP)来查看所有的属性名称/值。我们也可以使用。show()和IP.show()来这样做。第➁行显示了如何设置目标IP地址字段。如果未设置字段,则将使用默认值。
  • 行➂创建了一个ICMP对象。默认类型是echo请求。在第➃行中,我们将a和b堆叠在一起以形成一个新对象。/操作符被IP类重载,因此它不再表示划分;相反,它意味着将b添加到a作为a的有效负载字段,并相应地修改a的字段。因此,我们得到了一个表示ICMP数据包的新对象。我们现在可以使用行➄中发送()发送这个包。请对示例代码进行任何必要的更改,然后证明您可以用任意的源IP地址欺骗ICMP回波请求包。
  • 安装wireshark:
sudo apt-get update
sudo apt-get install wireshark

在这里插入图片描述

  • 启动wireshark:
  • sudo wireshark:(root权限下、报错忽略)
  • 准备抓包:

在这里插入图片描述

  • 运行发包程序:
#!/usr/bin/python3
from scapy.all import *

ip = IP()
ip.src ="10.0.2.4"
ip.dst ="192.169.0.1"

icmp=ICMP()
send(ip/icmp)

在这里插入图片描述
在这里插入图片描述

Task 1.3: Traceroute
  • 此任务的目的是使用Scapy来估计虚拟机和选定目的地之间的路由器数量方面的距离。这基本上是由跟踪工具实现的。在这个任务中,我们将编写我们自己的工具。这个想法非常简单:只需发送一个数据包(任何类型)到目的地,首先将其实时时间(TTL)字段设置为1。这个数据包将被第一个路由器丢弃,该路由器将向我们发送一个ICMP错误消息,告诉我们它的运行时间已经超过。这就是我们如何得到第一个路由器的IP地址。然后,我们将TTL字段增加到2,发送另一个数据包,并获得第二个路由器的IP地址。我们将重复此过程,直到我们的数据包最终到达目的地。需要注意的是,这个实验只得到一个估计结果,因为理论上,不是所有这些包采取相同的路径(但在实际中,它们可能在短时间内)。下面的代码显示了这个过程中的一轮。
a = IP()
a.dst =1.2.3.4’
a.ttl = 3
b = ICMP()
send(a/b)
  • 如果您是一个经验丰富的Python程序员,您可以编写工具来自动执行整个过程。如果您是Python编程的新手,您可以通过手动更改TTL字段,并根据Wireshark的观察记录IP地址。这两种方法都是可以接受的,只要你得到了结果。
  • 模拟一个traceroute,循环每次TTL+1,中间节点都发回ICMP TTL字段过期的错误信息,目的节点发回ICMP reply就结束:
  • 创建一个trace.py文件:
    在这里插入图片描述
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])
  • 运行结果如下所示

在这里插入图片描述

Task 1.4: Sniffing and-then Spoofing
  • 在此任务中,您将结合嗅探和欺骗技术来实现以下嗅探和欺骗程序。您需要在同一局域网上的两台机器:虚拟机和用户容器。从用户容器中,您可以生成一个IPX。这将生成一个ICMP回波请求包。如果X被激活,ping程序将收到一个回波响应,并打印出响应。您的嗅探和欺骗程序运行在VM上,它通过数据包嗅探来监视局域网。每当它看到ICMP回波请求时,无论目标IP地址是什么,您的程序都应该立即使用数据包欺骗技术发送回波回复。因此,无论机器X是否活动,ping程序将始终收到回复,表明X激活。您需要使用Scapy来完成此任务。在您的报告中,您需要提供证据来证明您的技术是有效的。在您的实验中,您应该从用户容器中获取以下三个IP地址。报告你的观察结果,并解释这些结果。
  • 提示:您需要解释ARP协议是如何工作的,以便正确地解释您的观察结果。您还需要了解一点关于路由的知识。以下命令可帮助您找到指定目的地的路由器:
  • 创建sniffer2.py
    在这里插入图片描述
    在这里插入图片描述
#!/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)

  • 运行结果如下

在这里插入图片描述

Task 2.1
Task 2.1A: Understanding How a Sniffer Works
  • 可以使用pcap库很容易地编写嗅探器程序。有了pcap,嗅探器的任务就变成了调用pcap库中的一个简单的过程序列。在序列的最后,一旦数据包被捕获,就将被放入缓冲区中进行进一步处理。数据包捕获的所有细节都由pcap库处理。SEED的书提供了一个示例代码,展示了如何使用pcap编写一个简单的嗅探器程序。我们在下面包括了示例代码(详细说明请参阅本书)。
  • 在这个任务中,学生需要编写一个嗅探器程序来打印出每个捕获的数据包的源和目标IP地址。学生可以输入上面的代码或从SEED书的网站(https://www.handsonsecurity。net/figurecode.html)。学生应该提供屏幕截图作为证据,以表明他们的嗅探程序可以成功运行,并产生预期的结果。另外,请回答以下问题:
  • 这部分主要是写一个打印捕获的包的源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[] = "tcp and dst portrange 10-100";
  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 sniff sniff.c -lpcap
  • 运行,并尝试ping baidu.com,可以看到发送的包出现在结果中:

  • 运行的结果如下:
    在这里插入图片描述

  • ping
    在这里插入图片描述

在这里插入图片描述

  • Q1: 描述在你的嗅探程序中的库函数的调用
  • A1: 第一步,启动pcap监听网卡。
    • 第二步就是编译BPF过滤器并设置过滤器。
    • 第三步就是设置嗅探的处理函数。
    • 最后关闭嗅探即可。
  • Q2: 为什么需要root权限才能运行嗅探程序?不使用root权限运行该程序会在哪里报错?
  • A2: 嗅探数据包是一个高权限的操作,因为涉及到隐私,安全相关问题。如果普通用户也能嗅探数据包,那么他就能窃取别人的隐私,甚至盗取账号密码等等。不使用root权限运行该程序。对比如下,可以看到在没有权限时第一步监听网卡就失败了:
  • Q3: 打开嗅探程序的混杂模式。打开和关闭这个模式有什么区别?
  • A3: 使用混杂模式可以监听所在网段下其他机器的数据包,关闭则不能。打开混杂模式,可以监听到本网段的机器 ping baidu.com的数据包,关闭后则嗅探不到。
Task 2.1B: Writing Filters
  • 这部分主要是写一些过滤器。这部分还是复用 task 2.1A的代码,只是修改其中的过滤器而已。Pcap过滤器的例子:
  • 只捕捉两个特定主机之间的ICMP包,使用的过滤器为 icmp and src hostand dst host 10.0.2.4, 只捕捉从 发送到 10.0.2.4的ICMP包。、
  • 这边改成了百度的IP
    在这里插入图片描述
  • 结果如下,可以看到全是从百度IP发送到 10.0.2.4的ICMP包,没有其他类型的包。
    在这里插入图片描述
    在这里插入图片描述
  • 捕捉目的端口在10到100之间的TCP包:
    在这里插入图片描述
  • 结果如下,可以看到全是从 10.0.2.15 发送到 10.0.2.4的ICMP包,没有其他类型的包。
  • 捕捉目的端口在10到100之间的TCP包:使用的过滤器为 tcp and dst portrange 10-100, 只捕捉从 10.0.2.15 发送到 10.0.2.4的ICMP包。
  • 结果如下,用浏览器访问baidu.com的包出现在结果中,用浏览器访baidu.com:111的包没有出现在结果中。
    在这里插入图片描述
Task2.1C: Sniffing Passwords
  • 当普通用户发送数据包时,操作系统通常不允许用户设置协议头中的所有字段(如TCP、UDP和IP头)。操作系统将设置大部分字段,而只允许用户设置少数字段,如目标IP地址、目标端口号等。但是,如果用户具有根权限,他们可以在数据包头中设置任何任意字段。这被称为数据包欺骗,它可以通过原始套接字来完成。原始套接字为程序员提供了对数据包构造的绝对控制,允许程序员构造任何任意的数据包,包括设置头字段和有效负载。使用原始套接字非常简单;它涉及四个步骤:(1)创建一个原始套接字,(2)集套接字选项,(3)构建数据包,以及(4)通过原始套接字发送数据包。有许多在线教程可以教您如何在C编程中使用原始套接字。我们已经将一些教程链接到该实验室的网页。请阅读它们,并学习如何编写一个数据包欺骗程序。我们展示了这样一个程序的一个简单的骨架。

  • 嗅探密码。请说明当有人在您监控的网络上使用telnet时,您如何使用嗅探器程序来捕获密码。您可能需要修改您的嗅探器代码来打印出捕获的TCP数据包的数据部分(telnet使用TCP)。如果您打印出整个数据部分,然后手动标记密码(或部分密码)的位置,这是可以接受的。

  • 这边可以看到运行代码之后对tcp包的截获情况

在这里插入图片描述

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

Task 2.2A: Write a spoofing program
  • 请用c编写您自己的数据包欺骗程序。您需要提供证据(例如,有线鲨鱼数据包跟踪),以表明您的程序成功地发送了欺骗的IP数据包。
  • 这部分主要是伪造IP包。这里伪造是UDP包, 代码如下:
  • 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);
}
  • task22A
#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: Spoof an ICMP Echo Request
  • 这部分是伪造ICMP Echo请求。伪造的代码如下, 其中源IP10.0.2.5是局域网内另一个虚拟机的IP,
    在这里插入图片描述
  • task22B.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);
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.9.0.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没有捕捉到包,说明没有发出去。
  • 修改成1000B,结果如下,可以看到正常发送出去,且收到了相应。说明可以调大length,不能调小length。
  • Q5: 使用 raw socket 编程, 我们要计算IP头部的checksum吗?
  • A5: 不用计算IP头部的checksum,但是需要计算ICMP头部的checksum。
  • Q6: 为什么使用raw socket 编程需要root权限?没有root权限执行时程序会在哪里报错?
  • A6:因为能任意读取发送包意味着很大的安全风险,所以需要root权限。使用普通权限运行结果如下:
    在这里插入图片描述
Task 2.3: Sniff and then Spoof
  • 在此任务中,您将结合嗅探和欺骗技术来实现以下嗅探和欺骗程序。你需要在同一局域网上的两台机器。从机器A开始,你就可以得到一个IPX。这将生成一个ICMP回波请求包。如果X被激活,ping程序将收到一个回波响应,并打印出响应。您的嗅探和欺骗程序在攻击者机器上运行,它通过数据包嗅探监视局域网。每当它看到ICMP回波请求时,无论目标IP地址是什么,您的程序都应该立即使用数据包欺骗技术发送回波回复。因此,无论机器X是否活动,ping程序将始终收到回复,表明X激活。您需要用C编写这样的程序,并在报告中包含屏幕截图,以显示您的程序可以工作。也请在您的报告中附上代码(并有足够数量的评论)。
  • 准备两个在同一个局域网的虚拟机,这部分主要是同时嗅探和伪造包,实现一个机器ping任意IP x,另一个机器伪造ICMP回复请求,使得其有回复,而IP x所对应的机器可能根本不存在。
    准备两个在同一个局域网的虚拟机,这部分主要是同时嗅探和伪造包,实现一个机器ping任意IP x,另一个机器伪造ICMP回复请求,使得其有回复,而IP x所对应的机器可能根本不存在。
  • 代码如下task23.c
#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,此机器运行上面的程序,结果如下:

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从入门到入土:[SEED-Lab]- Packet Sniffing and Spoofing Lab 的相关文章

随机推荐

  • 部门新来的00后测试员已把我卷崩溃,老油条表示真干不过,但是...

    在程序员职场上 什么样的人最让人反感呢 是技术不好的人吗 并不是 技术不好的同事 我们可以帮他 是技术太强的人吗 也不是 技术很强的同事 可遇不可求 向他学习还来不及呢 真正让人反感的 是技术平平 却急于表现自己的人 每天加班到12点 在老
  • workman 日志_workerman 的属性

    Created by PhpStorm User zeopean Date 2016 08 26 Time 16 35 use Workerman Worker use Workerman Lib Timer require once Wo
  • (译) JSON-RPC 2.0 规范(中文版)

    起源时间 2010 03 26 基于2009 05 24版本 更新 2013 01 04 作者 JSON RPC工作组 lt json rpc googlegroups com gt 原文链接 http www jsonrpc org sp
  • Linux 如何解决共享库的版本控制(避免Dll Hell)

    Linux 系统 也同样面临和Window一样的问题 如何控制动态库的多个版本问题 Window之前没有处理好 为此专门有个名词来形容这个问题 Dll hell 其严重影响软件的升级和维护 Dll hell 是指windows 上动态库新版
  • k8s集群环境搭建

    环境规划 集群类型 一主多从 一台master节点和多台node节点 搭建简单 但是有单机故障风险 适合用于测试环境 多主多从 多台master节点和多台node节点 搭建麻烦 安全性高 适合用于生产环境 为了测试简单 本次搭建的是一主两从
  • Unity—UGUI控件

    补上昨天的UGUI控件 以后会持续两天一更 直至月末 结尾有彩蛋呦 每日一句 窗外有风景 手里有课本 眼里有梦想 心中有未来 目录 UGUI控件 Canvas画布 需求 UI是UI 3D是3D Rect Transform矩形变换 API
  • 面试中常见的小程序题

    function unique1 arr i从1开始遍历arr中每个元素 同时声明数组r 初始化一个元素为arr中第0个元素 for var i 1 r arr 0 i
  • 时间序列算法Prophet代码实现——以天气预测模型为例

    最近在做销售量预测模型相关的项目 重新拾起时间序列算法 包括AR 自回归模型 MA 移动平均模型 ARIMA 差分回归移动平均模型 等 综合预测效果想要特别记录时间序列中的Prophet算法 操作简单 效果显著 一 算法简介 Prophet
  • 【满分】【华为OD机试真题2023 JAVA&JS】优雅数组

    华为OD机试真题 2023年度机试题库全覆盖 刷题指南点这里 优雅数组 知识点双指针数组滑窗 时间限制 1s 空间限制 256MB 限定语言 不限 题目描述 如果一个数组中出现次数最多的元素出现大于等于k次 被称为 k 优雅数组 k也可以被
  • python 区块链学习(一) 单链结构实现

    最近在纠结以后的研究方向 就先看了看云链 即一种云计算 区块链 物联网设备的架构模式 虽然还是雨里雾里 还是决定先把区块链的编程落实一下 python 区块链学习 二 python 区块链学习 三 0x00 系统环境 本次使用的为Pytho
  • pycharm注释快捷键

    选中需要注释的行代码 按ctrl 进行注释
  • 分红 10 亿,小游戏《羊了个羊》背后实控人拿走 3亿 !股价暴跌 38%

    关注后回复 进群 拉你进程序员交流群 一个月前 一款名为 羊了个羊 的突然爆火 让无数人沉迷不可自拔 但正如一颗流星 昙花一现的它很快消失在公众视野中 10月10日 厦门吉比特技术公司披露 其间接持有 羊了个羊 开发商北京简游科技20 的股
  • git idea 如何删除本地分支_在intellij idea 中怎么不用git 解除关联

    展开全部 file gt settings gt version control 选中这一栏 右边有个 点红色减号 就解除了 然后去项目目录下删除 git这个文件夹 你可以不删除 为了以后继续关联62616964757a686964616f
  • 使用IDEA构建jar然后转执行程序exe的爬坑

    https download csdn net download leoysq 87939492 构建jar
  • Storybook(一)

    TOC 欢迎使用Storybook 你好 这是你第一次使用 Storybook 这个工具 如果你想学习如何使用Storybook 可以仔细阅读这篇文章 了解一下Storybook的基本知识 基本用法 我们对Storybook进行了一些说明
  • 简单的个人介绍网页-主页面【附代码】

    主页面 代码1 style css nav height 41px border top 3px solid b4fffa border bottom 1px solid edeef0 background color fcfcfc lin
  • 微机原理中操作数位置总结

    立即数 立即数在CS里 CS在存储器里 但和存储器操作数有本质的区别 但是不属于存储器数的一种 本质上是立即数寻址而不是存储器寻址 寄存器数 在cup内部 AX BX CX DX属于EU部件 存储器操作数 1看他有没有段超越前缀 超越到了什
  • 在职的我竟然一次通过了注册测绘师考试(注册测绘师备考经验分享)

    先上一波成绩吧 首先说一下我是万万没想到案例能过的 本来做好二战准备的 认为案例答的不够全面 时间不够了 既然过了那我就回想下从几个方面简短的整理下经验吧 没过的话叫教训 希望帮助给后面的同学 时间准备 确切的开始时间记不清了 但应该是20
  • Unity SpriteAtlas 打包AssetBundle的一些问题总结

    1 新版sprite要打包成图集 需要手动创建SpriteAtlas资源 然后选择需要打包进图集资源的Sprite目录或资源文件 参考 https docs unity3d com Manual class SpriteAtlas html
  • 从入门到入土:[SEED-Lab]- Packet Sniffing and Spoofing Lab

    此博客仅用于记录个人学习进度 学识浅薄 若有错误观点欢迎评论区指出 欢迎各位前来交流 部分材料来源网络 若有侵权 立即删除 本人博客所有文章纯属学习之用 不涉及商业利益 不合适引用 自当删除 若被用于非法行为 与我本人无关 SEED Lab