@@ -22,15 +22,48 @@ def initialize
22
22
23
23
register_options (
24
24
[
25
- OptPort . new ( 'EXTERNAL_PORT' , [ true , 'The external port to foward from' ] ) ,
26
- OptPort . new ( 'INTERNAL_PORT' , [ true , 'The internal port to forward to' ] ) ,
27
- OptInt . new ( 'LIFETIME' , [ true , "Time in ms to keep this port forwarded" , 3600000 ] ) ,
28
- OptEnum . new ( 'PROTOCOL' , [ true , "Protocol to forward" , 'TCP' , %w( TCP UDP ) ] ) ,
25
+ OptString . new ( 'EXTERNAL_PORTS' , [ true , 'The external ports to foward from (0 to let the target choose)' , 0 ] ) ,
26
+ OptString . new ( 'INTERNAL_PORTS' , [ true , 'The internal ports to forward to' , '22,135-139,80,443,445' ] )
29
27
] ,
30
28
self . class
31
29
)
32
30
end
33
31
32
+ def build_ports ( ports_string )
33
+ # We don't use Rex::Socket.portspec_crack because we need to allow 0 and preserve order
34
+ ports = [ ]
35
+ ports_string . split ( /[ ,]/ ) . map { |s | s . strip } . compact . each do |port_part |
36
+ if /^(?<port>\d +)$/ =~ port_part
37
+ ports << port . to_i
38
+ elsif /^(?<low>\d +)\s *-\s *(?<high>\d +)$/ =~ port_part
39
+ ports |= ( low ..high ) . to_a . map ( &:to_i )
40
+ else
41
+ fail ArgumentError , "Invalid port specification #{ port_part } "
42
+ end
43
+ end
44
+ ports
45
+ end
46
+
47
+ def setup
48
+ super
49
+ @external_ports = build_ports ( datastore [ 'EXTERNAL_PORTS' ] )
50
+ @internal_ports = build_ports ( datastore [ 'INTERNAL_PORTS' ] )
51
+
52
+ if @external_ports . size > @internal_ports . size
53
+ fail ArgumentError , "Too many external ports specified (#{ @external_ports . size } ); " +
54
+ "must be one port (0) or #{ @internal_ports . size } ports"
55
+ end
56
+
57
+ if @external_ports . size < @internal_ports . size
58
+ if @external_ports != [ 0 ]
59
+ fail ArgumentError , "Incorrect number of external ports specified (#{ @external_ports . size } ); " +
60
+ "must be one port (0) or #{ @internal_ports . size } ports"
61
+ else
62
+ @external_ports = [ 0 ] * @internal_ports . size
63
+ end
64
+ end
65
+ end
66
+
34
67
def run_host ( host )
35
68
begin
36
69
@@ -40,25 +73,42 @@ def run_host(host)
40
73
} )
41
74
add_socket ( udp_sock )
42
75
43
- # get the external address first
44
- vprint_status "#{ host } - NATPMP - Probing for external address"
45
- udp_sock . sendto ( external_address_request , host , datastore [ 'RPORT' ] , 0 )
46
- external_address = nil
47
- while ( r = udp_sock . recvfrom ( 12 , 1 ) and r [ 1 ] )
48
- ( ver , op , result , epoch , external_address ) = parse_external_address_response ( r [ 0 ] )
49
- end
76
+ external_address = get_external_address ( udp_sock , host , datastore [ 'RPORT' ] ) || host
77
+
78
+ @external_ports . each_index do |i |
79
+ external_port = @external_ports [ i ]
80
+ internal_port = @internal_ports [ i ]
50
81
51
- vprint_status "#{ host } - NATPMP - Sending mapping request"
52
- # build the mapping request
53
- req = map_port_request (
54
- datastore [ 'INTERNAL_PORT' ] , datastore [ 'EXTERNAL_PORT' ] ,
55
- Rex ::Proto ::NATPMP . const_get ( datastore [ 'PROTOCOL' ] ) , datastore [ 'LIFETIME' ]
56
- )
57
- # send it
58
- udp_sock . sendto ( req , host , datastore [ 'RPORT' ] , 0 )
59
- # handle the reply
60
- while ( r = udp_sock . recvfrom ( 16 , 1 ) and r [ 1 ] )
61
- handle_reply ( Rex ::Socket . source_address ( host ) , host , external_address , r )
82
+ actual_ext_port = map_port ( udp_sock , host , datastore [ 'RPORT' ] , internal_port , external_port , Rex ::Proto ::NATPMP . const_get ( protocol ) , lifetime )
83
+ map_target = Rex ::Socket . source_address ( host )
84
+ requested_forwarding = "#{ external_address } :#{ external_port } /#{ protocol } " +
85
+ " -> " +
86
+ "#{ map_target } :#{ internal_port } /#{ protocol } "
87
+ if actual_ext_port
88
+ map_target = datastore [ 'CHOST' ] ? datastore [ 'CHOST' ] : Rex ::Socket . source_address ( host )
89
+ actual_forwarding = "#{ external_address } :#{ actual_ext_port } /#{ protocol } " +
90
+ " -> " +
91
+ "#{ map_target } :#{ internal_port } /#{ protocol } "
92
+ if external_port == 0
93
+ print_good ( "#{ actual_forwarding } forwarded" )
94
+ else
95
+ if ( external_port != 0 && external_port != actual_ext_port )
96
+ print_good ( "#{ requested_forwarding } could not be forwarded, but #{ actual_forwarding } could" )
97
+ else
98
+ print_good ( "#{ requested_forwarding } forwarded" )
99
+ end
100
+ end
101
+ else
102
+ print_error ( "#{ requested_forwarding } could not be forwarded" )
103
+ end
104
+
105
+ report_service (
106
+ :host => host ,
107
+ :port => datastore [ 'RPORT' ] ,
108
+ :proto => 'udp' ,
109
+ :name => 'natpmp' ,
110
+ :state => Msf ::ServiceState ::Open
111
+ )
62
112
end
63
113
rescue ::Interrupt
64
114
raise $!
@@ -69,43 +119,4 @@ def run_host(host)
69
119
end
70
120
end
71
121
72
- def handle_reply ( map_target , host , external_address , pkt )
73
- return if not pkt [ 1 ]
74
-
75
- if ( pkt [ 1 ] =~ /^::ffff:/ )
76
- pkt [ 1 ] = pkt [ 1 ] . sub ( /^::ffff:/ , '' )
77
- end
78
-
79
- ( ver , op , result , epoch , internal_port , external_port , lifetime ) = parse_map_port_response ( pkt [ 0 ] )
80
-
81
- if ( result == 0 )
82
- if ( datastore [ 'EXTERNAL_PORT' ] != external_port )
83
- print_status ( "#{ external_address } " +
84
- "#{ datastore [ 'EXTERNAL_PORT' ] } /#{ datastore [ 'PROTOCOL' ] } -> #{ map_target } " +
85
- "#{ internal_port } /#{ datastore [ 'PROTOCOL' ] } couldn't be forwarded" )
86
- end
87
- print_status ( "#{ external_address } " +
88
- "#{ external_port } /#{ datastore [ 'PROTOCOL' ] } -> #{ map_target } " +
89
- "#{ internal_port } /#{ datastore [ 'PROTOCOL' ] } forwarded" )
90
- end
91
-
92
- # report NAT-PMP as being open
93
- report_service (
94
- :host => host ,
95
- :port => pkt [ 2 ] ,
96
- :proto => 'udp' ,
97
- :name => 'natpmp' ,
98
- :state => Msf ::ServiceState ::Open
99
- )
100
-
101
- # report the external port as being open
102
- if inside_workspace_boundary? ( external_address )
103
- report_service (
104
- :host => external_address ,
105
- :port => external_port ,
106
- :proto => datastore [ 'PROTOCOL' ] . to_s . downcase ,
107
- :state => Msf ::ServiceState ::Open
108
- )
109
- end
110
- end
111
122
end
0 commit comments