CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/admin/natpmp/natpmp_map.rb
Views: 1904
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Auxiliary
7
include Msf::Auxiliary::Report
8
include Msf::Auxiliary::Scanner
9
include Msf::Auxiliary::NATPMP
10
include Rex::Proto::NATPMP
11
12
def initialize
13
super(
14
'Name' => 'NAT-PMP Port Mapper',
15
'Description' => 'Map (forward) TCP and UDP ports on NAT devices using NAT-PMP',
16
'Author' => 'Jon Hart <jhart[at]spoofed.org>',
17
'License' => MSF_LICENSE
18
)
19
20
register_options(
21
[
22
OptString.new('EXTERNAL_PORTS', [true, 'The external ports to forward from (0 to let the target choose)', 0]),
23
OptString.new('INTERNAL_PORTS', [true, 'The internal ports to forward to', '22,135-139,80,443,445'])
24
],
25
self.class
26
)
27
end
28
29
def build_ports(ports_string)
30
# We don't use Rex::Socket.portspec_crack because we need to allow 0 and preserve order
31
ports = []
32
ports_string.split(/[ ,]/).map { |s| s.strip }.compact.each do |port_part|
33
if /^(?<port>\d+)$/ =~ port_part
34
ports << port.to_i
35
elsif /^(?<low>\d+)\s*-\s*(?<high>\d+)$/ =~ port_part
36
ports |= (low..high).to_a.map(&:to_i)
37
else
38
fail ArgumentError, "Invalid port specification #{port_part}"
39
end
40
end
41
ports
42
end
43
44
def setup
45
super
46
@external_ports = build_ports(datastore['EXTERNAL_PORTS'])
47
@internal_ports = build_ports(datastore['INTERNAL_PORTS'])
48
49
if @external_ports.size > @internal_ports.size
50
fail ArgumentError, "Too many external ports specified (#{@external_ports.size}); " +
51
"must be one port (0) or #{@internal_ports.size} ports"
52
end
53
54
if @external_ports.size < @internal_ports.size
55
if @external_ports != [0]
56
fail ArgumentError, "Incorrect number of external ports specified (#{@external_ports.size}); " +
57
"must be one port (0) or #{@internal_ports.size} ports"
58
else
59
@external_ports = [0] * @internal_ports.size
60
end
61
end
62
end
63
64
def run_host(host)
65
begin
66
67
udp_sock = Rex::Socket::Udp.create({
68
'LocalHost' => datastore['CHOST'] || nil,
69
'Context' => {'Msf' => framework, 'MsfExploit' => self}
70
})
71
add_socket(udp_sock)
72
73
external_address = get_external_address(udp_sock, host, datastore['RPORT']) || host
74
75
@external_ports.each_index do |i|
76
external_port = @external_ports[i]
77
internal_port = @internal_ports[i]
78
79
actual_ext_port = map_port(udp_sock, host, datastore['RPORT'], internal_port, external_port, Rex::Proto::NATPMP.const_get(protocol), lifetime)
80
map_target = Rex::Socket.source_address(host)
81
requested_forwarding = "#{external_address}:#{external_port}/#{protocol}" +
82
" -> " +
83
"#{map_target}:#{internal_port}/#{protocol}"
84
if actual_ext_port
85
map_target = datastore['CHOST'] ? datastore['CHOST'] : Rex::Socket.source_address(host)
86
actual_forwarding = "#{external_address}:#{actual_ext_port}/#{protocol}" +
87
" -> " +
88
"#{map_target}:#{internal_port}/#{protocol}"
89
if external_port == 0
90
print_good("#{actual_forwarding} forwarded")
91
else
92
if (external_port != 0 && external_port != actual_ext_port)
93
print_good("#{requested_forwarding} could not be forwarded, but #{actual_forwarding} could")
94
else
95
print_good("#{requested_forwarding} forwarded")
96
end
97
end
98
else
99
print_error("#{requested_forwarding} could not be forwarded")
100
end
101
102
report_service(
103
:host => host,
104
:port => datastore['RPORT'],
105
:proto => 'udp',
106
:name => 'natpmp',
107
:state => Msf::ServiceState::Open
108
)
109
end
110
rescue ::Interrupt
111
raise $!
112
rescue ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionRefused
113
nil
114
rescue ::Exception => e
115
print_error("Unknown error: #{e.class} #{e.backtrace}")
116
end
117
end
118
end
119
120