1 UDP 3478状态报告错误
以下实验用于重现此问题:
在本地安装了一台Windows XP2的虚拟机,并开启防火墙。在虚拟机内使用netstat命令查看自己的端口状态:
运行命令netstat -an,得到以下结果:
而同时,在本地PC机上使用Nmap6.00对该虚拟机XP的UDP端口进行扫描。Nmap将会报告该虚拟机的UDP 3478是开放的。虚拟机IP为192.168.1.121,本地PC的IP为192.168.1.103。
2 Wireshark抓包与调试log
Nmap使用的扫描命令:
nmap -sU -sV -p 3478 -d3 --reason 192.168.1.121> F:/nmapudp3478.txt
在wireshark中,没有看到来自目标机的任何UDP的回复包。而在log中可以看到在调试信息行里面包含了“READ TIMEOUT”,读取信息超时,所以,本质上Nmap并没有从该UDP端口上读取到任何数据。
3 根本原因分析
使用调试器跟踪,逐步排查到问题所在,在脚本文件stun.lua中有以下的函数:
-- Gets the server version ifit was returned by the server
-- @return status true onsuccess, false on failure
-- @return version stringcontaining the server product and version
getVersion = function(self)
-- check ifthe server version was cached
if (not(self.cache) or not(self.cache.version) ) then
self:getExternalAddress()
end
return true,(self.cache and self.cache.server or "")
end,
该函数用于获取stun(3478端口对应的服务名字)服务器的版本信息。在每次进行stun服务扫描时都会调用到该函数。
在我们场景中,将目标机的防火墙打开,在用Nmap进行端口扫描时,不会收到3478的UDP回复包,因而Nmap将3478的状态设置为open|filtered(请参见nmap扫描原理部分);而在进行服务扫描阶段,会对此类可能为开放的端口进行服务扫描,此时就会调用stun.lua脚本中getVersion()函数。
此函数,若在目标机stun端口开放时,执行流程正确;而在stun端口没有开放时,却会产生错误。原因在于上述红色代码行中,仅尝试获取stun外部地址,并没有判断获取的结果。而后续的返回行里面,直接返回true(表示服务是开启的)和server的版本信息(可能为空)。所以,即使对方stun端口根本没有开启,在此处也会被判断为开启。
4 解决方法
与stun.lua脚本的作者Patrik讨论了这个问题,他同意此处是一个BUG。
目前已经将代码做了如下修改:
--Gets the server version if it was returned by the server
--@return status true on success, false on failure
--@return version string containing the server product and version
getVersion= function(self)
local status, response = false, nil
--check if the server version was cached
if( not(self.cache) or not(self.cache.version) ) then
local status, response = self:getExternalAddress()
if ( status ) then
return true,(self.cache and self.cache.server or "")
end
return false, response
end
return true, (self.cache and self.cache.server or "")
end,