« | September 2025 | » | 日 | 一 | 二 | 三 | 四 | 五 | 六 | | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | | | | | |
|
统计 |
blog名称: 日志总数:14 评论数量:37 留言数量:0 访问次数:136862 建立时间:2004年11月6日 |
| 
|
本站首页 管理页面 写新日志 退出
[安全技术]端口扫描分析(二)端口扫描途径 |
二。 端口扫描途径什么是扫描器 扫描器是一种自动检测远程或本地主机安全性弱点的程序,通过使用扫描器你可一不留痕迹的发现远程服务器的各种TCP端口的分配及提供的服务和它们的软件版本!这就能让我们间接的或直观的了解到远程主机所存在的安全问题。工作原理 扫描器通过选用远程TCP/IP不同的端口的服务,并记录目标给予的回答,通过这种方法,可以搜集到很多关于目标主机的各种有用的信息(比如:是否能用匿名登陆!是否有可写的FTP目录,是否能用TELNET,HTTPD是用ROOT还是nobady在跑!)扫描器能干什么? 扫描器并不是一个直接的攻击网络漏洞的程序,它仅仅能帮助我们发现目标机的某些内在的弱点。一个好的扫描器能对它得到的数据进行分析,帮助我们查找目标主机的漏洞。但它不会提供进入一个系统的详细步骤。 扫描器应该有三项功能:发现一个主机或网络的能力;一旦发现一台主机,有发现什么服务正运行在这台主机上的能力;通过测试这些服务,发现漏洞的能力。 编写扫描器程序必须要很多TCP/IP程序编写和C, Perl和或SHELL语言的知识。需要一些Socket编程的背景,一种在开发客户/服务应用程序的方法。开发一个扫描器是一个雄心勃勃的项目,通常能使程序员感到很满意。 下面对常用的端口扫描技术做一个介绍。TCP connect() 扫描 这是最基本的TCP扫描。操作系统提供的connect()系统调用,用来与每一个感兴趣的目标计算机的端口进行连接。如果端口处于侦听状态,那么connect()就能成功。否则,这个端口是不能用的,即没有提供服务。这个技术的一个最大的优点是,你不需要任何权限。系统中的任何用户都有权利使用这个调用。另一个好处就是速度。如果对每个目标端口以线性的方式,使用单独的connect()调用,那么将会花费相当长的时间,你可以通过同时打开多个套接字,从而加速扫描。使用非阻塞I/O允许你设置一个低的时间用尽周期,同时观察多个套接字。但这种方法的缺点是很容易被发觉,并且被过滤掉。目标计算机的logs文件会显示一连串的连接和连接是出错的服务消息,并且能很快的使它关闭。TCP SYN扫描 这种技术通常认为是“半开放”扫描,这是因为扫描程序不必要打开一个完全的TCP连接。扫描程序发送的是一个SYN数据包,好象准备打开一个实际的连接并等待反应一样(参考TCP的三次握手建立一个TCP连接的过程)。一个SYN|ACK的返回信息表示端口处于侦听状态。一个RST返回,表示端口没有处于侦听态。如果收到一个SYN|ACK,则扫描程序必须再发送一个RST信号,来关闭这个连接过程。这种扫描技术的优点在于一般不会在目标计算机上留下记录。但这种方法的一个缺点是,必须要有root权限才能建立自己的SYN数据包。TCP FIN 扫描 有的时候有可能SYN扫描都不够秘密。一些防火墙和包过滤器会对一些指定的端口进行监视,有的程序能检测到这些扫描。相反,FIN数据包可能会没有任何麻烦的通过。这种扫描方法的思想是关闭的端口会用适当的RST来回复FIN数据包。另一方面,打开的端口会忽略对FIN数据包的回复。这种方法和系统的实现有一定的关系。有的系统不管端口是否打开,都回复RST,这样,这种扫描方法就不适用了。并且这种方法在区分Unix和NT时,是十分有用的。IP段扫描 这种不能算是新方法,只是其它技术的变化。它并不是直接发送TCP探测数据包,是将数据包分成两个较小的IP段。这样就将一个TCP头分成好几个数据包,从而过滤器就很难探测到。但必须小心。一些程序在处理这些小数据包时会有些麻烦。TCP 反向 ident扫描 ident 协议允许(rfc1413)看到通过TCP连接的任何进程的拥有者的用户名,即使这个连接不是由这个进程开始的。因此你能,举个例子,连接到http端口,然后用identd来发现服务器是否正在以root权限运行。这种方法只能在和目标端口建立了一个完整的TCP连接后才能看到。FTP 返回攻击 FTP协议的一个有趣的特点是它支持代理(proxy)FTP连接。即入侵者可以从自己的计算机a.com和目标主机target.com的FTP server-PI(协议解释器)连接,建立一个控制通信连接。然后,请求这个server-PI激活一个有效的server-DTP(数据传输进程)来给Internet上任何地方发送文件。对于一个User-DTP,这是个推测,尽管RFC明确地定义请求一个服务器发送文件到另一个服务器是可以的。但现在这个方法好象不行了。这个协议的缺点是“能用来发送不能跟踪的邮件和新闻,给许多服务器造成打击,用尽磁盘,企图越过防火墙”。 我们利用这个的目的是从一个代理的FTP服务器来扫描TCP端口。这样,你能在一个防火墙后面连接到一个FTP服务器,然后扫描端口(这些原来有可能被阻塞)。如果FTP服务器允许从一个目录读写数据,你就能发送任意的数据到发现的打开的端口。 对于端口扫描,这个技术是使用PORT命令来表示被动的User DTP正在目标计算机上的某个端口侦听。然后入侵者试图用LIST命令列出当前目录,结果通过Server-DTP发送出去。如果目标主机正在某个端口侦听,传输就会成功(产生一个150或226的回应)。否则,会出现"425 Can't build data connection: Connection refused."。然后,使用另一个PORT命令,尝试目标计算机上的下一个端口。这种方法的优点很明显,难以跟踪,能穿过防火墙。主要缺点是速度很慢,有的FTP服务器最终能得到一些线索,关闭代理功能。这种方法能成功的情景:220 xxxxxxx.com FTP server (Version wu-2.4(3) Wed Dec 14 ...) ready.220 xxx.xxx.xxx.edu FTP server ready.220 xx.Telcom.xxxx.EDU FTP server (Version wu-2.4(3) Tue Jun 11 ...) ready.220 lem FTP server (SunOS 4.1) ready.220 xxx.xxx.es FTP server (Version wu-2.4(11) Sat Apr 27 ...) ready.220 elios FTP server (SunOS 4.1) ready这种方法不能成功的情景:220 wcarchive.cdrom.com FTP server (Version DG-2.0.39 Sun May 4 ...) ready.220 xxx.xx.xxxxx.EDU Version wu-2.4.2-academ[BETA-12](1) Fri Feb 7220 ftp Microsoft FTP Service (Version 3.0).220 xxx FTP server (Version wu-2.4.2-academ[BETA-11](1) Tue Sep 3 ...) ready.220 xxx.unc.edu FTP server (Version wu-2.4.2-academ[BETA-13](6) ...) ready.UDP ICMP端口不能到达扫描 这种方法与上面几种方法的不同之处在于使用的是UDP协议。由于这个协议很简单,所以扫描变得相对比较困难。这是由于打开的端口对扫描探测并不发送一个确认,关闭的端口也并不需要发送一个错误数据包。幸运的是,许多主机在你向一个未打开的UDP端口发送一个数据包时,会返回一个ICMP_PORT_UNREACH错误。这样你就能发现哪个端口是关闭的。UDP和ICMP错误都不保证能到达,因此这种扫描器必须还实现在一个包看上去是丢失的时候能重新传输。这种扫描方法是很慢的,因为RFC对ICMP错误消息的产生速率做了规定。同样,这种扫描方法需要具有root权限。UDP recvfrom()和write() 扫描 当非root用户不能直接读到端口不能到达错误时,Linux能间接地在它们到达时通知用户。比如,对一个关闭的端口的第二个write()调用将失败。在非阻塞的UDP套接字上调用recvfrom()时,如果ICMP出错还没有到达时回返回EAGAIN-重试。如果ICMP到达时,返回ECONNREFUSED-连接被拒绝。这就是用来查看端口是否打开的技术。ICMP echo扫描 这并不是真正意义上的扫描。但有时通过ping,在判断在一个网络上主机是否开机时非常有用。下面是一个端口扫描器的源程序,功能相当的简单,一个典型的TCP connect()扫描。没有对返回的数据进行分析。#include <stdio.h>#include <sys/socket.h>#include <netinet/in.h>#include <errno.h>#include <netdb.h>#include <signal.h>int main(int argc, char **argv){int probeport = 0;struct hostent *host;int err, i, net;struct sockaddr_in sa;if (argc != 2) {printf("用法: %s hostname\n", argv[0]);exit(1);}for (i = 1; i < 1024; i++) { //这里有点不是很好,可以将主机地址放在循环外strncpy((char *)&sa, "", sizeof sa);sa.sin_family = AF_INET;if (isdigit(*argv[1]))sa.sin_addr.s_addr = inet_addr(argv[1]);else if ((host = gethostbyname(argv[1])) != 0)strncpy((char *)&sa.sin_addr, (char *)host->h_addr, sizeof sa.sin_addr);else {herror(argv[1]);exit(2);}sa.sin_port = htons(i);net = socket(AF_INET, SOCK_STREAM, 0);if (net < 0) {perror("\nsocket");exit(2);}err = connect(net, (struct sockaddr *) &sa, sizeof sa);if (err < 0) {printf("%s %-5d %s\r", argv[1], i, strerror(errno));fflush(stdout);} else {printf("%s %-5d accepted. \n", argv[1], i);if (shutdown(net, 2) < 0) {perror("\nshutdown");exit(2);}}close(net);}printf(" \r");fflush(stdout);return (0);}下面这个又是一个端口器:#include <stdio.h>#include <sys/types.h>#include <sys/socket.h>#include "netdb.h"struct hostent *gethostbyaddr();void bad_addr();main(argc, argv)int argc;char *argv[];{char addr[4];int i, j,a0, a1, a2, a3,c,classB, classC, single, hex;char *fmt = "%d.%d.%d";char **ptr;struct hostent *host;extern char *optarg;classB = classC = single = hex = 0;while((c = getopt(argc,argv,"bcsx")) != EOF) {switch(c) {case 'b':classB++;break;case 'c':classC++;break;case 's':single++;break;case 'x':hex++;break;}}if(classB == 0 && classC == 0 && single == 0) {fprintf(stderr, "usage: %s [-b||-c||-s] [-x] xxx.xxx[.xxx[.xxx]]\n", argv[0]);exit(1);}if(classB)if(hex) {fmt = "%x.%x";sscanf(argv[3], fmt, &a0, &a1);} else {fmt = "%d.%d";sscanf(argv[2], fmt, &a0, &a1);}else if(classC)if(hex) {fmt = "%x.%x.%x";sscanf(argv[3], fmt, &a0, &a1, &a2);} else {fmt = "%d.%d.%d";sscanf(argv[2], fmt, &a0, &a1, &a2);}else if(single)if(hex) {fmt = "%x.%x.%x.%x";sscanf(argv[3], fmt, &a0, &a1, &a2, &a3);} else {fmt = "%d.%d.%d.%d";sscanf(argv[2], fmt, &a0, &a1, &a2, &a3);}sscanf(argv[1], fmt, &a0, &a1, &a2);addr[0] = (unsigned char)a0;addr[1] = (unsigned char)a1;if(a0>255||a0<0)bad_addr(a0);if(a1>255||a1<0)bad_addr(a1);if(classB) {if(hex)printf("Converting address from hex. (%x.%x)\n", a0, a1);printf("Scanning Class B network %d.%d...\n", a0, a1);while(j!=256) {a2=j;addr[2] = (unsigned char)a2;jmpC:if(classC)if(hex)printf("Converting address from hex. (%x.%x.%x)\n", a0, a1, a2);printf("Scanning Class C network %d.%d.%d...\n", a0, a1, a2);while(i!=256) {a3=i;addr[3] = (unsigned char)a3;jmpS:if ((host = gethostbyaddr(addr, 4, AF_INET)) != NULL) {printf("%d.%d.%d.%d => %s\n", a0, a1, a2, a3, host->h_name);ptr = host->h_aliases;while (*ptr != NULL) {printf("%d.%d.%d.%d => %s (alias)\n", a0, a1, a2, a3, *ptr);ptr++;}}if(single)exit(0);i++;}if(classC)exit(0);j++;}} else if(classC) {addr[2] = (unsigned char)a2;if(a2>255||a2<0)bad_addr(a2);goto jmpC;} else if(single) {addr[2] = (unsigned char)a2;addr[3] = (unsigned char)a3;if(a2>255||a2<0)bad_addr(a2);if(a3>255||a3<0)bad_addr(a3);goto jmpS;}exit(0);}voidbad_addr(addr)int *addr;{printf("Value %d is not valid.\n", addr);exit(0);}
|
阅读全文(3910) | 回复(0) | 编辑 | 精华 |
|