在线客服:
yobo官网 yobo官网
全国服务热线:010-53193650
您的位置:首页 > 新闻中心 >

网络扫描程序的详细分析和实现

浏览 99次 来源:【jake推荐】 作者:-=Jake=-    时间:2021-02-23 20:19:54
[摘要] 端口扫描能够用来查找目标主机已开放的端口,包括TCP和UDP端口。当前针对TCP端口的扫描技术有三种,分别为:全连接扫描,SYN扫描和FIN扫描。FIN扫描与SYN扫描类似,也是构造数据包,通过识别回应来判断端口状态。扫描模块的设计流程图如下:扫描程序的主要程序:

1.网络扫描简介

网络扫描是用于检测远程或本地主机中的弱点和漏洞的自动化程序。漏洞扫描是入侵防御的最基本工作。攻击者正式使用各种漏洞来入侵系统。借助自动扫描凤凰体育Appyabobet ,可以在发现攻击者之前先发现漏洞,并给出相应的纠正程序。

攻击者入侵系统通常分为四个步骤:系统发现,漏洞检测,漏洞利用和跟踪删除。

本文的重点是系统发现和漏洞检测。

2.端口扫描技术

端口扫描可用于查找目标主机的打开端口,包括TCP和UDP端口。目前,TCP端口有三种扫描技术,即:完全连接扫描,SYN扫描和FIN扫描。 UDP端口扫描技术通常使用ICMP消息中的端口不可达信息来识别UDP端口是否打开。

作为最基本的TCP扫描方法,它使用connect()函数启动与每个目标主机的端口的连接。如果端口处于侦听状态,则该函数返回成功;否则,该函数将返回成功。否则,可以判断该端口未打开。

完全连接扫描有两个优点。首先,它不需要系统权限,任何用户都可以使用。另一个是它可以使用多线程并发扫描,并且扫描速度并不慢。

SYN扫描通常被认为是“半开放式”扫描,因为扫描仪不必打开完整的TCP连接。扫描程序构造并发送一个SYN数据包yobo体育官网 ,并执行TCP三向握手的第一步。如果返回SYN | ACK数据包,则表示该端口处于侦听状态,否则返回RST数据包,这表示该端口未打开。此方法需要root特权网络扫描,并且不会在主机上留下记录。

FIN扫描类似于SYN扫描。它还构造数据包并通过识别响应来判断端口状态​​。发送完FIN报文后,如果返回RST报文,则表示该端口未打开且处于关闭状态。否则,开放端口将忽略此类数据包。这种方法很难检测,但可能不准确。

UDP扫描方法并不常见。尽管UDP协议相对简单,但是无论UDP端口是否打开,默认情况下它都不会为收到的检测包发送响应消息。但是,UDP扫描的一种方法是使用主机ICMP消息的响应信息进行识别。当关闭的UDP端口发送数据包时,将返回ICMP_PORT_UNREACH错误。但是,由于UDP不可靠,ICMP消息也不可靠,因此有可能在途中丢失数据包。

3.具体实现

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

网络扫描

具体过程:

确定端口是否在扫描范围内并初始化套接字,启动连接并调用getservbyport函数以获得端口映射的TCP服务输出结果并退出程序

实施代码:

ad239网络扫描_网络扫描_佳能复印机网络扫描

//全连接扫描
void scan(char *ip,int minport,int maxport)
{
    if(maxport<minport){
        printf("error:can't scan int this condition\n");
        return;
    }
    printf("test ip:%s,port:%d,port:%d\n",ip,minport,maxport);
    
    int i=0;
    printf("Now start scanning.....\n");
    for(i=minport;ii){
        struct sockaddr_in clientaddr;
        
        clientaddr.sin_family=AF_INET;
        clientaddr.sin_addr.s_addr=inet_addr(ip);
        clientaddr.sin_port=htons(i);
        
        int sock=socket(AF_INET,SOCK_STREAM,0);
        if(sock<0){
            perror("error:create socket\n");
            return;
        }
        
        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);
    }
}

可以改进上述代码网络扫描,并可以添加多线程来解决扫描速度慢的问题。

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

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;imaxport;++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;ii){
        struct threadpara threadpara;
        strcpy(threadpara.ip,ip);
        threadpara.minport=minport+count*i;
        if(i==thread_num-1)
            threadpara.maxport=maxport;
        else
            threadpara.maxport=threadpara.minport+count;
            
        printf("i:%d maxport:%d,minport:%d\n",i,threadpara.maxport,threadpara.minport);
        
        int temp;
        pthread_t threadid;
        temp=pthread_create(&threadid,NULL,conntthread,(void*)&threadpara);
        if(temp<0)
            printf("create thread error...\n");
        pthread_join(threadid,NULL);
    }

接下来凤凰体育平台 ,我将介绍一个SYN半联接扫描的示例。

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

网络扫描

具体过程:

初始化套接字,设置信号量和全局变量标志(控制扫描状态),启动接收线程以构造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(;ii){
        clientaddr.sin_port=htons(i);
        if(sendSyn(fd,addr_p,&clientaddr)<0){
            perror("error:send syn\n");
        }
        alarm(3);
    }
    pthread_join(tid,NULL);
}

最后,附加上一个IP地址扫描代码!

老王
本文标签:网络端口,tcp端口

推荐阅读

最新评论