6.46 在中文Win7上使用Metasploit Framework 3.7.0时udp_sock.sendto()未能发出UDP报文 https://scz.617.cn/network/201105041447.txt D: scz@nsfocus 2011-05-04 12:43 近日偶然通过wireshark抓包发现,在中文Win7上使用Metasploit Framework 3.7.0 时udp_sock.sendto()未能发出UDP报文: -------------------------------------------------------------------------- udp_sock = Rex::Socket::Udp.create( { 'LocalHost' => datastore['CHOST'] || nil, 'Context' => {'Msf' => framework, 'MsfExploit' => self} }) udp_sock.sendto(data, ip, rport, 0) -------------------------------------------------------------------------- 但udp_sock.put()可以发出UDP报文: -------------------------------------------------------------------------- udp_sock = Rex::Socket::Udp.create( { 'LocalHost' => datastore['CHOST'] || nil, 'PeerHost' => ip, 'PeerPort' => rport, 'Context' => {'Msf' => framework, 'MsfExploit' => self} }) udp_sock.put(data) -------------------------------------------------------------------------- 前者没有connect(),后者connect()过。 -------------------------------------------------------------------------- # # C:\Program Files\Rapid7\framework\msf3\lib\rex\socket\udp.rb # def sendto(gram, peerhost, peerport, flags = 0) # # Catch unconnected IPv6 sockets talking to IPv4 addresses # peer = Rex::Socket.resolv_nbo(peerhost) if (peer.length == 4 and self.ipv == 6) peerhost = Rex::Socket.getaddress(peerhost) if peerhost[0,7].downcase != '::ffff:' peerhost = '::ffff:' + peerhost end end ... end -------------------------------------------------------------------------- sendto()跟IPv6有些纠缠,而我的Win7通过如下设置禁用了IPv6: -------------------------------------------------------------------------- Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\TCPIP6\Parameters] "DisabledComponents"=dword:ffffffff -------------------------------------------------------------------------- 用如下代码发现ipv被设为6: -------------------------------------------------------------------------- print_status( "#{udp_sock.ipv}" ) -------------------------------------------------------------------------- ipv在这里被设置: -------------------------------------------------------------------------- # # C:\Program Files\Rapid7\framework\msf3\lib\rex\socket.rb # # Initialize general socket parameters. # def initsock(params = nil) if (params) self.peerhost = params.peerhost self.peerport = params.peerport self.localhost = params.localhost self.localport = params.localport self.context = params.context || {} self.ipv = params.v6 ? 6 : 4 end end -------------------------------------------------------------------------- v6在这里被设置: -------------------------------------------------------------------------- # # C:\Program Files\Rapid7\framework\msf3\lib\rex\socket\parameters.rb # def initialize(hash) ... # # Whether to force IPv6 addressing # self.v6 = hash['IPv6'] || false end -------------------------------------------------------------------------- 对应下面这种用法: -------------------------------------------------------------------------- udp_sock = Rex::Socket::Udp.create( { 'LocalHost' => datastore['CHOST'] || nil, 'IPv6' => false, 'Context' => {'Msf' => framework, 'MsfExploit' => self} }) -------------------------------------------------------------------------- 参数"IPv6"默认就是false,如果设为true,表示强制使用IPv6地址。但v6在其它地 方会被修改: -------------------------------------------------------------------------- # # C:\Program Files\Rapid7\framework\msf3\lib\rex\socket\comm\local.rb # # Creates a socket using the supplied Parameter instance. # def self.create_by_type(param, type, proto = 0) # Whether to use IPv6 addressing usev6 = false # Detect IPv6 addresses and enable IPv6 accordingly if ( Rex::Socket.support_ipv6?()) # Allow the caller to force IPv6 if (param.v6) usev6 = true end # Force IPv6 mode for non-connected UDP sockets if (type == ::Socket::SOCK_DGRAM and not param.peerhost) # FreeBSD allows IPv6 socket creation, but throws an error on sendto() if (not Rex::Compat.is_freebsd()) usev6 = true end end local = Rex::Socket.resolv_nbo(param.localhost) if param.localhost peer = Rex::Socket.resolv_nbo(param.peerhost) if param.peerhost if (local and local.length == 16) usev6 = true end if (peer and peer.length == 16) usev6 = true end if (usev6) ... param.v6 = true end else # No IPv6 support param.v6 = false end ... if (param.v6) sock = ::Socket.new(::Socket::AF_INET6, type, proto) else sock = ::Socket.new(::Socket::AF_INET, type, proto) end ... sock end -------------------------------------------------------------------------- 假设Rex::Socket.support_ipv6?()返回true,对于没有connect()过的UDP套接字, 上述代码强制进入IPv6模式,usev6被设为true,从而导致v6被设为true。 -------------------------------------------------------------------------- # # C:\Program Files\Rapid7\framework\msf3\lib\rex\socket.rb # # Cache our IPv6 support flag @@support_ipv6 = nil # # Determine whether we support IPv6 # def self.support_ipv6? return @@support_ipv6 if not @@support_ipv6.nil? @@support_ipv6 = false if (::Socket.const_defined?('AF_INET6')) begin s = ::Socket.new(::Socket::AF_INET6, ::Socket::SOCK_DGRAM, ::Socket::IPPROTO_UDP) s.close @@support_ipv6 = true rescue end end return @@support_ipv6 end -------------------------------------------------------------------------- 看上去Metasploit认为我的Win7支持IPv6,从而导致sendto()使用IPv6,而我已经禁 用了IPv6,于是sendto()未能发出UDP报文。 我猜DisabledComponents设为0xFFFFFFFF没有彻底、干净地禁用IPv6,这点从如下命 令的输出即可看出: -------------------------------------------------------------------------- >netstat -na | findstr "::" TCP [::]:135 [::]:0 LISTENING UDP [::]:500 *:* UDP [::]:4500 *:* >sc qc tcpip6 [SC] QueryServiceConfig SUCCESS SERVICE_NAME: tcpip6 TYPE : 1 KERNEL_DRIVER START_TYPE : 3 DEMAND_START ERROR_CONTROL : 1 NORMAL BINARY_PATH_NAME : system32\DRIVERS\tcpip.sys LOAD_ORDER_GROUP : TAG : 0 DISPLAY_NAME : Microsoft IPv6 Protocol Driver DEPENDENCIES : Tcpip SERVICE_START_NAME : >sc query tcpip6 SERVICE_NAME: tcpip6 TYPE : 1 KERNEL_DRIVER STATE : 1 STOPPED WIN32_EXIT_CODE : 1077 (0x435) SERVICE_EXIT_CODE : 0 (0x0) CHECKPOINT : 0x0 WAIT_HINT : 0x0 -------------------------------------------------------------------------- 或者说Metasploit判断OS是否支持IPv6的办法有缺陷,tcpip6这个驱动并未加载。 2007年12月31日有人反馈,在FreeBSD上存在类似问题,参看: http://dev.metasploit.com/redmine/issues/172.pdf 后来的修正方案就是前面那个is_freebsd()调用。 这个问题估计很难被发现,因为像我这样变态地配置Win7的人不多,懒得报告这个自 己玩自己导致的BUG了。我的修正方案是: -------------------------------------------------------------------------- # # C:\Program Files\Rapid7\framework\msf3\lib\rex\socket.rb # # Determine whether we support IPv6 # def self.support_ipv6? return false end -------------------------------------------------------------------------- 用如下办法测试,用wireshark同步抓包: -------------------------------------------------------------------------- irb udp_sock = Rex::Socket::Udp.create() udp_sock.sendto("foo", "10.17.255.254", 137, 0) --------------------------------------------------------------------------