博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
网络扫描程序的详细分析与实现
阅读量:7229 次
发布时间:2019-06-29

本文共 6671 字,大约阅读时间需要 22 分钟。

1.网络扫描简介

  网络扫描是一种自动化程序,用于检测远程或本地主机的弱点和漏洞。漏洞扫描是入侵防范最基本的工作,攻击者正式利用各种漏洞入侵系统。借助自动化的扫描工作,在攻击者之前发现漏洞问题,并给予相应的修正程序。

  一名攻击者入侵系统,一般分为四个步骤:系统发现,漏洞探测,漏洞利用和痕迹清除。

  本文的重点就是在于系统发现与漏洞探测方面。

2.端口扫描技术

  端口扫描能够用来查找目标主机已开放的端口,包括TCP和UDP端口。当前针对TCP端口的扫描技术有三种,分别为:全连接扫描,SYN扫描和FIN扫描。针对UDP端口的扫描技术一般是采用ICMP报文中端口不可达的信息来识别UDP端口是否开放。

  • 全连接扫描

  作为最基本的TCP扫描方式,它利用connect()函数,向每一个目标主机的端口发起连接,若端口处于侦听状态,则函数返回成功;否则可以判断出该端口没有开放。

  全连接扫描有两个好处,首先它不许要得到系统权限,任何用户都可以使用,另外一个是,可以采用多线程并发扫描,扫描的速度也不慢。

  • SYN扫描

  SYN扫描通常认为是“半开放”的扫描,这是因为扫描程序不必打开一个完全的TCP连接。扫描程序构造并发送一个SYN数据包,执行TCP三次握手的第一步,若返回一个SYN|ACK数据包,则表示端口处于侦听状态,否则返回一个RST数据包,表示端口没有开放。这种方式需要root权限,并且它不会在主机上留下记录。

  • FIN扫描

  FIN扫描与SYN扫描类似,也是构造数据包,通过识别回应来判断端口状态。发送FIN数据包后,如果返回一个RST数据包,则表示端口没有开放,处于关闭状态,否则,开放端口会忽略这种报文。这种方式难以被发现,但是这种方式可能不准确。

  • UDP的ICMP端口不可达扫描

  UDP扫描的方法并不常见。虽然UDP协议相对比较简单,无论UDP端口是否开放,对于接受到的探测包,他本身默认是不会发送回应信息的。不过UDP扫描有一种方法,就是利用主机ICMP报文的回应信息来识别,当一个关闭的UDP端口发送一个数据包时,会返回一个ICMP_PORT_UNREACH的错误。但由于UDP不可靠,ICMP报文也是不可靠,因此存在数据包中途丢失的可能。

3.具体实现

  首先介绍全连接扫描模块的设计。

  具体流程:

  1. 判断端口是否处于扫描范围
  2. 初始化套接字,发起连接
  3. 调用getservbyport函数,获取端口映射的TCP服务
  4. 输出结果
  5. 退出程序

实现代码:

//全连接扫描void scan(char *ip,int minport,int maxport){    if(maxport
s_name); else printf("Port:%5d | Status:open\n",i); } close(sock); }}

  可以对上述代码进行改进,可以加入多线程的的方式来解决扫描速度较慢的问题。

  在这里需要定义一个结构体,来为线程传递必要的参数。

typedef struct threadpara{    char ip[20];    int minport;    int maxport;}tp;

  这样的话,我们就可以定义一个线程函数用于连接不同的端口。

void *conntthread(void *threadp){    struct threadpara *pThreadpara=(struct threadpara*)threadp;        int i;    printf("minport:%d maxport:%d thread....\n",pThreadpara->minport,pThreadpara->maxport);        for(i=pThreadpara->minport;i
maxport;++i){ struct sockaddr_in clientaddr; clientaddr.sin_family=AF_INET; clientaddr.sin_addr.s_addr=inet_addr(pThreadpara->ip); clientaddr.sin_port=htons(i); int sock=socket(AF_INET,SOCK_STREAM,0); if(sock<0){ perror("error:create socket\n"); return 0; } int error=connect(sock,(struct sockaddr*)&clientaddr,sizeof(clientaddr)); if(error<0){ printf("Port:%5d | Tatus:closed\n",i); fflush(stdout);//清空缓存 } else{ struct servent* sptr; if((sptr=getservbyport(htons(i),"tcp"))!=NULL) printf("Port:%5d | Server:%s | Status:open\n",i,sptr->s_name); else printf("Port:%5d | Status:open\n",i); } close(sock); } pthread_exit(NULL);}

  接下来,就是在主扫描程序中添加启动线程的模块,主要代码如下:

int count=(maxport-minport)/thread_num;        printf("count:%d num:%d ip:%s,port:%d,port:%d\n",count,thread_num,ip,minport,maxport);    printf("Now start scanning....\n");        int i;    for(i=0;i

  接下来,再介绍一个SYN半连接扫描的例子。

  扫描模块的设计流程图如下:

  具体流程:

  1. 初始化套接字
  2. 设置信号量以及全局变量flag(控制扫描状态)
  3. 启动接收线程
  4. 构造SYN数据包,开始扫描

  首先,构造并发送syn包模块的代码如下: 

int sendSyn(int sendSocket,u_long sourceIP,struct sockaddr_in *dest){    unsigned char netPacket[sizeof(struct tcphdr)];    struct tcphdr* tcp;    u_char * pPseudoHead;    u_char pseudoHead[12+sizeof(struct tcphdr)];    u_short tcpHeadLen;        memset(netPacket,0,sizeof(struct tcphdr));        //构造syn数据包    tcpHeadLen=htons(sizeof(struct tcphdr));    tcp=(struct tcphdr*)netPacket;    tcp->source=htons(10240);    tcp->dest=dest->sin_port;    tcp->seq=htonl(12345);    tcp->ack_seq=0;    tcp->doff=5;    tcp->syn=1;    tcp->window=htons(10052);    tcp->check=0;    tcp->urg_ptr=0;    pPseudoHead=pseudoHead;        memset(pPseudoHead,0,12+sizeof(struct tcphdr));    memcpy(pPseudoHead,&sourceIP,4);        pPseudoHead+=4;        memcpy(pPseudoHead,&(dest->sin_addr),4);    pPseudoHead+=5;        memset(pPseudoHead,6,1);    pPseudoHead++;        memcpy(pPseudoHead,&tcpHeadLen,2);    pPseudoHead+=2;        memcpy(pPseudoHead,tcp,sizeof(struct tcphdr));    tcp->check=checksum((u_short*)pPseudoHead,sizeof(struct tcphdr)+12);        int temp=sendto(sendSocket,netPacket,sizeof(struct tcphdr),0,(struct sockaddr*)dest,sizeof(struct sockaddr_in));    return temp;}

  TCP校验和代码:

unsigned short checksum(unsigned short *addr,int len)//TCP校验和{    int nleft=len;    int sum=0;    unsigned short *w=addr;    unsigned short answer=0;        while(nleft>1){        sum+=*w++;        nleft-=2;    }        if(nleft==1){        *(unsigned char*)(&answer)=*(unsigned char*)w;        sum+=answer;    }        sum=(sum>16)+(sum&0xffff);    sum+=(sum>>16);    answer=~sum;    return(answer);}

  接收返回数据包的代码如下:

void* recv_packet(void* arg){    struct sockaddr_in *in1;    char *srcaddr;    int size;    u_char readbuff[1600];    struct sockaddr from;    int from_len;    struct tcphdr* tcp;    struct servent* sptr;    tcp=(struct tcphdr*)(readbuff+20);    int fd=*((int*)arg);        while(1){        if(flag==1)            return 0;                    size=recvfrom(fd,(char*)readbuff,1600,0,&from,(socklen_t *)&from_len);        if(size<40)            continue;        printf("data is ok...ack:seq:%u,destport:%u\n",ntohl(tcp->ack_seq),ntohs(tcp->dest));        if((ntohl(tcp->ack_seq)!=123456)||(ntohs(tcp->dest)!=10240))            continue;        if(tcp->rst&&tcp->ack){            printf("port:%5d | Status: closed\n",htons(tcp->source));            continue;        }        if(tcp->ack&&tcp->syn){            in1=(struct sockaddr_in*)&from;            srcaddr=inet_ntoa(in1->sin_addr);            printf("SERVER:%s\r",srcaddr);        }        if((sptr=getservbyport(tcp->source,"tcp"))!=NULL){            printf("Port:%d Server:%s | Status: open\n",htons(tcp->source),sptr->s_name);        }        else            printf("Port:%5d | Status:open\n",htons(tcp->source));        fflush(stdout);        continue;    }}

  扫描程序的主要程序:

void synscan(char* ip,int minport,int maxport){    pthread_t tid;    struct ifreq if_data;    int fd;    u_long addr_p;        struct sockaddr_in clientaddr;    fd=socket(AF_INET,SOCK_RAW,IPPROTO_TCP);//SOCK_RAW原始套接子(数据包式)    if(fd<0){        perror("error:create raw socket\n");        return;    }        signal(SIGALRM,Alarm);        strcpy(if_data.ifr_name,"eth0");    if(ioctl(fd,SIOCGIFADDR,&if_data)<0){        perror("error:ioctl\n");        return;    }    memcpy((void*)&addr_p,(void*)&if_data.ifr_addr.sa_data+2,4);        bzero(&clientaddr,sizeof(clientaddr));    clientaddr.sin_family=AF_INET;    clientaddr.sin_addr.s_addr=inet_addr(ip);        printf("Now start scannning...\n");    int err;    err = pthread_create(&tid,NULL,recv_packet,(void*)&fd);    if(err<0)        perror("error:create thread\n");    int i=minport;    for(;i

 

最后附上之前的IP地址扫描!

本文转自cococo点点博客园博客,原文链接:http://www.cnblogs.com/coder2012/archive/2013/04/10/3010087.html,如需转载请自行联系原作者

你可能感兴趣的文章
Android开发 Firebase动态链接打开APP
查看>>
基于 HTML5 Canvas 的 3D 模型贴图问题
查看>>
让技术不要成为“背锅侠”!
查看>>
dubbo源码分析系列——dubbo的SPI机制源码分析
查看>>
表格单元格td设置宽度无效的解决办法
查看>>
防止视频资源被下载
查看>>
都是并发惹的祸
查看>>
eclipse实现JavaWeb项目 增量打包
查看>>
面试题系列一之 程序生命周期
查看>>
设计模式——观察者模式:气象监测应用
查看>>
NSUserDefaults简介及如何使用 NSUserDefaults 存储自定义对象
查看>>
IntelliJ IDEA搭建SpringBoot
查看>>
深入浅出iOS事件机制
查看>>
hadoop理解
查看>>
Oracle——18用户、角色和权限信息的视图总结
查看>>
WordPress 中的 Debug 模式(调试模式)
查看>>
node下使用express框架,ejs模板引擎
查看>>
搜索:文本的匹配算法
查看>>
Fedora 17 LibreOffice 办公套件的安装与汉化
查看>>
scrollview不充满屏幕的原因
查看>>