# 端口扫描

## 端口扫描

虽然Nmap这些年来功能越来越多， 它也是从一个高效的端口扫描器开始的，并且那仍然是它的核心功能。**nmap*****\<target>***&#x8FD9;个简单的命令扫描主&#x673A;*\<target>*&#x4E0A;的超过 1660个TCP端口。 许多传统的端口扫描器只列出所有端口是开放还是关闭的， Nmap的信息粒度比它们要细得多。 它把端口分成六个状态:

* open(开放的)\
  应用程序正在该端口接收TCP 连接或者UDP报文。发现这一点常常是端口扫描 的主要目标。安全意识强的人们知道每个开放的端口 都是攻击的入口。攻击者或者入侵测试者想要发现开放的端口。 而管理员则试图关闭它们或者用防火墙保护它们以免妨碍了合法用户。 非安全扫描可能对开放的端口也感兴趣，因为它们显示了网络上那些服务可供使用。
* closed(关闭的)\
  关闭的端口对于Nmap也是可访问的(它接受Nmap的探测报文并作出响应)， 但没有应用程序在其上监听。 它们可以显示该IP地址上(主机发现，或者ping扫描)的主机正在运行up 也对部分操作系统探测有所帮助。 因为关闭的关口是可访问的，也许过会儿值得再扫描一下，可能一些又开放了。 系统管理员可能会考虑用防火墙封锁这样的端口。 那样他们就会被显示为被过滤的状态，下面讨论。
* filtered(被过滤的)\
  由于包过滤阻止探测报文到达端口， Nmap无法确定该端口是否开放。过滤可能来自专业的防火墙设备，路由器规则 或者主机上的软件防火墙。这样的端口让攻击者感觉很挫折，因为它们几乎不提供 任何信息。有时候它们响应ICMP错误消息如类型3代码13 (无法到达目标: 通信被管理员禁止)，但更普遍的是过滤器只是丢弃探测帧， 不做任何响应。 这迫使Nmap重试若干次以访万一探测包是由于网络阻塞丢弃的。 这使得扫描速度明显变慢。
* unfiltered(未被过滤的)\
  未被过滤状态意味着端口可访问，但Nmap不能确定它是开放还是关闭。 只有用于映射防火墙规则集的ACK扫描才会把端口分类到这种状态。 用其它类型的扫描如窗口扫描，SYN扫描，或者FIN扫描来扫描未被过滤的端口可以帮助确定 端口是否开放。
* open|filtered(开放或者被过滤的)
* 当无法确定端口是开放还是被过滤的，Nmap就把该端口划分成 这种状态。开放的端口不响应就是一个例子。没有响应也可能意味着报文过滤器丢弃 了探测报文或者它引发的任何响应。因此Nmap无法确定该端口是开放的还是被过滤的。 UDP，IP协议， FIN，Null，和Xmas扫描可能把端口归入此类。
* closed|filtered(关闭或者被过滤的)\
  该状态用于Nmap不能确定端口是关闭的还是被过滤的。 它只可能出现在IPID Idle扫描中。

这些状态并非端口本身的性质，而是描述Nmap怎样看待它们。例如， 对于同样的目标机器的135/tcp端口，从同网络扫描显示它是开放的，而跨网络作完全相同的扫描则可能显示它是 filtered(被过滤的)。

## 端口扫描技术

作为一个修车新手，我可能折腾几个小时来摸索怎样把基本工具(锤子，胶带，扳子等) 用于手头的任务。当我惨痛地失败，把我的老爷车拖到一个真正的技师那儿的时候 ，他总是在他的工具箱里翻来翻去，直到拽出一个完美的工具然后似乎不费吹灰之力搞定它。 端口扫描的艺术和这个类似。专家理解成打的扫描技术，选择最适合的一种 (或者组合)来完成给定的 任务。 另一方面，没有经验的用户和刚入门者总是用默认的SYN扫描解决每个问题。 既然Nmap是免费的，掌握端口扫描的唯一障碍就是知识。这当然是汽车世界所不能比的， 在那里，可能需要高超的技巧才能确定您需要一个压杆弹簧压缩机，接着您还得为它付数千美金。

大部分扫描类型只对特权用户可用。 这是因为他们发送接收原始报文，这在Unix系统需要root权限。 在Windows上推荐使用administrator账户，但是当WinPcap已经被加载到操作系统时， 非特权用户也可以正常使用Nmap。当Nmap在1997年发布时，需要root权限是一个严重的局限，因为很多用户只有共享的shell账户。现在，世界变了，计算机便宜了，更多人拥有互联网连接 ，桌面UNIX系统 (包括Linux和MAC OS X)很普遍了。Windows版本的Nmap现在也有了，这使它可以运行在更多的桌面上。 由于所有这些原因，用户不再需要用有限的共享shell账户运行Nmap。 这是很幸运的，因为特权选项让Nmap强大得多也灵活得多。

虽然Nmap努力产生正确的结果，但请记住所有结果都是基于目标机器(或者它们前面的防火墙)返回的报文的。这些主机也许是不值得信任的，它们可能响应以迷惑或误导Nmap的报文。 更普遍的是非RFC兼容的主机以不正确的方式响应Nmap探测。FIN，Null和Xmas扫描特别容易遇到这个问题。这些是特定扫描类型的问题，因此我们在个别扫描类型里讨论它们。

这一节讨论Nmap支持的大约十几种扫描技术。 一般一次只用一种方法， 除了UDP扫描(-sU)可能和任何一种TCP扫描类型结合使用。 友情提示一下，端口扫描类型的选项格式是-&#x73;*\<C>*， 其&#x4E2D;*\<C>*&#x662F;个显眼的字符，通常是第一个字符。 一个例外是deprecated FTP bounce扫描(-b)。默认情况下，Nmap执行一个 SYN扫描，但是如果用户没有权限发送原始报文(在UNIX上需要root权限)或者如果指定的是IPv6目标，Nmap调用connect()。 本节列出的扫描中，非特权用户只能执行connect()和ftp bounce扫描。

* -sS (TCP SYN扫描)

SYN扫描作为默认的也是最受欢迎的扫描选项，是有充分理由的。 它执行得很快，在一个没有入侵防火墙的快速网络上，每秒钟可以扫描数千个端口。 SYN扫描相对来说不张扬，不易被注意到，因为它从来不完成TCP连接。 它也不像Fin/Null/Xmas，Maimon和Idle扫描依赖于特定平台，而可以应对任何兼容的 TCP协议栈。 它还可以明确可靠地区分open(开放的)， closed(关闭的)，和filtered(被过滤的) 状态。

它常常被称为半开放扫描， 因为它不打开一个完全的TCP连接。它发送一个SYN报文， 就像您真的要打开一个连接，然后等待响应。 SYN/ACK表示端口在监听 (开放)，而 RST (复位)表示没有监听者。如果数次重发后仍没响应， 该端口就被标记为被过滤。如果收到ICMP不可到达错误 (类型3，代码1，2，3，9，10，或者13)，该端口也被标记为被过滤。

* -sT (TCP connect()扫描)

当SYN扫描不能用时，CP Connect()扫描就是默认的TCP扫描。 当用户没有权限发送原始报文或者扫描IPv6网络时，就是这种情况。 ，Nmap通过创建connect() 系统调用要求操作系统和目标机以及端口建立连接，而不像其它扫描类型直接发送原始报文。 这是和Web浏览器，P2P客户端以及大多数其它网络应用程序用以建立连接一样的 高层系统调用。它是叫做Berkeley Sockets API编程接口的一部分。Nmap用 该API获得每个连接尝试的状态信息，而不是读取响应的原始报文。

当SYN扫描可用时，它通常是更好的选择。因为Nmap对高层的 connect()调用比对原始报文控制更少， 所以前者效率较低。 该系统调用完全连接到开放的目标端口而不是像SYN扫描进行半开放的复位。这不仅花更长时间，需要更多报文得到同样信息，目标机也更可能记录下连接。IDS(入侵检测系统)可以捕获两者，但大部分机器没有这样的警报系统。 当Nmap连接，然后不发送数据又关闭连接， 许多普通UNIX系统上的服务会在syslog留下记录，有时候是一条加密的错误消息。 此时，有些真正可怜的服务会崩溃，虽然这不常发生。如果管理员在日志里看到来自同一系统的 一堆连接尝试，他应该知道他的系统被扫描了。

* -sU (UDP扫描)

虽然互联网上很多流行的服务运行在TCP 协议上，[UDP](http://www.rfc-editor.org/rfc/rfc768.txt)服务也不少。 DNS，SNMP，和DHCP (注册的端口是53，161/162，和67/68)是最常见的三个。 因为UDP扫描一般较慢，比TCP更困难，一些安全审核人员忽略这些端口。 这是一个错误，因为可探测的UDP服务相当普遍，攻击者当然不会忽略整个协议。 所幸，Nmap可以帮助记录并报告UDP端口。

UDP扫描用-sU选项激活。它可以和TCP扫描如 SYN扫描 (-sS)结合使用来同时检查两种协议。

UDP扫描发送空的(没有数据)UDP报头到每个目标端口。 如果返回ICMP端口不可到达错误(类型3，代码3)， 该端口是closed(关闭的)。 其它ICMP不可到达错误(类型3， 代码1，2，9，10，或者13)表明该端口是filtered(被过滤的)。 偶尔地，某服务会响应一个UDP报文，证明该端口是open(开放的)。 如果几次重试后还没有响应，该端口就被认为是 open|filtered(开放|被过滤的)。 这意味着该端口可能是开放的，也可能包过滤器正在封锁通信。 可以用版本扫描(-sV)帮助区分真正的开放端口和被过滤的端口。

UDP扫描的巨大挑战是怎样使它更快速。 开放的和被过滤的端口很少响应，让Nmap超时然后再探测，以防探测帧或者 响应丢失。关闭的端口常常是更大的问题。 它们一般发回一个ICMP端口无法到达错误。但是不像关闭的TCP端口响应SYN或者Connect 扫描所发送的RST报文，许多主机在默认情况下限制ICMP端口不可到达消息。 Linux和Solaris对此特别严格。例如， Linux 2.4.20内核限制一秒钟只发送一条目标不可到达消息 (见net/ipv4/icmp。c)。

Nmap探测速率限制并相应地减慢来避免用那些目标机会丢弃的无用报文来阻塞 网络。不幸的是，Linux式的一秒钟一个报文的限制使65,536个端口的扫描要花 18小时以上。加速UDP扫描的方法包括并发扫描更多的主机，先只对主要端口进行快速 扫描，从防火墙后面扫描，使用--host-timeout跳过慢速的 主机。

* -sN; -sF; -sX (TCP Null，FIN，and Xmas扫描)

这三种扫描类型 (甚至用下一节描述的 --scanflags 选项的更多类型) 在[TCP RFC](http://www.rfc-editor.org/rfc/rfc793.txt)中发掘了一个微妙的方法来区分open(开放的)和 closed(关闭的)端口。第65页说“如果 \[目标]端口状态是关闭的.... 进入的不含RST的报文导致一个RST响应。” 接下来的一页 讨论不设置SYN，RST，或者ACK位的报文发送到开放端口: “理论上，这不应该发生，如果您确实收到了，丢弃该报文，返回。 ”

如果扫描系统遵循该RFC，当端口关闭时，任何不包含SYN，RST，或者ACK位的报文会导致 一个RST返回，而当端口开放时，应该没有任何响应。只要不包含SYN，RST，或者ACK， 任何其它三种(FIN，PSH，and URG)的组合都行。Nmap有三种扫描类型利用这一点：

Null扫描 (-sN)

不设置任何标志位(tcp标志头是0)

FIN扫描 (-sF)

只设置TCP FIN标志位。

Xmas扫描 (-sX)

设置FIN，PSH，和URG标志位，就像点亮圣诞树上所有的灯一样。

除了探测报文的标志位不同，这三种扫描在行为上完全一致。 如果收到一个RST报文，该端口被认为是 closed(关闭的)，而没有响应则意味着 端口是open|filtered(开放或者被过滤的)。 如果收到ICMP不可到达错误(类型 3，代号 1，2，3，9，10，或者13)，该端口就被标记为 被过滤的。

这些扫描的关键优势是它们能躲过一些无状态防火墙和报文过滤路由器。 另一个优势是这些扫描类型甚至比SYN扫描还要隐秘一些。但是别依赖它 -- 多数 现代的IDS产品可以发现它们。一个很大的不足是并非所有系统都严格遵循RFC 793。 许多系统不管端口开放还是关闭，都响应RST。 这导致所有端口都标记为closed(关闭的)。 这样的操作系统主要有Microsoft Windows，许多Cisco设备，BSDI，以及IBM OS/400。 但是这种扫描对多数UNIX系统都能工作。这些扫描的另一个不足是 它们不能辨别open(开放的)端口和一些特定的 filtered(被过滤的)端口，从而返回 open|filtered(开放或者被过滤的)。

* -sA (TCP ACK扫描)

这种扫描与目前为止讨论的其它扫描的不同之处在于 它不能确定open(开放的)或者 open|filtered(开放或者过滤的))端口。 它用于发现防火墙规则，确定它们是有状态的还是无状态的，哪些端口是被过滤的。

ACK扫描探测报文只设置ACK标志位(除非您使用 --scanflags)。当扫描未被过滤的系统时， open(开放的)和closed(关闭的) 端口 都会返回RST报文。Nmap把它们标记为 unfiltered(未被过滤的)，意思是 ACK报文不能到达，但至于它们是open(开放的)或者 closed(关闭的) 无法确定。不响应的端口 或者发送特定的ICMP错误消息(类型3，代号1，2，3，9，10， 或者13)的端口，标记为 filtered(被过滤的)。

* -sW (TCP窗口扫描)

除了利用特定系统的实现细节来区分开放端口和关闭端口，当收到RST时不总是打印unfiltered， 窗口扫描和ACK扫描完全一样。 它通过检查返回的RST报文的TCP窗口域做到这一点。 在某些系统上，开放端口用正数表示窗口大小(甚至对于RST报文) 而关闭端口的窗口大小为0。因此，当收到RST时，窗口扫描不总是把端口标记为 unfiltered， 而是根据TCP窗口值是正数还是0，分别把端口标记为open或者 closed

该扫描依赖于互联网上少数系统的实现细节， 因此您不能永远相信它。不支持它的系统会通常返回所有端口closed。 当然，一台机器没有开放端口也是有可能的。 如果大部分被扫描的端口是 closed，而一些常见的端口 (如 22， 25，53) 是 filtered，该系统就非常可疑了。 偶尔地，系统甚至会显示恰恰相反的行为。 如果您的扫描显示1000个开放的端口和3个关闭的或者被过滤的端口， 那么那3个很可能也是开放的端口。

* -sM (TCP Maimon扫描)

Maimon扫描是用它的发现者Uriel Maimon命名的。他在 Phrack Magazine issue #49 (November 1996)中描述了这一技术。 Nmap在两期后加入了这一技术。 这项技术和Null，FIN，以及Xmas扫描完全一样，除了探测报文是FIN/ACK。 根据RFC 793 (TCP)，无论端口开放或者关闭，都应该对这样的探测响应RST报文。 然而，Uriel注意到如果端口开放，许多基于BSD的系统只是丢弃该探测报文。

* \--scanflags (定制的TCP扫描)

真正的Nmap高级用户不需要被这些现成的扫描类型束缚。 --scanflags选项允许您通过指定任意TCP标志位来设计您自己的扫描。 让您的创造力流动，躲开那些仅靠本手册添加规则的入侵检测系统！

\--scanflags选项可以是一个数字标记值如9 (PSH和FIN)， 但使用字符名更容易些。 只要是URG， ACK，PSH， RST，SYN，and FIN的任何组合就行。例如，--scanflags URGACKPSHRSTSYNFIN设置了所有标志位，但是这对扫描没有太大用处。 标志位的顺序不重要。

除了设置需要的标志位，您也可以设置 TCP扫描类型(如-sA或者-sF)。 那个基本类型告诉Nmap怎样解释响应。例如， SYN扫描认为没有响应意味着 filtered端口，而FIN扫描则认为是 open|filtered。 除了使用您指定的TCP标记位，Nmap会和基本扫描类型一样工作。 如果您不指定基本类型，就使用SYN扫描。

* -sI\<zombie host\[:probeport]>(Idlescan)

这种高级的扫描方法允许对目标进行真正的TCP端口盲扫描 (意味着没有报文从您的真实IP地址发送到目标)。相反，side-channel攻击 利用zombie主机上已知的IP分段ID序列生成算法来窥探目标上开放端口的信息。 IDS系统将显示扫描来自您指定的zombie机(必须运行并且符合一定的标准)。 这种奇妙的扫描类型太复杂了，不能在此完全描述，所以我写一篇非正式的论文， 发布在<http://nmap.org/book/idlescan.html>。

除了极端隐蔽(由于它不从真实IP地址发送任何报文)， 该扫描类型可以建立机器间的基于IP的信任关系。 端口列表*从zombie 主机的角度。*&#x663E;示开放的端口。 因此您可以尝试用您认为(通过路由器/包过滤规则)可能被信任的 zombies扫描目标。

如果您由于IPID改变希望探测zombie上的特定端口， 您可以在zombie 主机后加上一个冒号和端口号。 否则Nmap会使用默认端口(80)。

* -sO (IP协议扫描)

IP 协议扫描可以让您确定目标机支持哪些IP协议 (TCP，ICMP，IGMP，等等)。从技术上说，这不是端口扫描 ，既然它遍历的是IP协议号而不是TCP或者UDP端口号。 但是它仍使用 -p选项选择要扫描的协议号， 用正常的端口表格式报告结果，甚至用和真正的端口扫描一样 的扫描引擎。因此它和端口扫描非常接近，也被放在这里讨论。

除了本身很有用，协议扫描还显示了开源软件的力量。 尽管基本想法非常简单，我过去从没想过增加这一功能也没收到任何对它的请求。 在2000年夏天，Gerhard Rieger孕育了这个想法，写了一个很棒的补丁程序，发送到nmap-hackers邮件列表。 我把那个补丁加入了Nmap，第二天发布了新版本。 几乎没有商业软件会有用户有足够的热情设计并贡献他们的改进。

协议扫描以和UDP扫描类似的方式工作。它不是在UDP报文的端口域上循环， 而是在IP协议域的8位上循环，发送IP报文头。 报文头通常是空的，不包含数据，甚至不包含所申明的协议的正确报文头 TCP，UDP，和ICMP是三个例外。它们三个会使用正常的协议头，因为否则某些系 统拒绝发送，而且Nmap有函数创建它们。协议扫描不是注意ICMP端口不可到达消息， 而是ICMP*协议*不可到达消息。如果Nmap从目标主机收到 任何协议的任何响应，Nmap就把那个协议标记为open。 ICMP协议不可到达 错误(类型 3，代号 2) 导致协议被标记为 closed。其它ICMP不可到达协议(类型 3，代号 1，3，9，10，或者13) 导致协议被标记为 filtered (虽然同时他们证明ICMP是 open )。如果重试之后仍没有收到响应， 该协议就被标记为open|filtered

* -b\<ftp relay host>(FTP弹跳扫描)

FTP协议的一个有趣特征([RFC 959](http://www.rfc-editor.org/rfc/rfc959.txt)) 是支持所谓代理ftp连接。它允许用户连接到一台FTP服务器，然后要求文件送到一台第三方服务器。 这个特性在很多层次上被滥用，所以许多服务器已经停止支持它了。其中一种就是导致FTP服务器对其它主机端口扫描。 只要请求FTP服务器轮流发送一个文件到目标主机上的所感兴趣的端口。 错误消息会描述端口是开放还是关闭的。 这是绕过防火墙的好方法，因为FTP服务器常常被置于可以访问比Web主机更多其它内部主机的位置。 Nmap用-b选项支持ftp弹跳扫描。参数格式&#x662F;*\<username>*:*\<password>*@*\<server>*:*\<port>*。*\<Server>*&#x662F;某个脆弱的FTP服务器的名字或者IP地址。 您也许可以省&#x7565;*\<username>*:*\<password>*， 如果服务器上开放了匿名用户(user:anonymous password:-wwwuser@)。 端口号(以及前面的冒号) 也可以省略，如&#x679C;*\<server>*&#x4F7F;用默认的FTP端口(21)。

当Nmap1997年发布时，这个弱点被广泛利用，但现在大部分已经被fix了。 脆弱的服务器仍然存在，所以如果其它都失败了，这也值得一试。 如果您的目标是绕过防火墙，扫描目标网络上的开放的21端口(或者 甚至任何ftp服务，如果您用版本探测扫描所有端口)， 然后对每个尝试弹跳扫描。Nmap会告诉您该主机脆弱与否。 如果您只是试着玩Nmap，您不必(事实上，不应该)限制您自己。 在您随机地在互联网上寻找脆弱的FTP服务器时，考虑一下系统管理员不太喜欢您这样滥用他们的服务器。

## 端口说明和扫描顺序

除了所有前面讨论的扫描方法， Nmap提供选项说明那些端口被扫描以及扫描是随机还是顺序进行。 默认情况下，Nmap用指定的协议对端口1到1024以及nmap-services 文件中列出的更高的端口在扫描。

* -p\<port ranges>(只扫描指定的端口)

该选项指明您想扫描的端口，覆盖默认值。 单个端口和用连字符表示的端口范围(如 1-1023)都可以。 范围的开始以及/或者结束值可以被省略， 分别导致Nmap使用1和65535。所以您可以指定 -p-从端口1扫描到65535。 如果您特别指定，也可以扫描端口0。 对于IP协议扫描(-sO)，该选项指定您希望扫描的协议号 (0-255)。

当既扫描TCP端口又扫描UDP端口时，您可以通过在端口号前加上T: 或者U:指定协议。 协议限定符一直有效您直到指定另一个。 例如，参数 -p U:53，111，137，T:21-25，80，139，8080 将扫描UDP 端口53，111，和137，同时扫描列出的TCP端口。注意，要既扫描 UDP又扫描TCP，您必须指定 -sU ，以及至少一个TCP扫描类型(如 -sS，-sF，或者 -sT)。如果没有给定协议限定符， 端口号会被加到所有协议列表。

* -F (快速 (有限的端口) 扫描)

在nmap的nmap-services 文件中(对于-sO，是协议文件)指定您想要扫描的端口。 这比扫描所有65535个端口快得多。 因为该列表包含如此多的TCP端口(1200多)，这和默认的TCP扫描 scan (大约1600个端口)速度差别不是很大。如果您用--datadir选项指定您自己的 小小的nmap-services文件 ，差别会很惊人。

* -r (不要按随机顺序扫描端口)

默认情况下，Nmap按随机顺序扫描端口 (除了出于效率的考虑，常用的端口前移)。这种随机化通常都是受欢迎的， 但您也可以指定-r来顺序端口扫描。
