分享
 
 
 

端口和CGI的扫描实现

王朝other·作者佚名  2006-01-31
窄屏简体版  字體: |||超大  

端口和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;

}

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

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有