@@ -303,52 +303,20 @@ def load_session_info()
303303 safe_info . gsub! ( /[\x00 -\x08 \x0b \x0c \x0e -\x19 \x7f -\xff ]+/n , "_" )
304304 self . info = safe_info
305305
306- # Enumerate network interfaces to detect IP
307- ifaces = self . net . config . get_interfaces ( ) . flatten rescue [ ]
308- routes = self . net . config . get_routes ( ) . flatten rescue [ ]
309- shost = self . session_host
310-
311- # Try to match our visible IP to a real interface
312- # TODO: Deal with IPv6 addresses
313- found = !!( ifaces . find { |i | i . addrs . find { |a | a == shost } } )
314- nhost = nil
315- hobj = nil
316-
317- if Rex ::Socket . is_ipv4? ( shost ) and not found
318-
319- # Try to find an interface with a default route
320- default_routes = routes . select { |r | r . subnet == "0.0.0.0" || r . subnet == "::" }
321- default_routes . each do |r |
322- ifaces . each do |i |
323- bits = Rex ::Socket . net2bitmask ( i . netmask ) rescue 32
324- rang = Rex ::Socket ::RangeWalker . new ( "#{ i . ip } /#{ bits } " ) rescue nil
325- if rang and rang . include? ( r . gateway )
326- nhost = i . ip
327- break
328- end
329- end
330- break if nhost
331- end
306+ hobj = nil
332307
333- # Find the first non-loopback address
334- if not nhost
335- iface = ifaces . select { |i | i . ip != "127.0.0.1" and i . ip != "::1" }
336- if iface . length > 0
337- nhost = iface . first . ip
338- end
339- end
340- end
308+ nhost = find_internet_connected_address
341309
310+ original_session_host = self . session_host
342311 # If we found a better IP address for this session, change it up
343312 # only handle cases where the DB is not connected here
344- if not ( framework . db and framework . db . active )
313+ if ! ( framework . db && framework . db . active )
345314 self . session_host = nhost
346315 end
347316
348-
349317 # The rest of this requires a database, so bail if it's not
350318 # there
351- return if not ( framework . db and framework . db . active )
319+ return if ! ( framework . db && framework . db . active )
352320
353321 ::ActiveRecord ::Base . connection_pool . with_connection {
354322 wspace = framework . db . find_workspace ( workspace )
@@ -384,18 +352,18 @@ def load_session_info()
384352 if nhost
385353 framework . db . report_note ( {
386354 :type => "host.nat.server" ,
387- :host => shost ,
355+ :host => original_session_host ,
388356 :workspace => wspace ,
389357 :data => { :info => "This device is acting as a NAT gateway for #{ nhost } " , :client => nhost } ,
390358 :update => :unique_data
391359 } )
392- framework . db . report_host ( :host => shost , :purpose => 'firewall' )
360+ framework . db . report_host ( :host => original_session_host , :purpose => 'firewall' )
393361
394362 framework . db . report_note ( {
395363 :type => "host.nat.client" ,
396364 :host => nhost ,
397365 :workspace => wspace ,
398- :data => { :info => "This device is traversing NAT gateway #{ shost } " , :server => shost } ,
366+ :data => { :info => "This device is traversing NAT gateway #{ original_session_host } " , :server => original_session_host } ,
399367 :update => :unique_data
400368 } )
401369 framework . db . report_host ( :host => nhost , :purpose => 'client' )
@@ -470,6 +438,60 @@ def create(param)
470438
471439 attr_accessor :rstream # :nodoc:
472440
441+ # Rummage through this host's routes and interfaces looking for an
442+ # address that it uses to talk to the internet.
443+ #
444+ # @see Rex::Post::Meterpreter::Extensions::Stdapi::Net::Config#get_interfaces
445+ # @see Rex::Post::Meterpreter::Extensions::Stdapi::Net::Config#get_routes
446+ # @return [String] The address from which this host reaches the
447+ # internet, as ASCII. e.g.: "192.168.100.156"
448+ def find_internet_connected_address
449+
450+ ifaces = self . net . config . get_interfaces ( ) . flatten rescue [ ]
451+ routes = self . net . config . get_routes ( ) . flatten rescue [ ]
452+
453+ # Try to match our visible IP to a real interface
454+ found = !!( ifaces . find { |i | i . addrs . find { |a | a == session_host } } )
455+ nhost = nil
456+
457+ # If the host has no address that matches what we see, then one of
458+ # us is behind NAT so we have to look harder.
459+ if !found
460+ # Grab all routes to the internet
461+ default_routes = routes . select { |r | r . subnet == "0.0.0.0" || r . subnet == "::" }
462+
463+ default_routes . each do |route |
464+ # Now try to find an interface whose network includes this
465+ # Route's gateway, which means it's the one the host uses to get
466+ # to the interweb.
467+ ifaces . each do |i |
468+ # Try all the addresses this interface has configured
469+ addr_and_mask = i . addrs . zip ( i . netmasks ) . find do |addr , netmask |
470+ bits = Rex ::Socket . net2bitmask ( netmask )
471+ range = Rex ::Socket ::RangeWalker . new ( "#{ addr } /#{ bits } " ) rescue nil
472+
473+ !!( range && range . valid? && range . include? ( route . gateway ) )
474+ end
475+ if addr_and_mask
476+ nhost = addr_and_mask [ 0 ]
477+ break
478+ end
479+ end
480+ break if nhost
481+ end
482+
483+ if !nhost
484+ # Find the first non-loopback address
485+ non_loopback = ifaces . find { |i | i . ip != "127.0.0.1" && i . ip != "::1" }
486+ if non_loopback
487+ nhost = non_loopback . ip
488+ end
489+ end
490+ end
491+
492+ nhost
493+ end
494+
473495end
474496
475497end
0 commit comments