CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/scanner/natpmp/natpmp_portscan.rb
Views: 11784
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 External Port Scanner',
15
'Description' => 'Scan NAT devices for their external listening ports using NAT-PMP',
16
'Author' => 'Jon Hart <jhart[at]spoofed.org>',
17
'License' => MSF_LICENSE
18
)
19
20
register_options(
21
[
22
OptString.new('PORTS', [true, "Ports to scan (e.g. 22-25,80,110-900)", "1-1000"])
23
])
24
end
25
26
def run_host(host)
27
begin
28
udp_sock = Rex::Socket::Udp.create({
29
'LocalHost' => datastore['CHOST'] || nil,
30
'Context' => {'Msf' => framework, 'MsfExploit' => self} }
31
)
32
add_socket(udp_sock)
33
peer = "#{host}:#{datastore['RPORT']}"
34
vprint_status("#{peer} Scanning #{protocol} ports #{datastore['PORTS']} using NATPMP")
35
36
external_address = get_external_address(udp_sock, host, datastore['RPORT'])
37
if (external_address)
38
print_good("#{peer} responded with external address of #{external_address}")
39
else
40
vprint_status("#{peer} didn't respond with an external address")
41
return
42
end
43
44
# clear all mappings
45
map_port(udp_sock, host, datastore['RPORT'], 0, 0, Rex::Proto::NATPMP.const_get(protocol), 0)
46
47
Rex::Socket.portspec_crack(datastore['PORTS']).each do |port|
48
map_req = map_port_request(port, port, Rex::Proto::NATPMP.const_get(datastore['PROTOCOL']), 1)
49
udp_sock.sendto(map_req, host, datastore['RPORT'], 0)
50
while (r = udp_sock.recvfrom(16, 1.0) and r[1])
51
break if handle_reply(host, external_address, r)
52
end
53
end
54
55
rescue ::Interrupt
56
raise $!
57
rescue ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionRefused
58
nil
59
rescue ::Exception => e
60
print_error("Unknown error: #{e.class} #{e.backtrace}")
61
end
62
end
63
64
def handle_reply(host, external_addr, pkt)
65
return if not pkt[1]
66
67
if(pkt[1] =~ /^::ffff:/)
68
pkt[1] = pkt[1].sub(/^::ffff:/, '')
69
end
70
host = pkt[1]
71
protocol = datastore['PROTOCOL'].to_s.downcase
72
73
(ver, op, result, epoch, int, ext, lifetime) = parse_map_port_response(pkt[0])
74
peer = "#{host}:#{datastore['RPORT']}"
75
if (result == 0)
76
# we always ask to map an external port to the same port on us. If
77
# we get a successful response back but the port we requested be forwarded
78
# is different, that means that someone else already has it open
79
if (int != ext)
80
state = Msf::ServiceState::Open
81
print_good("#{peer} #{external_addr} - #{int}/#{protocol} #{state} because of successful mapping with unmatched ports")
82
if inside_workspace_boundary?(external_addr)
83
report_service(
84
:host => external_addr,
85
:port => int,
86
:proto => protocol,
87
:state => state
88
)
89
end
90
else
91
state = Msf::ServiceState::Closed
92
vprint_error("#{peer} #{external_addr} - #{int}/#{protocol} #{state} because of successful mapping with matched ports")
93
end
94
else
95
state = Msf::ServiceState::Closed
96
vprint_error("#{peer} #{external_addr} - #{int}/#{protocol} #{state} because of code #{result} response")
97
end
98
99
report_service(
100
:host => host,
101
:port => pkt[2],
102
:name => 'natpmp',
103
:proto => 'udp',
104
:state => Msf::ServiceState::Open
105
)
106
true
107
end
108
end
109
110