Skip to content

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:


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)