Chinaunix首页 | 论坛 | 博客
  • 博客访问: 48040
  • 博文数量: 30
  • 博客积分: 2000
  • 博客等级: 大尉
  • 技术积分: 230
  • 用 户 组: 普通用户
  • 注册时间: 2009-08-07 21:27
文章分类
文章存档

2011年(1)

2009年(29)

我的朋友

分类: 系统运维

2009-08-08 13:17:38

1 引题
   
这里提出一个概念:什么是主机扫描?主机扫描顾名思义就是扫描网络中存在的主机。那怎么扫描特定的主机是否存在呢?答案就是通过发送ICMP协议包来确定。那什么是ICMP包呢?
我打个不恰当的比方,ICMP包就好比邮局的快递,你要扫描一个主机是否存在,就向这个主机的地址(IP)发一个快递,不管是否投递成功,邮局都会通知你。那么你就知道该网络地址是否存在了。那么邮局的回单,我要如何分析才能知道对方的信息呢?那么我们就要来分析ICMP这个‘快递’包的投送回单。


具体的结构解释我就不多说了,网上很多,可以自己查阅

在Linux中ICMP数据结构()定义如下:


struct icmp
{
u_int8_t icmp_type; /* type of message, see below */
u_int8_t icmp_code; /* type sub code */
u_int16_t icmp_cksum; /* ones complement checksum of struct */
union
{
u_char ih_pptr; /* ICMP_PARAMPROB */
struct in_addr ih_gwaddr; /* gateway address */
struct ih_idseq /* echo datagram */
{
u_int16_t icd_id;
u_int16_t icd_seq;
} ih_idseq;
u_int32_t ih_void;

/* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */
struct ih_pmtu
{
u_int16_t ipm_void;
u_int16_t ipm_nextmtu;
} ih_pmtu;

struct ih_rtradv
{
u_int8_t irt_num_addrs;
u_int8_t irt_wpa;
u_int16_t irt_lifetime;
} ih_rtradv;
} icmp_hun;
#define icmp_pptr icmp_hun.ih_pptr
#define icmp_gwaddr icmp_hun.ih_gwaddr
#define icmp_id icmp_hun.ih_idseq.icd_id
#define icmp_seq icmp_hun.ih_idseq.icd_seq
#define icmp_void icmp_hun.ih_void
#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void
#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu
#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs
#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa
#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime
union
{
struct
{
u_int32_t its_otime;
u_int32_t its_rtime;
u_int32_t its_ttime;
} id_ts;
struct
{
struct ip idi_ip;
/* options and then 64 bits of data */
} id_ip;
struct icmp_ra_addr id_radv;
u_int32_t id_mask;
u_int8_t id_data[1];
} icmp_dun;
#define icmp_otime icmp_dun.id_ts.its_otime
#define icmp_rtime icmp_dun.id_ts.its_rtime
#define icmp_ttime icmp_dun.id_ts.its_ttime
#define icmp_ip icmp_dun.id_ip.idi_ip
#define icmp_radv icmp_dun.id_radv
#define icmp_mask icmp_dun.id_mask
#define icmp_data icmp_dun.id_data
};

那么现在的问题我们怎么自己组装ICMP包,也就是我们的包裹呢?答案在下面
void  make_icmp_packet(struct icmp *icmp,int len,int n)
{
     memset((char *)icmp,0,len);
     gettimeofday((struct timeval*)(icmp->icmp_data),(struct timezone*)0 );
     //生成ICMP报头
     icmp->icmp_type=ICMP_ECHO;
     icmp->icmp_code=0;
     icmp->icmp_id=getpid();
     icmp->icmp_seq=n;
     //icmp->icmp_cksum=0;//进行检查和,要或不要均可
     icmp->icmp_cksum=checksum((u_short*)icmp,len);
}

这里有一个校验和的程序,我在网上down了一个,大家就这么用好了
u_short checksum(u_short *data,int len)
{
     u_long sum=0;
     for(;len>1;len-=2)
     {
         sum+=*data++;
         if(sum & 0x80000000)
         sum=(sum & 0xffff)+(sum>>16);
     }
     if(len==1)
     {
         u_short i=0;
         *(u_char*)(&i)=*(u_char*)data;
         sum+=i;
     }
     while(sum>>16)
     {
         sum=(sum & 0xffff)+(sum>>16);
     }
     return (sum==0xffff)?sum:~sum;

}
需要扫描,那么自然需要一个定时器,做超时控制
void tvsub(struct timeval* out,struct  timeval *in)
{
    out->tv_sec-=in->tv_sec;
}
好了,一切就绪,我们现在可以开始我们的主机扫描之旅了
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define  PACK_LEN 72
#define  BUFSIZE  4096

int main(int argc, char *argv[])
{
    struct sockaddr_in send_sa;
    //struct s;
    int i=0,j=0;
    int scan_icmp_socket;
    char send_buff[PACK_LEN];
    char  recv_buff[BUFSIZE];
    struct in_addr  start_addr,end_addr;
    struct timeval tv;
    fd_set readfd_set;
    struct  ip  *ip;
    struct  icmp *icmp;
    int hlen;     //报头 长度

    send_sa.sin_family=AF_INET;
    scan_icmp_socket=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
    if (scan_icmp_socket<0)
    {
        perror("scan_icmp_socket:");
        return -1;
    }
    char  ip_addr[17];
    //循环ip地址
    for (j=1;j<254;j++)
    {
         memset(ip_addr,'\0',sizeof(ip_addr));
         sprintf(ip_addr,"%s.%d",argv[1],j);
         send_sa.sin_addr.s_addr=inet_addr(ip_addr);
         printf("scan %s\n",inet_ntoa(send_sa.sin_addr));
         fflush(stdout);
         for (i=0;i<3 ;i++ )
         {
             make_icmp_packet((struct icmp*)send_buff,PACK_LEN,i);
             if ( (sendto(scan_icmp_socket,send_buff,PACK_LEN,0,(struct    sockaddr*)&send_sa,sizeof(send_sa)))<0 )
             {
                 perror("sendto");
             }
             //设定超时0.4妙
             tv.tv_sec=0;
             tv.tv_usec=400*1000;
             FD_ZERO(&readfd_set);
             FD_SET(scan_icmp_socket,&readfd_set);
             while(1)
             {
                if (select(scan_icmp_socket+1,&readfd_set,NULL,NULL,&tv)<=0)
                {
                   break;
                }
                 //等待0.4妙后如果数据有回应那么就开始接收包含ICMP包的IP报
                if (recvfrom(scan_icmp_socket,recv_buff,BUFSIZE,0,NULL,NULL)<=0)
                {
                   perror("recvfrom:");
                   exit(0);
                 }
                 ip=(struct ip*)recv_buff;
                 //获得IP数据包长度;
                 hlen=ip->ip_hl<<2;
                 //根据IP的源ip是否和自己相同判断是否是自己收到的包
                 if (ip->ip_src.s_addr==send_sa.sin_addr.s_addr)
                 {
                     icmp=(struct icmp*)(recv_buff+hlen);
                     //解析icmp包内容信息
                     if (icmp->icmp_type==ICMP_ECHOREPLY)
                     {
                        printf("%-15s",inet_ntoa( *(struct in_addr*)
&(ip->ip_src.s_addr)));
                        //获得当前系统时间后与ICMP包内的数据内容对比
                        gettimeofday(&tv,NULL);
                        tvsub(&tv,(struct timeval*) (icmp->icmp_data));
                        printf(":RTT=%8.4f  ms\n",tv.tv_sec+tv.tv_usec/1000.0);
                        break;
                      }
                      else
                      {
                         printf("ICMP STATE:%d\n",icmp->icmp_type);
                      }
                    }
              }
          }
       
    }
    close(scan_icmp_socket);
    return 0;
}

至此,我们主机扫描的原理和实现已经讲完了,那么主机扫描有什么用?
    没错,主机是否可到达是网络安全测试的第一步内容。而且,每次有人发送ICMP包,你的电脑都 要应答。如果很多人同时发送ICMP包达到你的电脑,也就是说邮局同时送来了1000个包裹,你可能就有些应付不了了吧。这时候的状态就是你的电脑上网很 卡很卡,或者根本上不了。那么我们怎么防范ICMP攻击呢,或者我不想别人知道我的电脑到底在不在上网?很简单,装个防火墙,将拒绝ICMP勾选上就可以 了。
    其实说了半天,ICMP多半用来DOS攻击,这种攻击多半基于单机,带宽小,效率低,对于被扫描者不会造成很大的危害。然后,目前的网络攻击多半是类似云计算的形式,当成千上万的肉鸡向你发动攻击的时候,那可不是好玩的。
阅读(1821) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:ARP三部曲之协议篇

给主人留下些什么吧!~~