Path: blob/master/modules/auxiliary/admin/natpmp/natpmp_map.rb
19813 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45require 'English'6class MetasploitModule < Msf::Auxiliary7include Msf::Auxiliary::Report8include Msf::Auxiliary::Scanner9include Msf::Auxiliary::NATPMP10include Rex::Proto::NATPMP1112def initialize13super(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_LICENSE18)1920register_options(21[22OptString.new('EXTERNAL_PORTS', [true, 'The external ports to forward from (0 to let the target choose)', 0]),23OptString.new('INTERNAL_PORTS', [true, 'The internal ports to forward to', '22,135-139,80,443,445'])24],25self.class26)27end2829def build_ports(ports_string)30# We don't use Rex::Socket.portspec_crack because we need to allow 0 and preserve order31ports = []32ports_string.split(/[ ,]/).map(&:strip).compact.each do |port_part|33if /^(?<port>\d+)$/ =~ port_part34ports << port.to_i35elsif /^(?<low>\d+)\s*-\s*(?<high>\d+)$/ =~ port_part36ports |= (low..high).to_a.map(&:to_i)37else38raise ArgumentError, "Invalid port specification #{port_part}"39end40end41ports42end4344def setup45super46@external_ports = build_ports(datastore['EXTERNAL_PORTS'])47@internal_ports = build_ports(datastore['INTERNAL_PORTS'])4849if @external_ports.size > @internal_ports.size50raise ArgumentError, "Too many external ports specified (#{@external_ports.size}); " \51"must be one port (0) or #{@internal_ports.size} ports"52end5354if @external_ports.size < @internal_ports.size55if @external_ports != [0]56raise ArgumentError, "Incorrect number of external ports specified (#{@external_ports.size}); " \57"must be one port (0) or #{@internal_ports.size} ports"58else59@external_ports = [0] * @internal_ports.size60end61end62end6364def run_host(host)65udp_sock = Rex::Socket::Udp.create({66'LocalHost' => datastore['CHOST'] || nil,67'Context' => { 'Msf' => framework, 'MsfExploit' => self }68})69add_socket(udp_sock)7071external_address = get_external_address(udp_sock, host, datastore['RPORT']) || host7273@external_ports.each_index do |i|74external_port = @external_ports[i]75internal_port = @internal_ports[i]7677actual_ext_port = map_port(udp_sock, host, datastore['RPORT'], internal_port, external_port, Rex::Proto::NATPMP.const_get(protocol), lifetime)78map_target = Rex::Socket.source_address(host)79requested_forwarding = "#{external_address}:#{external_port}/#{protocol}" \80' -> ' \81"#{map_target}:#{internal_port}/#{protocol}"82if actual_ext_port83map_target = datastore['CHOST'] || Rex::Socket.source_address(host)84actual_forwarding = "#{external_address}:#{actual_ext_port}/#{protocol}" \85' -> ' \86"#{map_target}:#{internal_port}/#{protocol}"87if external_port == 088print_good("#{actual_forwarding} forwarded")89elsif external_port != 0 && external_port != actual_ext_port90print_good("#{requested_forwarding} could not be forwarded, but #{actual_forwarding} could")91else92print_good("#{requested_forwarding} forwarded")93end94else95print_error("#{requested_forwarding} could not be forwarded")96end9798report_service(99host: host,100port: datastore['RPORT'],101proto: 'udp',102name: 'natpmp',103state: Msf::ServiceState::Open104)105end106rescue ::Interrupt107raise $ERROR_INFO108rescue ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionRefused109nil110rescue StandardError => e111print_error("Unknown error: #{e.class} #{e.backtrace}")112end113end114115116