hacker成长的代码之路:扫描(2)

发表于:2007-07-04来源:作者:点击数: 标签:
作者:kf_701 写作时间:2005/4 Email:kf_701@21cn.com 转载请保留原作者信息,谢谢。 要求的专业知识: 一: 精通OSI参考模型,精通 网络 五层:物理层,数据链路层, 网络 层,传输层,应用层。 精通每一层的协议,数据报格式。精通 网络 拓扑结构,第一层
作者:kf_701 写作时间:2005/4 Email:kf_701@21cn.com
转载请保留原作者信息,谢谢。

要求的专业知识
    一:    精通OSI参考模型,精通网络五层:物理层,数据链路层,网络层,传输层,应用层。
        精通每一层的协议,数据报格式。精通网络拓扑结构,第一层,第二层,第三层的网
        络互联,数据的转发和路由等。
    二:    精通C语言程序设计,UNIX/LINUX程序设计,网络程序设计。熟悉UNIX/LINUX系
        统操作,熟悉著名服务的基本配置,特性及使用的端口号。熟悉经典网络命令的使用,
        如:netstat,ping,traceroute,netcat,arp等。
    三:    精通标准SQL语言,熟悉流行的数据库使用,如:Oracle,Mysql等。掌握数据库与
        WEB语言的结合使用。

  有的时候可能要确定一个局域网内有多少台机器是开机的,那么就要依次扫描这个网段内的所有IP。通
常的端口扫描或漏洞扫描的前提是目标主机是开机的,否则所有的扫描都是白费时间。最简单的办法是先
ping一下目标主机。大部分的扫描软件都会在扫描开始前进行和ping类似的测试

  我们要成为真正的黑客,所以我们不会满足于使用别人的程序,我们要理解这里面全部的网络原理,我
们要写自己的程序。

  其实这样的程序并不难,我们只要向目标主机发送一个ICMP ECHO请求报文,如果目标主机回应了一
个ICMP ECHOREPLY报文,则目标主机一定是开机的。那么我们就可以进行后面的扫描工作了。

  ICMP是第三层(网络层)的协议,虽然它和IP协议都在网络层,但ICMP数据报依然使用IP报头封装
其报文内容。ICMP ECHO的类型值是8(ICMP_ECHO),代码值是0。我们用程序来完成一个简单的ping。
读到这里,我假想你是完全知道ICMP报文的格式的,如果你不知道,那么请你离开,去打点基础再来阅
读,否则纯属浪费时间。

  先建一个原始socket,再自已构造一个ICMP报文,通过这个原始socket把ICMP报文发送出去,然后
用这个原始socket接收目标主机的回应ICMP,收到回应,那么进行后面的扫描吧。要说明的是系统内核
会把收到的所有ICMP消息给每个ICMP原始socket复制一份,也就是说我们程序里创建的ICMP RAW
socket会收到所有的ICMP消息,但我们只想等待我们程序里指定的目标主机的ICMP ECHOREPLY消息,
较好的办法是使用ICMP ECHO报头的标识字段,在构造ICMP请求报文的时候,把标识字段(icmp_id)设
为进程号(process id)。然后检查收到的每个ICMP消息的标识字段,和process id相同的则是我们
等待的报文。

  raw socket只有superuser可以创建,务必在superuser权限下运行。下面是一段简单的代码,不
过也是完整呈现了ping程序。

  send_icmp()构造ICMP报头并使用raw socket发送。main循环接收ICMP消息,交给proc_icmp
判断处理。代码是linux系统上测试通过。

  本程序只对一个IP地址进行,如果要对一段IP进行测试,简单修改程序即可。可将发送放在单独的进程
里(使用fork()),send_icmp里做成循环,每次重新初始化struct sockaddr_in。那么对接收到的数据
进行分析的proc_icmp()将多一道对IP报头ip->src字段的判断。具体的修改,留给读者自己完成。

     1  /*
     2     A simply ping program for unix
     3     Copyright (C) 2005  by kf_701
     4
     5     This program is free software; you can redistribute it and/or modify
     6     it under the terms of the GNU General Public License as published by
     7     the Free Software Foundation; either version 2 of the License, or
     8     (at your option) any later version.
     9
    10     This program is distributed in the hope that it will be useful,
    11     but WITHOUT ANY WARRANTY; without even the implied warranty of
    12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13     GNU General Public License for more details.
    14
    15     You should have received a copy of the GNU General Public License
    16     along with this program; if not, write to the Free Software
    17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
    18
    19     The author can be reached as follows:
    20          E_mail:         kf_701@21cn.com
    21          Address:        hefei of china
    22          Phone:          0551-2150103
    23  */
    24
    25  #include <netinet/ip.h>
    26  #include <stdio.h>
    27  #include <netinet/ip_icmp.h>
    28  #include <netinet/in_systm.h>
    29  #include <netdb.h>
    30  #include <sys/types.h>
    31  #include <sys/socket.h>
    32  #include <netinet/in.h>
    33  #include <arpa/inet.h>
    34  #include <unistd.h>
    35  #include <sys/time.h>
    36  #include <errno.h>
    37  #include <signal.h>
    38  #include <string.h>
    39  #include <stdlib.h>
    40
    41  #define BUFSIZE         1024
    42
    43          /* global vars */
    44  char recvbuf[BUFSIZE];
    45  char sendbuf[BUFSIZE];
    46  int datalen = 56;       /* bytes of data,following ICMP header*/
    47  pid_t pid;              /* the pid use as icmp_id*/
    48  unsigned short seqno;           /* icmp_seq number*/
    49  int timeerr;            /* test gettimeofday if error*/
    50  int sockfd = -1;
    51  struct sockaddr_in destaddr;
    52  socklen_t len = sizeof(struct sockaddr);
    53
    54          /* function prototypes */
    55  static unsigned short check_sum(unsigned short *,int);
    56  static void send_icmp(void);
    57  static void proc_icmp(char *,ssize_t,struct timeval *);
    58  static void tv_sub(struct timeval *,struct timeval *);
    59  static void sig_alrm(int);
    60  static void sig_int(int);
    61
    62  int
    63  main(int argc,char **argv)
    64  {
    65          int size = 60*1024;     /* set SO_RCVBUF */
    66          struct timeval timeval; /* recvfrom time */
    67          struct hostent *host;
    68
    69          if(argc != 2)
    70                  puts("-----usage:ping host------"),exit(1);
    71
    72          bzero(&destaddr,sizeof(destaddr));
    73          destaddr.sin_family = AF_INET;
    74          if(inet_aton(argv[1],&destaddr.sin_addr) == 0){
    75                  host = gethostbyname(argv[1]);
    76                  if(host == NULL){
    77                          fprintf(stderr,"Hostname Error: %s \n",hstrerror(h_errno));
    78                          exit(1);
    79                  }
    80                  destaddr.sin_addr = *(struct in_addr *)(host->h_addr_list[0]);
    81          }
    82          /*struct addrinfo hints,*res;
    83          hints.ai_flags = AI_CANONNAME;
    84          hints.ai_family = AF_INET;
    85          hints.ai_socktype = 0;
    86          if(getaddrinfo(argv[1],NULL,&hints,&res) != 0)
    87                  perror("getaddrinfo error"),exit(1);*/
    88
    89          sockfd = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
    90          if(sockfd == -1)
    91                  perror("socket error"),exit(1);
    92          setuid(getuid());       /* not need super permission any more*/
    93          setsockopt(sockfd,SOL_SOCKET,SO_RCVBUF,&size,sizeof(size));
    94
    95          signal(SIGINT,sig_int);
    96          signal(SIGALRM,sig_alrm);
    97          pid = getpid();
    98          printf("------------ping %s 56 bytes packet------------\n",argv[1]);
    99          sig_alrm(SIGALRM);      /* send first packet*/
   100
   101          while(1){               /* receive packet */
   102                  int n = -1;
   103                  n = recvfrom(sockfd,recvbuf,sizeof(recvbuf),0,(struct sockaddr *)NULL,NULL);
   104                  if(n < 0){
   105                          if(errno == EINTR)
   106                                  continue;
   107                          else
   108                                  perror("recvfrom error"),exit(1);
   109                  }
   110                  /*printf("received : ");*/
   111                  if(gettimeofday(&timeval,NULL) == -1)
   112                          perror("gettimeofday error"),timeerr++;
   113                  proc_icmp(recvbuf,n,&timeval);
   114          }
   115  }
   116
   117  static void
   118  send_icmp(void)
   119  {
   120          int len;
   121          struct icmp *icmp;
   122
   123          icmp = (struct icmp *)sendbuf;
   124          icmp->icmp_type = ICMP_ECHO;
   125          icmp->icmp_code = 0;
   126          icmp->icmp_id = pid;
   127          icmp->icmp_seq = seqno;
   128          if(gettimeofday((struct timeval *)icmp->icmp_data,NULL) == -1)
   129                  puts("set icmp_data error"),timeerr++;
   130          len = 8 + datalen;
   131          icmp->icmp_cksum = 0;
   132          icmp->icmp_cksum = check_sum((u_short *)icmp,len);
   133          if(sendto(sockfd,sendbuf,len,0,(struct sockaddr *)&destaddr,len) == -1)
   134                  perror("sendto error"),exit(1);
   135          printf("send one packet and wait for answer ......\n");
   136          fflush(NULL);
   137  }
   138
   139  static void
   140  sig_alrm(int signo)
   141  {
   142          send_icmp();
   143          seqno = seqno + 1;
   144          alarm(1);
   145          return;
   146  }
   147
   148  static void
   149  proc_icmp(char *ptr,ssize_t len,struct timeval *tvrecv)
   150  {
   151          int iphdlen,icmplen;
   152          struct ip *ip;
   153          struct icmp *icmp;
   154          struct timeval *tvsend;
   155          double rtt;
   156
   157          ip = (struct ip *)ptr;                  /* start of IP header   */
   158          iphdlen = ip->ip_hl<<2;                 /* length of IP header  */
   159          icmp = (struct icmp *)(ptr+iphdlen);    /* start of ICMP header */
   160          if( (icmplen = len - iphdlen) < 8){     /* test icmp header len */
   161                  puts("icmplen error");
   162                  return;
   163          }
   164          if((icmp->icmp_type == ICMP_ECHOREPLY)&&(icmp->icmp_id == pid)){
   165                  printf("*receive: icmp_seq=%d ",icmp->icmp_seq);
   166                  if(icmplen < 16)
   167                          puts("icmplen < 16"),exit(1);
   168                  tvsend = (struct timeval *)icmp->icmp_data;
   169                  if(!timeerr){
   170                          tv_sub(tvrecv,tvsend);
   171                          rtt = tvrecv->tv_sec*1000.0 + tvrecv->tv_usec/1000.0;
   172                          printf(" rtt=%.3f ms\n",rtt);
   173                  }
   174          }
   175          return;
   176  }
   177
   178  static void
   179  tv_sub(struct timeval *out,struct timeval *in)
   180  {
   181          if( (out->tv_usec -= in->tv_usec) < 0 ){
   182                  --out->tv_sec;
   183                  out->tv_usec += 1000000;
   184          }
   185          out->tv_sec -= in->tv_sec;
   186  }
   187
   188  static void sig_int(int sig)
   189  {
   190          printf("-------------------------------------------------------\n");
   191          exit(0);
   192  }
   193
   194  static unsigned short
   195  check_sum(unsigned short *addr,int len)
   196  {
   197          register int nleft = len;
   198          register int sum = 0;
   199          register short *w = addr;
   200          short answer = 0;
   201
   202          while(nleft>1)
   203          {
   204                  sum += *w++;
   205                  nleft -= 2;
   206          }
   207          if(nleft ==1)
   208          {
   209                  *(unsigned char *)(&answer) = *(unsigned char *)w;
   210
   211                  sum += answer;
   212          }
   213          sum = (sum>>16)+(sum&0xffff);
   214          sum += (sum>>16);
   215          answer = ~sum;
   216          return(answer);
   217  }



check_sum函数是大家都使用的函数,这里就不作详细介绍了。作用是计算校验和。
看完后,你是否觉得原来是如些简单的事情呢,有问题请给我mail,谢谢。
******待续******

原文转自:http://www.ltesting.net