扫描对外公开的服务器信息,是 nmap 的主要用途之一。为了识别服务器上运行的是哪一种服务,nmap 把主流服务的特征信息存储在 nmap-services-probes 和 nmap-os-db 这两个文件中。其中前者包含应用程序的特征信息,后者放置操做系统的特征信息。不一样操做系统上,这两个文件的位置不同,能够经过 locate
或其余类似的全盘搜索工具找出它们具体的位置。html
接下来让咱们解读下这两个文件,看看 nmap 是如何利用这些信息来识别服务的。python
当咱们指定 -sV
选项运行 nmap 时,它会根据 nmap-services-probes 文件里面存储的是服务类型特征数据去判断具体扫描到的是哪一种服务。linux
nmap-services-probes 看上去比较乱。事实上,若是这部分数据能够组织成 xml 或 yaml 这种树型结构的格式,看上去会明显清晰得多。nginx
贴个片断看下:正则表达式
Probe TCP GetRequest q|GET / HTTP/1.0\r\n\r\n| rarity 1 ports 1,70,79,80-85,88,113,139,143,280,497,505,514,515,540,554,591,620,631,783,888,898,900,901,1026,1080,1042,1214,1220,1234,1314,1344,1503,1610,1611,1830,1900,2001,2002,2030,2064,2160,2306,2396,2525,2715,2869,3000,3002,3052,3128,3280,3372,3531,3689,3872,4000,4444,4567,4660,4711,5000,5427,5060,5222,5269,5280,5432,5800-5803,5900,5985,6103,6346,6544,6600,6699,6969,7002,7007,7070,7100,7402,7776,8000-8010,8080-8085,8088,8118,8181,8880-8888,9000,9001,9030,9050,9080,9090,9999,10000,10001,10005,11371,13013,13666,13722,14534,15000,17988,18264,31337,40193,50000,55555 sslports 443,993,995,1311,1443,3443,4443,5061,7443,8443,9443,10443,14443,44443,60443 ... match http m|^HTTP/1\.[01] \d\d\d.*?\r\nServer: nginx\r\n|s p/nginx/ cpe:/a:igor_sysoev:nginx/ match http m|^HTTP/1\.[01] \d\d\d.*\r\nServer: nginx/([\d.]+)\r\n|s p/nginx/ v/$1/ cpe:/a:igor_sysoev:nginx:$1/
nmap-services-probes 没有直接列出各类服务的特征,而是描述了服务识别扫描过程当中的操做步骤。其中 Probe
开头表示新起一个探测项。后面跟着的 TCP GetRequest
表示该探测项的种类和名字。q|GET / HTTP/1.0\r\n\r\n|
表示探测时采起的动做,这里就是发送一个最小的 GET 请求。redis
下一行的 rarity 表示该探测的罕见性。nmap 默认只会执行 rarity 7 如下的探测,不过能够经过 --version-intensity N
选项更改。服务器
再往下,是须要执行该探测的端口列表。在发起识别服务的扫描以前,nmap 已经扫描出当前可用的端口列表了。对于列表中的端口,若是它在某个探测的端口列表里,nmap 就会对该端口执行对应的探测。不用担忧每一个端口都执行许多探测会明显减慢扫描速度 —— nmap 会并行扫描多个端口。tcp
sslports 相似于 ports,不一样之处在于生效的时间。当 nmap 完成 tls 握手后,会根据 sslports 登记的配置去运行对应的探测。工具
接下来是一连串的 match 语句。顾名思义,它们都是响应的匹配规则。其中 m 开头的是正则表达式,p 开头的是产品名字,v 开头的是版本号,cpe 开头的是 cpe 编号, i 开头表示附加的信息。这里列出的匹配规则表示,若是 GET 请求对应的响应匹配到 ^HTTP/1\.[01] \d\d\d.*?\r\nServer: nginx\r\n
,说明对应的服务是 Nginx。单个产品可能会有多个与之相关的规则,好比 nmap 会有如下方法去匹配 Nginx:测试
<center>nginx</center>
<head><title>400 Bad Request</title></head>\r\n<h1>400 Bad Request</h1>
HTTP/1.1 400 Bad Request\r\n.*<title>400 The plain HTTP request was sent to HTTPS port</title>
match 语句最多只会匹配到一个服务。若是想匹配多个服务,好比 Nginx 代理的 PHP 应用,能够结合 softmmatch 使用。添加下面一行:
softmatch http m|^HTTP/1\.[01] .*\r\nX-Powered-By: PHP/(\d[\w._-]+)|s i/PHP $1/
最后输出结果里会多一个括号:8080/tcp open http nginx (PHP 5.6.25)
。
除了 HTTP 请求,nmap 也会用其余方式探测目标服务,好比这个为 Redis 量身定制的请求:Probe TCP redis-server q|\*1\r\n\$4\r\ninfo\r\n|
。甚至连 minecraft 都有:Probe TCP minecraft-ping q|\xFE\x01|
。
nmap-service-probes 开头的 Probe TCP NULL q||
值得介绍。这个 Probe 是为了检测出某些会主动给连上来的客户端发送数据的服务设置的。跟其余 Probe 不一样,它不发送请求,只是干等 6 秒。当你给 nmap 抓包时,端口探测和服务识别间会相差 6 秒,就是这个探测致使的。
附赠一个列出全部可探测的服务的 Python 脚本:
import re # 以实际位置替换下面的路径 nmap_service_probes_file = "/usr/local/share/nmap/nmap-service-probes" pat = re.compile(r"^match .+ p/([^/]+)/ .+$") products = set() with open(nmap_service_probes_file) as f: for line in f: m = pat.search(line) if m is not None and not m.group(1).startswith('$'): # 会存在 product 名中间含有 $xx 变量的状况,这里就忽略吧 products.add(m.group(1)) for p in sorted(list(products)): print(p)
跟 -sV
选项相似,有一个名为 -O
的选项能够开启操做系统探测的扫描功能。依本人的经验,nmap 的 操做系统探测的准确度仅到操做系统类型这一级,对于具体的版本,其扫描结果可能会不许。
扫描过程当中会用到 nmap-os-db 这个文件里面的特征信息识别遇到的 OS。若是说 nmap-service-probes 相对还好阅读,那 nmap-os-db 无疑即是天书通常了。还好 nmap 的文档里面对此有充分的解释,参见:
操做系统探测利用的是 IP/TCP 层面上的特征。在 nmap-os-db 里面,每一个特征以 Fingerprint 开头,接着是该特征对应的操做系统信息,而后是具体的特征值。
举个例子,像下面这样的特征数据:
Fingerprint Linux 3.10 Class Linux | Linux | 3.X | general purpose CPE cpe:/o:linux:linux_kernel:3.10 auto SEQ(SP=FB-105%GCD=1-6%ISR=109-113%TI=Z%CI=I%II=I%TS=A) OPS(O1=M548ST11NW7%O2=M548ST11NW7%O3=M548NNT11NW7%O4=M548ST11NW7%O5=M548ST11NW7%O6=M548ST11) WIN(W1=3890%W2=3890%W3=3890%W4=3890%W5=3890%W6=3890) ECN(R=Y%DF=Y%T=3B-45%TG=40%W=3908%O=M548NNSNW7%CC=Y%Q=) T1(R=Y%DF=Y%T=3B-45%TG=40%S=O%A=S+%F=AS%RD=0%Q=) T2(R=N) T3(R=N) T4(R=Y%DF=Y%T=3B-45%TG=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=) T5(R=Y%DF=Y%T=3B-45%TG=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=) T6(R=Y%DF=Y%T=3B-45%TG=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=) T7(R=Y%DF=Y%T=3B-45%TG=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=) U1(DF=N%T=3B-45%TG=40%IPL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G) IE(DFI=N%T=3B-45%TG=40%CD=S)
看上去仍是人话的前三行描述了该特征对应的 OS。须要解释的是鬼画符通常的后面几行。
每一行都是一项测试的结果,其中 XXX()
中的 XXX 是测试的名字。括号内以 %
分隔的各项是测试中的各类指标。每项指标的值都是 K-V 形式,K 是指标的名字,而 V 具体怎么解释,则各个指标各个不一样。具体表明什么烦请查阅 https://nmap.org/book/osdetec... 。
全部的测试分红五组,详见 https://nmap.org/book/osdetec... 的说明。第一组测试包含 SEQ、OPS、WIN、T1。这项测试会发送六个 TCP 包,而后检查响应的各类细节。第二组测试是 IE,会发送两个不一样的 ICMP echo 请求,检测其响应特征。第三组测试是 U1,发送一个 UDP 包给一个关闭的端口,而后看下 ICMP 的 port unreachable 回复。第四组测试是 ECN,全称是 Explicit Congestion Notification,即“显式拥塞通知”。该测试会发送带 ECN 位的 TCP 请求,比较其响应。最后一组是发送六个不一样的 TCP 包,这六个 TCP 包的响应结果将对应T2到T7的各项指标,其中 T2-T4 会发给打开的 TCP 端口,T5-T7 会发给关闭的 TCP 端口。