端口扫描程序的设计49681
- 格式:doc
- 大小:264.50 KB
- 文档页数:16
课程设计题目:端口扫描程序设计院、系:计算机科学与技术学院网络工程系班级:学号:姓名:同组成员:指导教师:成绩:一.系统设计的目标:扫描器是网络信息收集的一种方法,从功能上可分为漏洞扫描器和端口扫描器。
通过此次课程设计,能够掌握漏洞、端口的基础知识,掌握扫描器的基本原理并设计实现端口扫描和漏洞扫描程序。
二.系统原理:常用的端口扫描技术有以下几种:2.1 TCP connect()扫描:2.1.1简介:这是最基本的TCP扫描,操作系统提供的connect()系统调用可以用来与每一个感兴趣的目标计算机的端口进行连接。
如果端口处于侦听状态,那么connect()就能成功。
否则,这个端口是不能用的,即没有提供服务。
2.2.2优点:不需要任何权限。
系统中的任何用户都有权利使用这个调用。
另一个好处就是速度,如果对每个目标端口以线性的方式,使用单独的connect()调用,那么将会花费相当长的时间,使用者可以通过同时打开多个套接字来加速扫描。
使用非阻塞I/O允许你设置一个低的时间用尽周期,同时观察多个套接字。
2.2.3 缺点:很容易被察觉,并且被防火墙将扫描信息包过滤掉。
目标计算机的logs文件会显示一连串的连接和连接出错消息,并且能很快使它关闭。
2.2 TCP SYN扫描:2.2.1简介:这种技术通常认为是“半开放”扫描,这是因为扫描程序不必要打开一个完全的TCP 连接。
扫描程序发送的是一个SYN数据包,好象准备打开一个实际的连接并等待反应一样(参考TCP的三次握手建立一个TCP连接的过程)。
一个SYN|ACK的返回信息表示端口处于侦听状态:返回RST表示端口没有处于侦听态。
如果收到一个SYN|ACK,则扫描程序必须再发送一个RST信号,来关闭这个连接过程。
2.2.2优点:一般不会在目标计算机上留下记录。
2.2.3缺点:必须要有root权限才能建立自己的SYN数据包。
2.3 TCP FIN 扫描:2.3.1简介:SYN扫描虽然是“半开放”方式扫描,但在某些时候也不能完全隐藏扫描者的动作,防火墙和包过滤器会对管理员指定的端口进行监视,有的程序能检测到这些扫描。
相反,FIN数据包在扫描过程中却不会遇到过多问题,这种扫描方法的思想是关闭的端口会用适当的RST来回复FIN数据包。
另一方面,打开的端口会忽略对FIN数据包的回复。
这种方法和系统的实现有一定的关系,有的系统不管端口是否打开都会回复RST,在这种情况下此种扫描就不适用了。
另外这种扫描方法可以非常容易的区分服务器是运行Unix系统还是NT系统。
2.3.2优点:SYN扫FIN数据包可以不惹任何麻烦的通过。
2.3.3缺点:这种方法和系统的实现有一定的关系,有些系统不论是打开的或关闭的端口对FIN 数据包都要给以回复,这种情况下该方法就不实用了。
2.4 IP段扫描:2.4.1简介:这种扫描方式并不是新技术,它并不是直接发送TCP探测数据包,而是将数据包分成两个较小的IP段。
这样就将一个TCP头分成好几个数据包。
2.4.2优点:过滤器就很难探测到。
2.4.3缺点:一些程序在处理这些小数据包时会有些麻烦。
2.5 TCP 反向 ident扫描:2.5.1简介:ident 协议允许(rfc1413)看到通过TCP连接的任何进程的拥有者的用户名,即使这个连接不是由这个进程开始的。
例如扫描者可以连接到http端口,然后用identd 来发现服务器是否正在以root权限运行。
2.5.2优点:通过TCP连接的任何进程的拥有者的用户名。
2.5.3缺点:这种方法只能在和目标端口建立了一个完整的TCP连接后才能看到。
2.6 FTP 返回攻击2.6.1简介:FTP协议的一个有趣的特点是它支持代理(proxy)FTP连接,即入侵者可以从自己的计算机和目标主机的FTP server-PI(协议解释器)连接,建立一个控制通信连接。
然后请求这个server-PI激活一个有效的server-DTP(数据传输进程)来给Internet上任何地方发送文件。
2.6.2优点:建立一个控制通信连接。
2.6.3缺点:能用来发送不能跟踪的邮件和新闻,给许多服务器造成打击,用尽磁盘,企图越过防火墙。
三. 系统功能分析:作为端口扫描程序,首先需要完成的功能就是对于系统操作系统的服务端口进行扫描,返回扫描结果。
对于端口的扫描,包括对于本机系统服务端口,局域网内目标机系统,以及远程IP的系统服务端口进行扫描。
有些时候,用户并不需要去扫描整个系统的所有端口,因为这样的话不仅会浪费大量的时间,而且可能导致难以找到自己需要了解的端口的扫描结果。
所以,对于选择性地对端口进行扫描也非常重要。
这当然也是扫描程序需要实现的功能之一。
用户在等待扫描的时候,往往希望知道它的工作进度。
这样用户可以更好地控制自己的操作。
站在用户的角度思考,设置进度是程序需要完成的,这样就能知道程序扫描的进度。
系统必须提供的服务是功能需求的基本,本着站在用户角度思考的原则,做出如上叙述需求,从简列举如下:扫描功能;地址选择功能;端口选择功能;本程序主要实现了简易的TCP connect()扫描,对TCP扫描支持多线程扫描。
四.系统实现:4.1步骤:4.1.1 先输入想要扫描的网段;4.1.2 然后将输入的网段转化为可排序的ip数组4.1.3 建立多个线程,每个线程扫描一个ip。
每个线程内先建立数据流套接字,然后绑定ip端口进行扫描。
将扫描端口保存到g_map_ScanResult。
4.1.4 清理结束后进程,输出结果。
4.1.5 计算所用时间。
4.2 程序中主要的函数:程序简介int main();主函数InitProc();初始化UserInput();输入ScanIp(g_startIp,g_endIp,g_map_ScanResult);开始扫描CleanProc();清理结束后进程OutPutScanInfo();输出结果DWORD WINAPI ThreadFunc(LPVOID th_para) 扫描线程每一个ip unsigned long InvertIp(unsigned long srcIp) 将ip化为长整型将所有ip排序放在一个数组内int GetIpToScan(const string &StartIp, conststring &EndIp, vector<unsigned long> &vec_ip)4.3 实验结果:图4-1 开始界面图4-2 扫描界面图4-3 扫描结果附录:源程序代码:#pragma comment(lib,"ws2_32.lib")#pragma warning (disable:4786)#include <iostream>#include <strstream>#include <winsock2.h>#include <string>#include <vector>#include <map>#include <fstream>#include <time.h>//#include "IpScan.h"using namespace std;//全局变量://待扫描的端口short g_portsTOscan[]= {20,21,22,23,25,42,43,47,53,63,67,68,79,80,95,106,107,109,110,113,135,137,138,139,143,144,161,162,443,445,1024,1080,1433,1434,1755,3306,4000,5010,5190,5631,5632,8000,8080 } ;const short PORTSNUM = sizeof(g_portsTOscan) / sizeof(short);//端口个数//等扫描的IPvector<unsigned long> g_vec_IpToScan;string g_startIp;string g_endIp;//开启的线程数,目前为1个IP1个线程long g_runThreadNum;//socket相关TIMEVAL g_timeout; //阻塞等待时间//FD_SET g_mask; //socket模式设置,储存socket信息const short TIMEOUT = 1; //阻塞等待时间WSADATA g_wsadata; //socket版本信息//线程中的互斥体HANDLE g_PortMutex;HANDLE g_ThreadNumMutex;HANDLE g_ResultMutex; //输入结果的互斥量//保存IP扫描的结果multimap<unsigned long, string> g_map_ScanResult;//-------------------------------------------------------------------------------------------------------------------//线程函数,扫描每一个IPDWORD WINAPI ThreadFunc(LPVOID th_para){//获取需要扫描的IP//char *pStrIp = (char*)th_para;unsigned long ulScanIp = *(unsigned long*)th_para;int index = 0; //端口索引SOCKET link_sock; //SOCKETFD_SET set_flag; //SOCKET描述short select_ret; //select异步返回值short port; //正在扫描的端口while (index < PORTSNUM){port = g_portsTOscan[index];//创建数据流套接字link_sock = socket(AF_INET, SOCK_STREAM, 0);if (link_sock == INVALID_SOCKET){//cout << "创建link_sock socket失败:错误号为: " << GetLastError() << endl; WaitForSingleObject(g_ThreadNumMutex,INFINITE);g_runThreadNum--;ReleaseMutex(g_ThreadNumMutex);//cout << "***还有_"<< g_runThreadNum << "_个扫描线程进行中**"<< endl;return -1;}FD_ZERO(&set_flag); //将指定文件描述符清空FD_SET(link_sock,&set_flag); //用于在文件描述符集合中增加一个新的文件描述符//设置连接地址SOCKADDR_IN scan_addr;scan_addr.sin_family = AF_INET;scan_addr.sin_addr.s_addr = ulScanIp;scan_addr.sin_port = htons(port);unsigned long sock_set = 1;ioctlsocket(link_sock,FIONBIO,&sock_set); //设置套接字为非阻塞模式,第3个参数非0为非阻塞connect(link_sock,(struct sockaddr *) &scan_addr, sizeof(scan_addr));//连接指定IP端口select_ret = select(0,NULL,&set_flag,NULL,&g_timeout);//异步返回值if (select_ret == 0 || select_ret == -1){++index;continue;}else{strstream stream_result;struct in_addr ipaddr;ipaddr.s_addr = ulScanIp;char *pStrIp = inet_ntoa(ipaddr);stream_result << "\t 主机地址为:" << pStrIp << "\t找到开放的端口: " << port <<'\0';string str_result(stream_result.str());//将扫描结果储存到输出变量中去WaitForSingleObject(g_ResultMutex,INFINITE);g_map_ScanResult.insert(make_pair(ulScanIp,str_result));ReleaseMutex(g_ResultMutex);}}//扫描完一个线程shutdown(link_sock, 0);closesocket(link_sock);WaitForSingleObject(g_ThreadNumMutex,INFINITE);g_runThreadNum--;ReleaseMutex(g_ThreadNumMutex);//cout << "****还有_"<< g_runThreadNum << "_个扫描线程进行中****"<< endl;return 0;}//----------------------------------------------------------------------------------------------------------//将IP转化成能直接递增和递减的地址unsigned long InvertIp(unsigned long srcIp){unsigned char first;unsigned char second;unsigned char third;unsigned char fourth;first = srcIp & 0x00FF;second = (srcIp >> 8) & 0x00FF;third = (srcIp >> 16) & 0x00FF;fourth = (srcIp >> 24) & 0x00FF;return (first << 24) | (second << 16) | (third << 8) | fourth;}//------------------------------------------------------------------------------------------------//将IP内的IP转化成一个一个unsigned long 类型存在数组中int GetIpToScan(const string &StartIp, const string &EndIp, vector<unsigned long> &vec_ip) {//判断输入的IP是否合法unsigned long ulStartIp = inet_addr(StartIp.c_str());unsigned long ulEndIp = inet_addr(EndIp.c_str());if(INADDR_NONE == ulStartIpINADDR_NONE == ulEndIp){cout << " 请输入合法的IP" << endl;return -1;}//////////////判断查询的是一个IP还是IP段///////////////////////////////////// if (ulStartIp == ulEndIp && ulStartIp !=0){vec_ip.push_back(ulStartIp);return 0;}if (ulStartIp == 0 && ulEndIp == 0){return 0;}if (ulStartIp == 0){vec_ip.push_back(ulEndIp);return 0;}if (ulEndIp == 0){vec_ip.push_back(ulStartIp);return 0;}//////////////////////////////////////////////////////////////////////////////将IP转换成可以递增比较的类型ulStartIp = InvertIp(ulStartIp);ulEndIp = InvertIp(ulEndIp);//指定前后顺序,ulEndIp较大unsigned long max_ip;if (ulStartIp > ulEndIp){max_ip = ulStartIp;ulStartIp = ulEndIp;ulEndIp = max_ip;}int ipnums = ulEndIp - ulStartIp;for(int i = 0;i <= ipnums;++i){//将每个IP的unsigned long型存到数组中供扫描vec_ip.push_back(InvertIp(ulStartIp++));}return 0;}//-----------------------------------------------------------------------------------------------------------------//功能: 输入一个IP段,输出该IP段内的端口开放情况信息int ScanIp(const string &start_Ip, const string &endIp, multimap<unsigned long, string> &ouputMap){//分解IP段内的IP到全局数组中去GetIpToScan(start_Ip,endIp,g_vec_IpToScan);int scanNum = g_vec_IpToScan.size();//线程总数g_runThreadNum = scanNum;cout<<endl;cout<<endl;cout<<"******************************************************************************* *";cout << " 共有" << scanNum <<" 个IP要扫描" << endl;//对每个IP开一个线程for (int i = 0; i < scanNum; ++i){CreateThread(NULL,0,ThreadFunc,&g_vec_IpToScan[i],0,NULL);//要是不间隔时间的话,同时创建socket会出现10093错误Sleep(50);}return 0;}//-------------------------------------------------------------------------------------------------------//输出扫描结果int OutPutScanInfo(){cout <<" 扫描到 " << g_map_ScanResult.size() << " 条记录" << endl;multimap<unsigned long, string>::iterator iter = g_map_ScanResult.begin();ofstream out("out.txt");cout <<" 显示总 " << g_map_ScanResult.size() << " 条记录:" << endl;cout<<endl;for (; iter!=g_map_ScanResult.end(); ++iter){out << iter->second << endl;cout << iter->second << endl;}return 0;}//----------------------------------------------------------------------------------------------------void UserInput(){cout<<""<<endl;cout<<" *********************** "<<endl;cout<<" * * "<<endl;cout<<" * 端口扫描器* "<<endl;cout<<" * * "<<endl;cout<<" *********************** "<<endl;cout<<""<<endl;cout<<"********************************************************************************"<<endl;cout<<"* 可扫描一个或多个IP,输入同一网段的两个IP。