LionD8' Blog

明志. 博学. 笃行

用户操作
[即时聊天] [发私信] [加为好友]
LionD8
LionD8的公告
最近评论
zhegaozhouji:哇塞~~ 大牛啊!
safer:D8 要买房子了
sweet:不但有全局变量,还有改了入口5个字节的函数,如果可以重入,都会导致问题的。
boli:啥都往内核里面整~ 不管对系统健壮性有没有危险,对系统效率有没有影响~ ;p
阿呆:高手哟。
呵呵,不错。
也请关注此技术blog,也是不错的哟。
http://blog.csdn.net/cxxsoft/
文章分类
收藏
    相册
    黑黑
    生活中的朋友和同学
    我的相册
    杂物
    ebook
    chinaitlab
    netYi专业电脑电子书库
    中国E书网
    国外站1
    国外站2
    PHP
    php5研究室
    phpchina
    安全相关
    astalavista
    BlackHat
    ccert
    elitehackers
    frsirt
    h4cky0u
    intrusion
    marc.theaimsgroup
    milw0rm
    networkintrusion
    packetstormsecurity
    securityfocus
    securitytracker
    WhiteCell
    中华安全网
    中国讯息安全网
    安全焦点
    幻影旅团
    重庆网络安全小组
    留言本
    朋友的Blog【非IT】
    YY的博客
    无线网络
    无线网络安全
    系统/编程
    CVC
    jiurl Home
    Kendiv的专栏
    OSR Online
    RootKit
    sourceforge
    SysInternals
    TheCodeProject
    VC知识库
    Windows Developer's Journal
    陆麟的主页
    驱动开发网
    兄弟伙的Blog
    alpha兄的好东西
    CDrea' s Blog
    Darkness Blog
    ffantasyYD的专栏
    Gxter的Blog
    heiyeluren's Blog
    lanker 's Blog
    looooo 's blog
    shadow3 's Blog
    孤独's Blog
    慕容小雨的Blog
    梁上君子Blog
    翼帆Blog
    娱乐
    flyinufo的相册
    存档
    软件项目交易
    订阅我的博客
    XML聚合  FeedSky
    订阅到鲜果
    订阅到Google
    订阅到抓虾
    订阅到BlogLines
    订阅到Yahoo
    订阅到GouGou
    订阅到飞鸽
    订阅到Rojo
    订阅到newsgator
    订阅到netvibes

    原创 端口和CGI的扫描实现收藏

    新一篇: arp 欺骗的技术原理及应用 | 旧一篇: DIY一个简单共享儒虫

    端口和CGI的扫描实现<首发于2003年黑客防线11期>

    WriteBy: LionD8

    email:   liond8@eyou.com

    Website: http://liond8.126.com

     

    . DIY一个端口扫描器之-高级技术

    端口的扫描技术到现在大致分为两种,一种就是低级传统的扫描器,还有就是高级技术的。今天我们就来讲讲高级技术的原理及其实现在基本代码。

        经过测试我们知道正在LISTEN的端口,如果接收在一个SYN包(就是TCP握手的第一次)那么它就会返回一个SYN|ACK(0x12)包,如果一个 关闭的端口接收到SYN包就会返回一个PSH|RST|SYN(0x14)的包并且SYN序列号为0。如果远程主机不存在,那么不返回任何数据包。

        根据上面的分析我们就可以构造一个扫描器了。

        如果我们对目标机器发一个SYN包,如果接收到一个SYN|ACK(0x12)的包我们就知道远程端口是存活的。如果接收到PSH|RST|SYN(0x14)那么就确定那个端口没有开放。

        好的那么我们在发包前就需要建立一个侦听线程来接收返回的数据包,并加一分析。

     

    1.定义侦听线程:

    DWORD   WINAPI  ListeningFunc(LPVOID lpvoid)

    {

     

    首先就需要建立一个原始套结字。

        SOCKET rawsock=socket(AF_INET,SOCK_RAW,IPPROTO_IP);

     

    然后取得本机的IP地址,确定一个端口绑定rawsock。

        struct hostent  *pHostent;

        CHAR    name[100]={0};

        gethostname(name, 100);

        pHostent=gethostbyname(name);

     

    把本机IP地址复制到addr_in.sin_addr.S_un.S_addr中。

        memcpy(&addr_in.sin_addr.S_un.S_addr, pHostent->h_addr_list[0], pHostent->h_length);

     

    绑定。 

        int ret=bind(rawsock, (struct sockaddr *)&addr_in, sizeof(addr_in));

     

    设置SIO_RCVALL 接收所有的数据包

        DWORD lpvBuffer = 1;

        DWORD lpcbBytesReturned = 0;

        WSAIoctl(rawsock, SIO_RCVALL, &lpvBuffer, sizeof(lpvBuffer), NULL, 0, &lpcbBytesReturned, NULL, NULL);

     

    然后剩下的就是对数据包的捕获分析了。用一个死循环来不断的捕获接收到的数据包,分析如果是存活端口返回的包就打出来,不是的话就放弃,不做任何处理,继续捕获下一个数据包。

    while (TRUE)

    {

    SOCKADDR_IN from={0};

    int  size=sizeof(from);

    char RecvBuf[256]={0};

    //接收数据包

    ret=recvfrom(rawsock,RecvBuf,sizeof(RecvBuf),0,(struct sockaddr*)&from,&size);

    char* sourceip=inet_ntoa(* (struct in_addr *)&from.sin_addr);

    if(ret!=SOCKET_ERROR)

    {

       // 分析数据包

       IPHEADER *lpIPheader;

       lpIPheader=(IPHEADER *)RecvBuf;

       if (lpIPheader->proto==IPPROTO_TCP)

       {

        TCPHEADER *lpTCPheader=(TCPHEADER*)(RecvBuf+sizeof(IPHEADER));

        //判断是不是远程开放端口返回的数据包

        if (lpTCPheader->th_seq != 0 && lpTCPheader->th_flag==0x12)  

        {

            //如果是,就从TCP头中提出端口源端口信息,打印出来。

            printf("===%s:%d\n",sourceip,ntohs(lpTCPheader->th_sport));

        }

        }

    }

    }     // end while

     

    }  一上就是我们要建立的侦听分析线程。

     

    IPHEADER 和 TCPHEADER的定义分别如下。

    typedef struct ip_head      //定义IP首部

    {

    unsigned char h_verlen;    //4位首部长度,4位IP版本号

    unsigned char tos;         //8位服务类型TOS

    unsigned short total_len;  //16位总长度(字节)

    unsigned short ident;      //16位标识

    unsigned short frag_and_flags; //3位标志位(如SYN,ACK,等)

    unsigned char ttl;         //8位生存时间 TTL

    unsigned char proto;       //8位协议 (如ICMP,TCP等)

    unsigned short checksum;   //16位IP首部校验和

    unsigned int sourceIP;     //32位源IP地址

    unsigned int destIP;       //32位目的IP地址

    }IPHEADER;

     

    typedef struct tcp_head //定义TCP首部

    {

    USHORT th_sport;        //16位源端口

    USHORT th_dport;        //16位目的端口

    unsigned int th_seq;    //32位序列号

    unsigned int th_ack;    //32位确认号

    unsigned char th_lenres;    //4位首部长度/6位保留字

    unsigned char th_flag;  //6位标志位

    USHORT th_win;      //16位窗口大小

    USHORT th_sum;     //16位校验和

    USHORT th_urp;     //16位紧急数据偏移量

    }TCPHEADER;

     

    侦听搞定了,剩下的问题就是怎么构造SYN 包发送了。一般SYN包的发送都是自己构造IP头和TCP头部,然后用一个TCP伪头来计算效验和,一般情况下这样打造的。这样自己造SYN也是可以的, 但是我们的程序效率就会大大降低,我们用另外一个高效率方法。怎么才可以发出一个SYN包而不用自己构造呢?知道有个connect()API吗?本来那 是用来建立联接用的。它里面就隐藏了TCP的三次握手,如果我们在发出一个SYN包后就关闭套结字,是不是就能起到发一个SYN包的功效了啊?所以就必须 设置套结字为非阻塞的。

     

    2. 发SYN包的实现如下。

    DWORD  WINAPI  scan(LPVOID lp)

    {

    //lp为自己定义的一个结构地址,用来传递扫描目标的IP地址和端口信息。

    //  如下:

    //  typedef struct        //定义一个传递IP和端口,信息的结构

    //  {

    //  ULONG   IP;

    //  USHORT  port;

    //   }INFOR;

     

    SOCKET sock=NULL;

    SOCKADDR_IN addr_in={0};

    TCHAR      SendBuf[256]={0};

    INFOR*     lpInfor=(INFOR*)lp;

    int    iErr;

    ULONG     ul=1; 

    USHORT port=lpInfor->port;

    addr_in.sin_family=AF_INET;

    addr_in.sin_port=htons(port);

    addr_in.sin_addr.S_un.S_addr=lpInfor->IP;

    if ((sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==INVALID_SOCKET)

    printf("Socket Setup Error!\n");

    iErr=ioctlsocket(sock,FIONBIO,(unsigned long*)&ul); //设置sock为非阻塞

    connect(sock,(struct sockaddr *)&addr_in,sizeof(addr_in));  //发送SYN包

    closesocket(sock);

    return 0;

    }

     

    最主要的侦听和发送线程都完成了,剩下的就只是,怎么提取IP地址和端口然后传给发送函数了

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

    {

    WSADATA WSAData;

    INFOR   infor={0};

    ULONG StartIP=0, EndIP=0;

    int   number=0;

    if ( WSAStartup(MAKEWORD(2,2), &WSAData)!=0 )

    {

        printf("InitWSAStartup Error!\n");

        return 0;

    }

     //创建一个嗅包的线程分析接收到的包。

    CreateThread(NULL,0,ListeningFunc,&tempnum,NULL,NULL);

    Sleep(500); //等待线程的初始化完成

    ULONG StartIP=0, EndIP=0;

    StartIP=ntohl(inet_addr(argv[1]));

    EndIP  =ntohl(inet_addr(argv[2]));

    for ( ; StartIP <= EndIP ; StartIP++)   //从第一个IP到最后一个IP

    {

       infor.IP=htonl(StartIP);    

       int   Num=ListNum;       //ListNum为定义的端口列表的长度

       while ( Num-- )

       {        

        infor.port=PortList[Num];  //从列表中取得端口值,准备传递给发包函数

        scan(&infor);              //对目标IP,端口发送SYN包.

     

        }

       

     } //end for

    Sleep(2000);  //最后等待2s,等最后发出的包返回。

    printf("Scan completely.");

    return 1;

    } //主线程返回  程序结束。

     

    以上全部代码基本上就是一个扫描器了。根据实际测试上面的这种扫描方法速度是相当快的。

     

    . CGI的扫描器

    CGI 的扫描前提是开放了80(Web服务)才可以利用的。首先我们必须和远程的80端口建立联接。然后通过提交GET请求,再根据返回的信息加以判断的。例如 返回的200代表成功,一切正常。404代表无法找到指定位置的资源。403代表资源不可用等。然后我们侦听返回的数据是不是有"HTTP/1.1 200"这样的子串。有代表请求成功,否则请求失败。

    大致的实现如下:

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

    {

    WSADATA WSAData;

    FILE* fp=NULL;

    fp= fopen("cgi.lst","r");

    //cgi.lst是个CGI漏洞的列表里面的全部是类似"GET /_vti_bin/shtml.exe"这样的。

    WSAStartup(MAKEWORD(2,2), &WSAData);

    INFOR  infor={0};

    // INFOR  结构用来传递CGI信息和IP信息

    // 定义如下:

    // typedef  struct

    // {

    //  char sendbuf[100];

    //  char IP[20];

    // }INFOR;

     

    if (argc !=2 ) return 0;

    memcpy (infor.IP,argv[1],strlen(argv[1]));

    printf("Scan start.......\n");

    // 从文件中读取要扫描的CGI信息

    while ( fgets(infor.sendbuf,100,fp) !=NULL )

    {

        HANDLE h=0;

        h=CreateThread(NULL,0,scan,&infor,NULL,NULL);  //创建一个线程扫描

        if ( h == NULL )

        printf("CreateThread false\n");

        WaitForSingleObject(h,INFINITE);  //等待一次扫描结束

        memset(infor.sendbuf,0,100);

    }  

    printf("Scan completely.\n");

    // end main

    scan线程定义如下:

    DWORD  WINAPI  scan(LPVOID lp)

    {

        SOCKET      sock=NULL;

        SOCKADDR_IN  target={0};

        int   error=0;

        char  buf[256]={0};

        char* p=NULL;

        INFOR* lpInfor =(INFOR*)lp;

        if ( (sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==INVALID_SOCKET)

        {

            printf("Socket Setup Error!\n");

            return false;

        }

        target.sin_family=AF_INET;

        target.sin_port=htons(80);

        target.sin_addr.S_un.S_addr=inet_addr(lpInfor->IP);

        error=connect (sock, (struct sockaddr* )&target, sizeof(target)); //连接

        if (error == SOCKET_ERROR)

        {

            printf("Connect false!\n");

            return 0;

        }

        send(sock,lpInfor->sendbuf,100,0);  //发送GET请求

        recv(sock,buf,256,0);       //接收返回的信息

        p=strstr(buf,"HTTP/1.1 200");  //查找返回的信息中有有没有HTTP/1.1 200子串。

        if ( p!=NULL)   //200的意思是一切正常,对GET和POST请求的应答文档跟在后面

        {

            printf("%s",lpInfor->sendbuf);  //把扫描到的漏洞打出来

        }

        closesocket(sock);

        return 1;

    }

    如转载:请说明作者信息,表明首发刊物。

    发表于 @ 2005年03月06日 14:39:00|评论(loading...)|编辑

    新一篇: arp 欺骗的技术原理及应用 | 旧一篇: DIY一个简单共享儒虫

    评论:没有评论。

    发表评论  


    当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
    Csdn Blog version 3.1a
    Copyright © LionD8