3389等端口入侵实例解析
为了提升网站安全性,许多网站会在Web服务器前端部署防火墙,或实施TCP IP过滤策略,仅对外开放80端口。从攻击者视角来看,通过80端口上的CGI程序发起攻击是最直接的入侵途径——当然,也存在其他间接攻击手段。而从网络管理员的角度,既要确保CGI脚本自身的安全性,同时也要关注整个网络的安全防护。市
为了提升网站安全性,许多网站会在Web服务器前端部署防火墙,或实施TCP/IP过滤策略,仅对外开放80端口。从攻击者视角来看,通过80端口上的CGI程序发起攻击是最直接的入侵途径——当然,也存在其他间接攻击手段。而从网络管理员的角度,既要确保CGI脚本自身的安全性,同时也要关注整个网络的安全防护。市面上针对80端口的CGI扫描器种类繁多,但它们的核心工作原理基本一致。
CGI扫描器的工作原理极为简洁,用四步即可概括:首先,连接目标Web服务器;其次,发送一个特制的请求;然后,接收服务器响应的数据;最后,根据响应内容判断目标服务器是否存在对应的CGI漏洞。
当管理的服务器数量增长到一定规模时,手动逐个检测CGI漏洞将变得极其耗时费力,如同噩梦一般。因此,对于网络管理员而言,拥有一款好用的CGI漏洞扫描工具显得十分必要。那么,今天我们就亲手用C语言编写一个简易的CGI扫描器,用于日常服务器的安全检测。
以下是完整的源代码,代码中已添加大量注释,以帮助理解。该代码在VC 6.0环境下编译通过,并在Windows 2000系统上运行良好。
/*************************************************************************
Module:CGICheck.cpp
Author:ey4s
Date:2001/5/16
说明:这是一个Console下多线程,带有进度显示的CGI扫描器的模板,
更改一下szSign和SendBuff就可以扫描其他CGI漏洞,
设置了连接、发送、接收超时,速度还可以。
希望可以帮助到admins检测自己的服务器:)
*************************************************************************/
#include
#include
#include
#include
#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\r\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;
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;
}
// 获取目标IP范围
int StartNet=inet_addr(argv[1]);
int StopNet=inet_addr(argv[2]);
int StartHost=ntohl(StartNet);
int StopHost=ntohl(StopNet);
// 取得线程数量
MaxThread=atoi(argv[3]);
// 取得连接超时时间
iConnTimeout=atoi(argv[4]);
// 检查参数合法性
if((iConnTimeout>6) || (iConnTimeout<2) ||
(MaxThread>500) || (MaxThread<1) ||
(StopHost0xFFFFFFFF) || (StartHost>0xFFFFFFFF))
{
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");
__lea ve;
}
// 创建信标内核对象句柄
hSemaphore=CreateSemaphore(NULL,MaxThread,MaxThread,NULL);
if(hSemaphore==NULL)
{
ShowError("CreateSemaphore");
__lea ve;
}
// 取得console标准输出句柄
hStdout=GetStdHandle(STD_OUTPUT_HANDLE);
if(hStdout==INVALID_HANDLE_VALUE)
{
ShowError("GetStdHandle");
__lea ve;
}
// 设置目标总数
iTotal=StopHost-StartHost;
// 创建进度显示线程
hThread=CreateThread(NULL,0,ShowProInfo,NULL,0,&dwThreadID);
if(hThread==NULL)
{
ShowError("1 CreateThread");
__lea ve;
}
CloseHandle(hThread);
// 循环创建扫描线程
for(i=StartHost; i=iTotal)
break;
// 计算百分比
m=100.0*ii/iTotal;
// 重置光标位置
ResetCursor();
// 输出进度信息
j=ii;
if(j>=iTotal) j=iTotal-1;
if(j<0) j=0;
// 根据当前进度选择字符
k=j%4;
printf("%-15s %s [%d/%d] %s %%%0.3g",CurrentTarget,turn[k],ii,iTotal,turn[k],m);
}
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;
// 创建socket
s=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(s==INVALID_SOCKET)
{
printf("\nCreate socket failed:%d",GetLastError());
ExitProcess(1);
}
// 填充地址结构
server.sin_family=AF_INET;
server.sin_port=htons(iPort);
server.sin_addr.S_un.S_addr=htonl(i);
__try
{
// 设置socket为非阻塞模式
iErr=ioctlsocket(s,FIONBIO,(unsigned long*)&ul);
if(iErr==SOCKET_ERROR )
{
ResetCursor();
ShowError("ioctlsocket");
ExitProcess(1);
}
// 连接目标
connect(s,(struct sockaddr *)&server,sizeof(server));
// 设置select参数,等待连接成功且socket可写
FD_ZERO(&w);
FD_SET(s, &w);
iErr=select(0, 0, &w, 0, &timeout);
// 如果socket仍不可写,则退出
if((iErr==SOCKET_ERROR) || (iErr==0))
{
__lea ve;
}
// socket可写,发送请求
iErr=send(s,SendBuff,SendBuffLen,0);
if(iErr==SOCKET_ERROR)
__lea ve;
// 等待socket可读
FD_ZERO(&r);
FD_SET(s, &r);
iErr=select(0, &r, 0, 0, &timeout);
if((iErr==SOCKET_ERROR) || (iErr==0))
{
__lea ve;
}
// 接收数据
iErr=recv(s,RecvBuff,RecvBuffLen,0);
if(iErr==SOCKET_ERROR)
__lea ve;
// 验证返回数据中是否包含漏洞标志
ptr=strstr(RecvBuff,szSign);
if(ptr!=NULL)
{
// 线程输出前要先重置光标位置
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 StartIP StopIP 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);
}
代码的关键部分已添加详细注释,只需修改szSign和SendBuff这两个参数,即可扩展扫描其他CGI漏洞。该扫描器支持多线程并发扫描,具备进度显示功能,并设置了连接、发送、接收的超时机制,扫描速度表现良好。希望这个工具能帮助各位网络管理员更高效地检测自身服务器的安全性。

