WIP of NAT-PMP rework
This commit is contained in:
parent
8e58efbf4f
commit
ea6824c46f
|
@ -3,8 +3,6 @@
|
|||
#
|
||||
# NAT-PMP protocol support
|
||||
#
|
||||
# by Jon Hart <jhart@spoofed.org>
|
||||
#
|
||||
##
|
||||
|
||||
module Rex
|
||||
|
@ -16,6 +14,20 @@ module NATPMP
|
|||
[ 0, 0 ].pack('nn')
|
||||
end
|
||||
|
||||
def get_external_address(udp_sock, host, port, timeout=1)
|
||||
vprint_status("#{host}:#{port} - Probing NAT-PMP for external address")
|
||||
udp_sock.sendto(external_address_request, host, port, 0)
|
||||
external_address = nil
|
||||
while (r = udp_sock.recvfrom(12, timeout) and r[1])
|
||||
(ver, op, result, epoch, external_address) = parse_external_address_response(r[0])
|
||||
if external_address
|
||||
vprint_good("#{host}:#{port} - NAT-PMP external address is #{external_address}")
|
||||
break
|
||||
end
|
||||
end
|
||||
external_address
|
||||
end
|
||||
|
||||
# Parse a NAT-PMP external address response +resp+.
|
||||
# Returns the decoded parts of the response as an array.
|
||||
def parse_external_address_response(resp)
|
||||
|
@ -23,6 +35,21 @@ module NATPMP
|
|||
[ ver, op, result, epoch, Rex::Socket::addr_itoa(addr) ]
|
||||
end
|
||||
|
||||
def map_port(udp_sock, host, port, int_port, ext_port, protocol, lifetime, timeout=1)
|
||||
vprint_status("#{host}:#{port} - Sending NAT-PMP mapping request")
|
||||
# build the mapping request
|
||||
req = map_port_request(int_port, ext_port,
|
||||
Rex::Proto::NATPMP.const_get(datastore['PROTOCOL']), datastore['LIFETIME'])
|
||||
# send it
|
||||
udp_sock.sendto(req, host, datastore['RPORT'], 0)
|
||||
# handle the reply
|
||||
while (r = udp_sock.recvfrom(16, timeout) and r[1])
|
||||
(_, _, result, _, _, actual_ext_port, _) = parse_map_port_response(r[0])
|
||||
return (result == 0 ? actual_ext_port : nil)
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
# Return a NAT-PMP request to map remote port +rport+/+protocol+ to local port +lport+ for +lifetime+ ms
|
||||
def map_port_request(lport, rport, protocol, lifetime)
|
||||
[ Rex::Proto::NATPMP::Version, # version
|
||||
|
@ -39,6 +66,7 @@ module NATPMP
|
|||
def parse_map_port_response(resp)
|
||||
resp.unpack("CCnNnnN")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -40,25 +40,29 @@ class Metasploit3 < Msf::Auxiliary
|
|||
})
|
||||
add_socket(udp_sock)
|
||||
|
||||
# get the external address first
|
||||
vprint_status "#{host} - NATPMP - Probing for external address"
|
||||
udp_sock.sendto(external_address_request, host, datastore['RPORT'], 0)
|
||||
external_address = nil
|
||||
while (r = udp_sock.recvfrom(12, 1) and r[1])
|
||||
(ver, op, result, epoch, external_address) = parse_external_address_response(r[0])
|
||||
end
|
||||
# new
|
||||
external_address = get_external_address(udp_sock, host, datastore['RPORT']) || host
|
||||
actual_ext_port = map_port(udp_sock, host, datastore['RPORT'], datastore['INTERNAL_PORT'], datastore['EXTERNAL_PORT'], Rex::Proto::NATPMP.const_get(datastore['PROTOCOL']), datastore['LIFETIME'])
|
||||
|
||||
vprint_status "#{host} - NATPMP - Sending mapping request"
|
||||
# build the mapping request
|
||||
req = map_port_request(
|
||||
datastore['INTERNAL_PORT'], datastore['EXTERNAL_PORT'],
|
||||
Rex::Proto::NATPMP.const_get(datastore['PROTOCOL']), datastore['LIFETIME']
|
||||
)
|
||||
# send it
|
||||
udp_sock.sendto(req, host, datastore['RPORT'], 0)
|
||||
# handle the reply
|
||||
while (r = udp_sock.recvfrom(16, 1) and r[1])
|
||||
handle_reply(Rex::Socket.source_address(host), host, external_address, r)
|
||||
if actual_ext_port
|
||||
map_target = Rex::Socket.source_address(host)
|
||||
if (datastore['EXTERNAL_PORT'] != actual_ext_port)
|
||||
print_status( "#{external_address} " +
|
||||
"#{datastore['EXTERNAL_PORT']}/#{datastore['PROTOCOL']} -> #{map_target} " +
|
||||
"#{datastore['INTERNAL_PORT']}/#{datastore['PROTOCOL']} couldn't be forwarded")
|
||||
end
|
||||
print_status( "#{external_address} " +
|
||||
"#{actual_ext_port}/#{datastore['PROTOCOL']} -> #{map_target} " +
|
||||
"#{datastore['INTERNAL_PORT']}/#{datastore['PROTOCOL']} forwarded")
|
||||
|
||||
# report NAT-PMP as being open
|
||||
report_service(
|
||||
:host => host,
|
||||
:port => datastore['RPORT'],
|
||||
:proto => 'udp',
|
||||
:name => 'natpmp',
|
||||
:state => Msf::ServiceState::Open
|
||||
)
|
||||
end
|
||||
rescue ::Interrupt
|
||||
raise $!
|
||||
|
@ -69,43 +73,4 @@ class Metasploit3 < Msf::Auxiliary
|
|||
end
|
||||
end
|
||||
|
||||
def handle_reply(map_target, host, external_address, pkt)
|
||||
return if not pkt[1]
|
||||
|
||||
if(pkt[1] =~ /^::ffff:/)
|
||||
pkt[1] = pkt[1].sub(/^::ffff:/, '')
|
||||
end
|
||||
|
||||
(ver, op, result, epoch, internal_port, external_port, lifetime) = parse_map_port_response(pkt[0])
|
||||
|
||||
if (result == 0)
|
||||
if (datastore['EXTERNAL_PORT'] != external_port)
|
||||
print_status( "#{external_address} " +
|
||||
"#{datastore['EXTERNAL_PORT']}/#{datastore['PROTOCOL']} -> #{map_target} " +
|
||||
"#{internal_port}/#{datastore['PROTOCOL']} couldn't be forwarded")
|
||||
end
|
||||
print_status( "#{external_address} " +
|
||||
"#{external_port}/#{datastore['PROTOCOL']} -> #{map_target} " +
|
||||
"#{internal_port}/#{datastore['PROTOCOL']} forwarded")
|
||||
end
|
||||
|
||||
# report NAT-PMP as being open
|
||||
report_service(
|
||||
:host => host,
|
||||
:port => pkt[2],
|
||||
:proto => 'udp',
|
||||
:name => 'natpmp',
|
||||
:state => Msf::ServiceState::Open
|
||||
)
|
||||
|
||||
# report the external port as being open
|
||||
if inside_workspace_boundary?(external_address)
|
||||
report_service(
|
||||
:host => external_address,
|
||||
:port => external_port,
|
||||
:proto => datastore['PROTOCOL'].to_s.downcase,
|
||||
:state => Msf::ServiceState::Open
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -28,6 +28,48 @@ class Metasploit3 < Msf::Auxiliary
|
|||
], self.class)
|
||||
end
|
||||
|
||||
def run_host(host)
|
||||
begin
|
||||
|
||||
udp_sock = Rex::Socket::Udp.create({
|
||||
'LocalHost' => datastore['CHOST'] || nil,
|
||||
'Context' => {'Msf' => framework, 'MsfExploit' => self}
|
||||
})
|
||||
add_socket(udp_sock)
|
||||
|
||||
# new
|
||||
external_address = get_external_address(udp_sock, host, datastore['RPORT']) || host
|
||||
actual_ext_port = map_port(udp_sock, host, datastore['RPORT'], datastore['INTERNAL_PORT'], datastore['EXTERNAL_PORT'], Rex::Proto::NATPMP.const_get(datastore['PROTOCOL']), datastore['LIFETIME'])
|
||||
|
||||
if actual_ext_port
|
||||
map_target = Rex::Socket.source_address(host)
|
||||
if (datastore['EXTERNAL_PORT'] != actual_ext_port)
|
||||
print_status( "#{external_address} " +
|
||||
"#{datastore['EXTERNAL_PORT']}/#{datastore['PROTOCOL']} -> #{map_target} " +
|
||||
"#{datastore['INTERNAL_PORT']}/#{datastore['PROTOCOL']} couldn't be forwarded")
|
||||
end
|
||||
print_status( "#{external_address} " +
|
||||
"#{actual_ext_port}/#{datastore['PROTOCOL']} -> #{map_target} " +
|
||||
"#{datastore['INTERNAL_PORT']}/#{datastore['PROTOCOL']} forwarded")
|
||||
|
||||
# report NAT-PMP as being open
|
||||
report_service(
|
||||
:host => host,
|
||||
:port => datastore['RPORT'],
|
||||
:proto => 'udp',
|
||||
:name => 'natpmp',
|
||||
:state => Msf::ServiceState::Open
|
||||
)
|
||||
end
|
||||
rescue ::Interrupt
|
||||
raise $!
|
||||
rescue ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionRefused
|
||||
nil
|
||||
rescue ::Exception => e
|
||||
print_error("Unknown error: #{e.class} #{e.backtrace}")
|
||||
end
|
||||
end
|
||||
|
||||
def run_host(host)
|
||||
begin
|
||||
udp_sock = Rex::Socket::Udp.create({
|
||||
|
|
Loading…
Reference in New Issue