80埠入侵 CGI掃描器的原理和實現過程(轉)

ljm0211發表於2012-07-02
很多網站為了安全起見,在WEB Server懊婕芰朔闌鵯劍 蛘咦雋薚CP/IP過濾,對外只開放TCP 80 埠。從入侵者角度來看,要入侵那麼從80上跑的CGI入手是比較可行的,當然也可以用別的辦法,例如旁敲側擊,呵呵。從網管角度來看,一是要保證CGI 的安全性,另外網路的整體安全性也是很重要的。針對基於80埠入侵、防範而出的CGI掃描器數不勝數,但基本上原理都一樣。CGI掃描器原理說起來其實 非常簡單,可以用四句話來概括:
<1>連線目標WEBSERVER;
<2>傳送一個特殊的請求;
<3>接收目標伺服器返回資料;
<4>根據返回資料判斷
目標伺服器是否有此CGI漏洞。
當管理的伺服器達到一定數量的時候,手工檢測自己的伺服器是否存在各種各樣的CGI
漏洞,那就太消耗時間和精力了,所以一個網管手上有個比較好用的CGI漏洞掃描器還是
必要的。OK!今天我們就自己來動手用C寫一個簡單的CGI掃描器,幫助自己在日常工作
中檢測伺服器:))
原始碼如下,很多地方我都加了註釋,別嫌我煩哦:))編譯好的程式可以從
下載。
/*************************************************************************
Module:CGICheck.cpp
Author:ey4s
Date:2001/5/16
說明:這是一個Console下多執行緒,帶有進度顯示的CGI掃描器的模板,更改一下szSign
和SendBuff就可以掃描其他CGI漏洞,設定了連線、傳送、接收超時,速度還可以哦。希
望可以幫助到admins檢測自己的伺服器:))
*************************************************************************/
#i nclude
#i nclude
#i nclude

#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]=,//存放最後一個執行緒將掃描的目標
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 {
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 {
//休息一會兒:)))
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]=,*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 2001.5.20"
"\"
"\n\nUsage:%s "
"\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上執行良好:)

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/11411056/viewspace-734409/,如需轉載,請註明出處,否則將追究法律責任。

相關文章