CGI扫描器的原理和实现过程

gugu 2001-08-07 03:40:34
加精

本 作者: eyas 发表日期: 2001-06-11 20:56:20 返回《黑客也是侠》 快速返回

 

有很多网站为了安全起见,在WEB Server前面架了防火墙,或者做了TCP/IP过滤,对外只开放TCP 80 端口。从入侵者角度来看,要入侵那么从80上跑的CGI入手是比较可行的,当然也可以用别的办法,例如旁敲侧击,呵呵。从网管角度来看,一是要保证CGI的安全性,另外网络的整体安全性也是很重要的。针对基于80端口入侵、防范而出的CGI扫描器数不胜数,但基本上原理都一样。


    CGI扫描器原理说起来其实非常简单,可以用四句话来概括:<1>连接目标WEB SERVER;<2>发送一个特殊的请求;<3>接收目标服务器返回数据;<4>根据返回数据判断目标服务器是否有此CGI漏洞。


   当管理的服务器达到一定数量的时候,手工检测自己的服务器是否存在各种各样的CGI漏洞,那就太消耗时间和精力了,所以一个网管手上有个比较好用的CGI漏洞扫描器还是必要的。OK!今天我们就自己来动手用C写一个简单的CGI扫描器,帮助自己在日常工作中检测服务器:))


   源代码如下,很多地方我都加了注释,别嫌我烦哦:))编译好的程序可以从http://eyas.3322.net/program/cgicheck.exe下载。


/*************************************************************************


Module:CGICheck.cpp


Author:ey4s<ey4s@21cn.com>


Date:2001/5/16


说明:这是一个Console下多线程,带有进度显示的CGI扫描器的模板,更改一下szSign和SendBuff就可以扫描其他CGI漏洞,设置了连接、发送、接收超时,速度还可以哦。希望可以帮助到admins检测自己的服务器:))


*************************************************************************/


#include <stdio.h>


#include <winsock2.h>


#include <time.h>





#define iPort 80//目标Web Server端口


#define szSign "500 13\r\nServer: Microsoft-IIS/5.0"//根据此标志来检查目标是否有漏洞





#pragma comment(lib,"ws2_32.lib")


///////////////////////////////////////////////////////////////////////////


//


//定义&初始化全局变量


//


char *SendBuff="GET /NULL.printer\n",//发送的请求buff


    CurrentTarget[52]={0},//存放最后一个线程将扫描的目标


    turn[4][2]={"-","\\","|","/"};//显示进度时的字符


int SendBuffLen=strlen(SendBuff),//发送的buff长度


    iConnTimeout,//TCP Connect TimeOut


    ii=0,//扫描进度


    iTotal;//服务器总数


HANDLE hSemaphore=NULL,//信标内核对象句柄,用来控制线程数量


       hStdout;//console标准输出句柄,做进度显示的时候用的


struct timeval timeout;//连接、发送和接收的超时值


DWORD SleepTime;//每个一个线程后等待的时间


    /*


    SleepTime值根据用户输入的线程数量[ThreadNum]和TCP ConnectTimeOut[CONNTIMEO]来计算。确保在CONNTIMEO时间左右开    ThreadNum个线程。这样在CONNTIMEO时间后,所开的线程开始陆续超时退出,可以继续稳定的开线程,可以有效的保证同时有    ThreadNum个线程在运行。


    */


///////////////////////////////////////////////////////////////////////////


void ShowError(char *);//显示出错信息函数,可以写完善一些,偶偷懒了:)


BOOL ResetCursor(void);//重置光标位置,线程输出的时候调用的


DWORD WINAPI ShowProInfo(LPVOID);//显示进度信息


DWORD WINAPI scan(LPVOID);//扫描函数


void usage(char *);//帮助函数


///////////////////////////////////////////////////////////////////////////


int main(int argc,char **argv)


{


    HANDLE hThread=NULL;//线程句柄


    DWORD dwThreadID;//线程ID


    struct sockaddr_in sa;


    int i,


       MaxThread;//最大线程数量


    WSADATA    wsd;


    long PreviousCount;


    clock_t start,end;//程序运行的起始和结束时间


    double duration;





    //检查用户输入参数


    if(argc!=5)


    {


       usage(argv[0]);


       return 1;


    }


    //get target range


    int StartNet=inet_addr(argv[1]);


    int StopNet=inet_addr(argv[2]);


    int StartHost=ntohl(StartNet);


    int StopHost=ntohl(StopNet);


    //取得线程数量


    MaxThread=atoi(argv[3]);


    //取得conn超时时间


    iConnTimeout=atoi(argv[4]);


    //检查参数合法性


    if((iConnTimeout>6) || (iConnTimeout<2) || (MaxThread<1) || (MaxThread>500) || (StopHost<StartHost))


    {


       usage(argv[0]);


       return 1;


    }


    //计算时间


    SleepTime=1000*iConnTimeout/MaxThread;


    //设置连接超时值


    timeout.tv_sec = iConnTimeout;


    timeout.tv_usec =0;


    __try


    {


       //开始计时


       start=clock();


       //加载winsock库


       if (WSAStartup(MAKEWORD(1,1), &wsd) != 0)


       {


           ShowError("WSAStartup");


           __leave;


       }


       //创建信标内核对象句柄


       hSemaphore=CreateSemaphore(NULL,MaxThread,MaxThread,NULL);


       if(hSemaphore==NULL)


       {


           ShowError("CreateSemaphore");


           __leave;


       }


       //取得console标准输出句柄


       hStdout=GetStdHandle(STD_OUTPUT_HANDLE);


       if(hStdout==INVALID_HANDLE_VALUE)


       {


           ShowError("GetStdHandle");


           __leave;


       }


       //设置目标总数


       iTotal=StopHost-StartHost;


       //创建进度显示线程


       hThread=CreateThread(NULL,0,ShowProInfo,NULL,0,&dwThreadID);


       if(hThread==NULL)


       {


           ShowError("1 CreateThread");


           __leave;


       }


//关闭句柄


       CloseHandle(hThread);


       //循环创建扫描线程


       for(i=StartHost;i<=StopHost;i++)


       {


           //等待信标内核对象通知


           WaitForSingleObject(hSemaphore,INFINITE);


           //create thread to scan


           hThread=CreateThread(NULL,0,scan,(LPVOID)i,0,&dwThreadID);


           if(hThread==NULL)


           {


              ShowError("2 CreateThread");


              break;


           }


           //进度自加1


           ii++;


           //重设最后一个线程扫描的目标


           sa.sin_addr.s_addr=htonl(i);


           strncpy(CurrentTarget,inet_ntoa(sa.sin_addr),sizeof(CurrentTarget));


           //休息一会儿:))


           Sleep(SleepTime);


           //关闭线程句柄


           CloseHandle(hThread);


       }


       //等待所有线程结束


       while(1)


       {


           WaitForSingleObject(hSemaphore,INFINITE);


           if(!ReleaseSemaphore(hSemaphore,1,&PreviousCount))


           {


              ShowError("main() ReleaseSemaphore");


              Sleep(5000);


              break;


           }


           if(PreviousCount==(MaxThread-1))


           {


              printf("\nAll done.");


              break;


           }


           Sleep(500);


       }


    }//end of try


    //搞定,清场,收工


    __finally


    {


       //计时结束


       end=clock();


       //转换时间格式


       duration = (double)(end - start) / CLOCKS_PER_SEC;


       //显示所用时间


       printf("\n\nComplete.Scan %d targets use %2.1f seconds.Speed %0.3g/s\n",iTotal,duration,iTotal/duration);


       //关闭句柄


       CloseHandle(hStdout);


       CloseHandle(hSemaphore);


       WSACleanup();


    }


    return 0;


}


///////////////////////////////////////////////////////////////////////////


//


//回显错误信息函数


//


void ShowError(char *msg)


{


    MessageBox(NULL,msg,"ERROR",0);


    //printf("\n%s failed:%d",GetLastError());


}


//////////////////////////////////////////////////////////////////////////


//


//重置光标位置函数,以便扫描线程输出结果


//


BOOL ResetCursor()


{


    CONSOLE_SCREEN_BUFFER_INFO ConsoleScreenBufferInfo;


    //取得当前光标位置


    if(!GetConsoleScreenBufferInfo(hStdout,&ConsoleScreenBufferInfo))


    {


       ShowError("GetConsoleScreenBufferInfo");


       return FALSE;


    }


    //设置光标X坐标为0


    ConsoleScreenBufferInfo.dwCursorPosition.X=0;


    //设置当前光标位置


    SetConsoleCursorPosition(hStdout,ConsoleScreenBufferInfo.dwCursorPosition);


    return TRUE;


}


///////////////////////////////////////////////////////////////////////////


//


//显示进度信息函数


//


DWORD WINAPI ShowProInfo(LPVOID lp)


{  


    int j,k;


    CONSOLE_SCREEN_BUFFER_INFO ConsoleScreenBufferInfo;


    float m;


    for(j=0;ii<iTotal;j++)


    {


       //休息一会儿:)))


       Sleep(SleepTime);


       //取得当前光标位置


       if(!GetConsoleScreenBufferInfo(hStdout,&ConsoleScreenBufferInfo))


       {


           ShowError("GetConsoleScreenBufferInfo");


           return 1;


       }


       //设置百分比进度显示的X坐标


       ConsoleScreenBufferInfo.dwCursorPosition.X=0;


       //设置当前光标位置


       SetConsoleCursorPosition(hStdout,ConsoleScreenBufferInfo.dwCursorPosition);


       //已经完成的百分比


       m=(ii+1)*100.00/iTotal;


       //显示进度


       if(ii==iTotal)


       {


           printf("******** 100%% Wait %d seconds to exit ********       \n",iConnTimeout);


           break;


       }


       else


       {


           k=j%4;


           printf("%-15s %s [%d/%d] %s %%%0.3g",CurrentTarget,turn[k],ii,iTotal,turn[k],m);


       }


    }//end of for


    return 0;


}


///////////////////////////////////////////////////////////////////////////


//


//扫描函数


//


DWORD WINAPI scan(LPVOID lp)


{


    int i=(int)lp,iErr;


    struct sockaddr_in server;


    SOCKET s=INVALID_SOCKET;


    char RecvBuff[1024]={0},*ptr;


    int RecvBuffLen=sizeof(RecvBuff);


    u_long ul=1;//初始化为为非0值


  fd_set r,w;





    //create socket


    s=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);


    if(s==INVALID_SOCKET)


    {


       printf("\nCreate socket failed:%d",GetLastError());


       ExitProcess(1);


    }


    //fill the addr struct


    server.sin_family=AF_INET;


    server.sin_port=htons(iPort);


    server.sin_addr.S_un.S_addr=htonl(i);


    __try


    {


       //设置socket为非锁定模式,ul为0值的话,那么soocket将被设置为锁定模式


       iErr=ioctlsocket(s,FIONBIO,(unsigned long*)&ul);


       if(iErr==SOCKET_ERROR )


       {


           ResetCursor();


           ShowError("ioctlsocket");


           ExitProcess(1);


       }


       //printf("\n%X ioctl ok.strat conn",i);


       //connect to target


       connect(s,(struct sockaddr *)&server,sizeof(server));


       //printf("\n%X conn return,start select w",i);


       //设置select参数


       FD_ZERO(&w);


       FD_SET(s, &w);


       //等待connect成功&socket可写


       iErr=select(0, 0, &w, 0, &timeout);


       //printf("\n%X select w return %d",i,iErr);


       //等待返回后,socket仍不可写则退出


       if((iErr==SOCKET_ERROR) || (iErr==0))


       {


           //printf("\n%X select return w err,exit",i);


           __leave;


       }


       //socket可写则继续


       else


       {


           //send buff to target


           //printf("\n%X send",i);


           iErr=send(s,SendBuff,SendBuffLen,0);


           //printf("\n%X send return",i);


           if(iErr==SOCKET_ERROR)


              __leave;


       }


       //等待socket可读


       FD_ZERO(&r);


       FD_SET(s, &r);


       //printf("\n%X start select r",i);


       iErr=select(0, &r, 0, 0, &timeout);


       //printf("\n%X select r return %d",i,iErr);


       if((iErr==SOCKET_ERROR) || (iErr==0))


       {


           //printf("\n%X select r err,exit",i);


           __leave;


       }


       else


       {


           //recv buff from target


           //printf("\n%X start recv",i);


           iErr=recv(s,RecvBuff,RecvBuffLen,0);


           //printf("\n%X recv ret",i);


           if(iErr==SOCKET_ERROR)


              __leave;


       }


       //verify buff


       ptr=strstr(RecvBuff,szSign);


       if(ptr!=NULL)


       {


           //线程输出前要先调用ResetCursor函数


           ResetCursor();


           //输出信息后务必加一个以上换行符号,输出前请别加换行符号,以免显示混乱


           printf("[%-15s] has .printer mapped.        \n",inet_ntoa(server.sin_addr));


       }


    }


    __finally


    {


       if(!ReleaseSemaphore(hSemaphore,1,NULL))


           ShowError("thread ReleaseSemaphore failed");


       closesocket(s);


    }


    return 0;


}


///////////////////////////////////////////////////////////////////////////


void usage(char *proname)


{


    printf("\n%s v0.1 only can find IIS5 .Printer mapped"


       "\nPower by ey4s<ey4s@21cn.com> 2001.5.20"


       "\nhttp://www.patching.net"


       "\n\nUsage:%s <StartIP> <EndIP> <ThreadNum> <CONNTIMEO>"


       "\n\nNotice"


       "\n    StartIP StopIP ==>Don't forgot StopIP must large than StartIP "


       "\n    ThreadNum ==>Thread number,please input between 1-500"


       "\n    CONNTIMEO ==>TCP connect timeout,please input between 2-6"


       "\n\nExample"


       "\n    %s 192.168.0.0 192.168.255.255 200 2",proname,proname,proname);


}


   程序在VC++6.0上编译通过,在windows2000上运行良好:)




 前方啊 没有方向 
 身上啊 没有了衣裳 
 鲜血啊 渗出了翅膀 
 我的眼泪 湿透了胸膛 
 孤独的雏鹰飞翔着 强忍着伤 


--------------------------------------------------------------------------------


回应人: 深蓝色的海 发表日期: 2001-06-11 21:29:28

谢谢

及时雨 啊


 终于明白感情的规则是沉默 
  
 而话语往往在脱口而出的瞬间 
  
 变的苍白无力  
   
   
  
深蓝色的海


--------------------------------------------------------------------------------


回应人: begwolf 发表日期: 2001-06-11 23:00:15

酷B了!!

 临渊羡鱼不如退而结网!! 
小海的EMAIL


--------------------------------------------------------------------------------


回应人: 浪哥 发表日期: 2001-06-12 00:08:22

应该是很有用的教材



 紧张的毕业设计中…… 
天府之空了吹


--------------------------------------------------------------------------------


回应人: wish? 发表日期: 2001-06-12 10:53:25

wonderful.


 壮哉!!! 


--------------------------------------------------------------------------------


回应人: lifemaster 发表日期: 2001-07-06 09:03:56

哈哈!!
看来你是“红客”了!


 我热爱生活,只是为了报复生命。 


--------------------------------------------------------------------------------


返回《黑客也是侠》 快速返回
...全文
1210 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
netken 2001-08-08
  • 打赏
  • 举报
回复
怎么感觉着这些东西用perl 30行左右就写出来了啊
puffdream 2001-08-08
  • 打赏
  • 举报
回复
好东西。爽
111222 2001-08-08
  • 打赏
  • 举报
回复
.printer漏洞啊
XXLong 2001-08-08
  • 打赏
  • 举报
回复
我最佩服这样的高手了!

9,506

社区成员

发帖
与我相关
我的任务
社区描述
Windows专区 安全技术/病毒
社区管理员
  • 安全技术/病毒社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧