|
一个端口开着,漏洞理不代表它该开着。扫描漏洞扫描器干的工具第一件事,就是漏洞理把这个“不该”找出来。 它的扫描底层逻辑其实很朴素:先敲门,再看门后有什么,工具最后对着已知的漏洞理“坏东西”名单逐一比对。整个过程拆开来看,扫描就是工具资产发现、服务识别、漏洞理漏洞匹配三步。扫描每一步都有不少门道。工具 先知道有什么,漏洞理才能判断哪里有问题 扫描器启动后,扫描第一件事是工具扫端口。TCP连接扫描最好理解——直接跟目标端口完成三次握手,连上了就是开着,连不上就关着。简单粗暴,但速度快、准确率高,缺点是会在目标日志里留下大量连接记录。老练的运维一眼就能看出来有人在扫。 于是有了SYN扫描。只发SYN包,收到SYN-ACK就说明端口开着,然后立刻发RST断开,从不完成握手。这叫“半开扫描”,隐蔽性好了不少。nmap默认就干这个。还有FIN扫描、XMAS扫描这些偏门手法,利用的是不同操作系统对异常TCP标志位的反应差异,能绕过一些简单的包过滤防火墙。 端口扫完,扫描器已经拿到一张“地图”:哪些IP活着,哪些端口开着。接下来要搞清楚每个端口后面跑的是什么服务、什么版本。这一步叫服务识别。 最直接的办法是抓banner。很多服务连上就会自报家门,比如SSH会返回“SSH-2.0-OpenSSH_8.9p1”,FTP会返回“220 ProFTPD 1.3.5”。扫描器把这些字符串抓下来,跟指纹库比对,就能判断出服务类型和版本号。但banner可以改,可以伪装,所以光靠这个不够。 更可靠的方式是主动探测。扫描器发送一系列精心构造的请求,观察响应特征。比如发一个畸形的HTTP请求,看返回的错误页面长什么样——Apache和Nginx的报错格式完全不同。再比如探测TLS握手时支持的加密套件列表,不同版本的OpenSSL有细微差别。这些特征组合起来,就形成了服务的“指纹”。 匹配才是核心,但匹配比想象中复杂 拿到服务名和版本号之后,扫描器去漏洞库里查。漏洞库通常以CVE编号为索引,每条记录包含影响范围、利用条件、危害等级。扫描器把目标的“服务+版本”跟库里的“影响范围”做比对,命中就报漏洞。 听起来很直接,但实际情况要复杂得多。同一个版本号,打没打补丁,漏洞状态完全不同。比如OpenSSH 8.9p1,如果发行版backport了安全修复,它可能不受某个CVE影响,但版本号看起来跟受影响的一样。扫描器如果只看版本号,就会误报。这就是为什么很多渗透测试人员说“扫描器报的洞,一半是假的”。 还有一种情况更麻烦:配置类漏洞。比如Redis未授权访问,跟版本关系不大,关键是有没有设密码、有没有绑定0.0.0.0。扫描器需要实际尝试连接、执行PING命令、检查返回结果,才能判断。这类漏洞靠版本比对根本查不出来。 所以现代扫描器通常会做两件事:一是版本比对做初筛,二是发送PoC(概念验证)请求做确认。比如检测Log4Shell,扫描器会构造一个带JNDI payload的请求发过去,看目标有没有触发外连。触发了就是有漏洞,没触发就是没有。这种“验证式扫描”准确率高得多,但速度慢,而且可能对目标系统造成影响。 我见过不少团队只依赖扫描器的版本比对结果,报告里列了一堆高危漏洞,开发团队修了一轮发现全是误报,后来就没人信扫描报告了。工具本身没问题,是用法太粗糙。 扫描器不是万能钥匙 漏洞扫描器能发现的是“已知的、有明确特征的”问题。零日漏洞它查不出来,逻辑漏洞它查不出来,需要多步交互才能触发的漏洞它也查不出来。它更像是一个自动化巡检工,拿着检查清单逐项打勾,而不是一个能推理、能联想的安全专家。 但这不意味着它没用。在一个有几百台服务器的环境里,靠人工去核对每个服务的补丁状态,根本不现实。扫描器能在几小时内完成初筛,把可疑目标圈出来,剩下的交给人工验证。这个定位才是准确的。 真正好用的扫描策略,往往是“扫描器+人工”的组合。扫描器负责覆盖面和速度,人负责判断力和深度。工具永远只是工具,关键还是看谁在用、怎么用。 |