def __init__(self, utils, app=None, ipa=None): Log.w('Creating Analysis for: {app} / {ipa}'.format(app=app, ipa=ipa)) self.UTILS = utils self.IPA = ipa self.APP = app self.PREPARED = self.prepare_analysis()
def run_static_analysis(self): issues = [] import mat.modules.android.static static_checks = [ m.replace('.py', '') for m in listdir(mat.modules.android.static.__path__[0]) if not m.endswith('.pyc') and not m.startswith('__') ] for check in static_checks: Log.d('Running Static {check}'.format(check=check)) check_module = __import__( 'mat.modules.android.static.{check}'.format(check=check), fromlist=['Issue']) issue = check_module.Issue(self) if issue.dependencies(): issue.run() else: Log.e('Error: Dependencies not met.') if issue.REPORT: issues += [issue] issues += self._run_custom_static_analysis() return issues
def clean_analysis(self): Log.w('Cleaning Android Analysis') if settings.uninstall: self.UTILS.ADB.uninstall(self.PACKAGE) if settings.clean: Utils.rmtree(self.LOCAL_WORKING_FOLDER)
def prepare_analysis(self): Log.w('Getting latest cordova versions') import urllib2 response = urllib2.urlopen(CordovaAnalysis.LATEST_VERSION_URL) html = response.read() for os in CordovaAnalysis.LATEST_VERSION: self.LATEST_VERSION[os] = html.split( '-{os}-'.format(os=os))[1].rsplit('.', 1)[0]
def __init__(self, utils, apk=None, package=None): Log.w('Creating Analysis for: {app} / {apk}'.format(apk=apk, app=package)) self.UTILS = utils self.WORKING_APK_FILE = apk self.PACKAGE = package self.PREPARED = self.prepare_analysis() self.REMOTE_DATA_FOLDER = self.UTILS.data_path(self.PACKAGE) self.REMOTE_APP_FOLDER = self.UTILS.app_path(self.PACKAGE)
def _run_custom_modules(self, module_type): issues = [] modules = self.get_custom_modules([module_type]) for m in modules: Log.d('Running Static {check}'.format(check=m.__name__)) issue = m.Issue(self) if issue.dependencies(): issue.run() else: Log.e('Error: Dependencies not met.') if issue.REPORT: issues += [issue] return issues
def run_analysis(self): Log.w('Starting Analysis.') self.prepare_analysis() if not self.CONFIG_FILE and not self.CORDOVA_FILE: Log.w('No cordova files found.') return [] issues = [] import mat.modules.cordova.static static_checks = [ m.replace('.py', '') for m in listdir(mat.modules.cordova.static.__path__[0]) if not m.endswith('.pyc') and not m.startswith('__') ] for check in static_checks: Log.d('Running Static {check}'.format(check=check)) check_module = __import__( 'mat.modules.cordova.static.{check}'.format(check=check), fromlist=['Issue']) issue = check_module.Issue(self) if issue.dependencies(): issue.run() else: Log.e('Error: Dependencies not met.') if issue.REPORT: issues += [issue] issues += self._run_custom_static_analysis() return issues
def run_dynamic_analysis(self): if not self.UTILS.ADB.unlocked(settings.device): Log.w('Please unlock the device') while not self.UTILS.ADB.unlocked(settings.device): sleep(5) # launch the app self.UTILS.launch_app(self.PACKAGE) issues = [] import mat.modules.android.dynamic dynamic_checks = [ m.replace('.py', '') for m in listdir(mat.modules.android.dynamic.__path__[0]) if not m.endswith('.pyc') and not m.startswith('__') ] for check in dynamic_checks: Log.d('Running Dynamic {check}'.format(check=check)) check_module = __import__( 'mat.modules.android.dynamic.{check}'.format(check=check), fromlist=['Issue']) issue = check_module.Issue(self) if issue.dependencies(): issue.run() else: Log.e('Error: Dependencies not met.') if issue.REPORT: issues += [issue] issues += self._run_custom_dynamic_analysis() return issues
def run_dynamic_analysis(self): # launch the app self.UTILS.launch_app(self.APP_INFO) issues = [] import mat.modules.ios.dynamic dynamic_checks = [m.replace('.py', '') for m in listdir(mat.modules.ios.dynamic.__path__[0]) if not m.endswith('.pyc') and not m.startswith('__')] for check in dynamic_checks: Log.d('Running Dynamic {check}'.format(check=check)) check_module = __import__('mat.modules.ios.dynamic.{check}'.format(check=check), fromlist=['Issue']) issue = check_module.Issue(self) if issue.dependencies(): issue.run() else: Log.e('Error: Dependencies not met.') if issue.REPORT: issues += [issue] issues += self._run_custom_dynamic_analysis() return issues
def __init__(self, root=None, data=None, atype=None, config=None, cordova=None): self.ASSESSMENT_TYPE = atype self.ROOT = root self.CONFIG_FILE = config self.CORDOVA_FILE = cordova if self.ROOT and not self.CONFIG_FILE: for location in CordovaAnalysis.LOCATIONS['config']: if path.exists('{root}/{loc}'.format(root=self.ROOT, loc=location)): self.CONFIG_FILE = '{root}/{loc}'.format(root=self.ROOT, loc=location) break if self.ROOT and not self.CORDOVA_FILE: for location in CordovaAnalysis.LOCATIONS['cordova']: if path.exists('{root}/{loc}'.format(root=self.ROOT, loc=location)): self.CORDOVA_FILE = '{root}/{loc}'.format(root=self.ROOT, loc=location) break if not self.CORDOVA_FILE and data: self.CORDOVA_FILE = Utils.run( 'find {data} -name cordova.js'.format( data=data))[0].split('\n')[0].strip() if not self.CONFIG_FILE and self.ROOT: self.CONFIG_FILE = Utils.run('find {root} -name config.xml'.format( root=self.ROOT))[0].split('\n')[0].strip() Log.d('Root: {fpath}'.format(fpath=self.ROOT)) Log.d('cordova.js: {fpath}'.format(fpath=self.CORDOVA_FILE)) Log.d('config.xml: {fpath}'.format(fpath=self.CONFIG_FILE))
def prepare_analysis(self): Log.w('Preparing iOS Analysis') if not self.UTILS.check_dependencies(['full'], install=True, silent=True): Log.e('Error: Required dependencies not met') # create local output folder Log.d('Creating local output folders') self.LOCAL_WORKING_FOLDER = '{output}/{work}-{uuid}'.format(output=settings.output, work=self.LOCAL_WORKING_FOLDER, uuid=(self.APP or self.IPA.rsplit('/',1)[-1].rsplit('.',1)[0])) self.LOCAL_DATA_CONTENT = '{main}/{data}'.format(main=self.LOCAL_WORKING_FOLDER, data=self.LOCAL_DATA_CONTENT) self.LOCAL_BIN_FOLDER = '{main}/{data}'.format(main=self.LOCAL_WORKING_FOLDER, data=self.LOCAL_BIN_FOLDER) self.LOCAL_CLASS_DUMP = '{main}/{data}'.format(main=self.LOCAL_WORKING_FOLDER, data=self.LOCAL_CLASS_DUMP) self.LOCAL_UNZIPED = '{main}/{data}'.format(main=self.LOCAL_WORKING_FOLDER, data=self.LOCAL_UNZIPED) local_paths = ['LOCAL_WORKING_FOLDER', 'LOCAL_DATA_CONTENT', 'LOCAL_BIN_FOLDER', 'LOCAL_CLASS_DUMP'] for local_path in local_paths: if not path.exists(getattr(self, local_path)): makedirs(getattr(self, local_path)) if self.UTILS.check_dependencies(['connection'], silent=True): # create a temp folder to work with Log.d('Creating iOS Working folders') self.UTILS.run_on_ios('mkdir {working}'.format(working=self.IOS_WORKING_FOLDER)) self.UTILS.run_on_ios('chmod 777 {working}'.format(working=self.IOS_WORKING_FOLDER)) # push tools to the temp folder self.UTILS.push(settings.dump_log, self.IOS_WORKING_FOLDER) self.UTILS.push(settings.dump_fileprot, self.IOS_WORKING_FOLDER) self.UTILS.push(settings.dump_decrypt, self.IOS_WORKING_FOLDER) self.UTILS.push(settings.keychain_dump, self.IOS_WORKING_FOLDER) self.UTILS.push(settings.backup_excluded, self.IOS_WORKING_FOLDER) # update binary paths self.UTILS.DUMP_DECRYPT = '{working}/{binary}'.format(working=self.IOS_WORKING_FOLDER, binary=settings.dump_decrypt.rsplit('/', 1)[1]) self.UTILS.KEYCHAIN_DUMP = '{working}/{binary}'.format(working=self.IOS_WORKING_FOLDER, binary=settings.keychain_dump.rsplit('/', 1)[1]) self.UTILS.DUMP_FILE_PROTECT = '{working}/{binary}'.format(working=self.IOS_WORKING_FOLDER, binary=settings.dump_fileprot.rsplit('/', 1)[1]) self.UTILS.DUMP_LOG = '{working}/{binary}'.format(working=self.IOS_WORKING_FOLDER, binary=settings.dump_log.rsplit('/', 1)[1]) self.UTILS.BACKUP_EXCLUDED = '{working}/{binary}'.format(working=self.IOS_WORKING_FOLDER, binary=settings.backup_excluded.rsplit('/', 1)[1]) if self.APP: # no need to check if there's connection - it will return None if there's no connection apps = self.UTILS.list_apps(silent=True) self.APP = apps[self.APP] if self.APP in apps else None if not self.APP: Log.e("Error: The ID specified was not found in the applications list.") return False if self.IPA: self.LOCAL_IPA = '{binaries}/{ipa}'.format(binaries=self.LOCAL_BIN_FOLDER, ipa=self.IPA.rsplit('/', 1)[-1]) Utils.run('cp {original} {dest}'.format(original=self.IPA, dest=self.LOCAL_IPA)) if self.UTILS.check_dependencies(['connection'], silent=True): self.APP = self.UTILS.install(self.LOCAL_IPA) if not self.APP: Log.e('Error: Couldn\'t install the app or retreive its details') return False if not self.IPA: self.APP_INFO = self.UTILS.get_info(self.APP_INFO['Path'], ios=True) self.LOCAL_WORKING_BIN, self.LOCAL_IPA = self.UTILS.pull_ipa(self.APP, self.APP_INFO, self.LOCAL_BIN_FOLDER) if self.LOCAL_IPA: UNZIPED_APP, self.APP_INFO = self.UTILS.unzip_to(self.LOCAL_IPA, self.LOCAL_UNZIPED) if not hasattr(self, 'LOCAL_WORKING_BIN'): self.LOCAL_WORKING_BIN = '{app}/{binary}'.format(app=UNZIPED_APP, binary=self.APP_INFO['CFBundleExecutable']) # copy working bin to the device: if not hasattr(self, 'LOCAL_WORKING_BIN') and self.UTILS.check_dependencies(['connection'], silent=True): self.IOS_WORKING_BIN = '{working}/{binary}'.format(working=self.IOS_WORKING_FOLDER, binary=self.APP_INFO['CFBundleExecutable']) self.UTILS.push(self.LOCAL_WORKING_BIN, self.IOS_WORKING_FOLDER) if self.APP and 'Container' in self.APP: self.IOS_DATA_PATH = self.APP['Container'].replace(' ', '\ ') if self.APP and self.APP_INFO: self.IOS_BIN_PATH = self.UTILS.app_executable(self.APP, self.APP_INFO) self.LOCAL_CLASS_DUMP = '{base}/{app}'.format(base=self.LOCAL_CLASS_DUMP, app=self.APP_INFO['CFBundleExecutable']) # get classes ########################## TESTING ##################################### if not path.exists(self.LOCAL_CLASS_DUMP): makedirs(self.LOCAL_CLASS_DUMP) self.UTILS.dump_classes_to_file(self.UTILS.dump_classes(self.LOCAL_WORKING_BIN), self.LOCAL_CLASS_DUMP) ########################## END ##################################### return True #and self.UTILS.check_dependencies(['full'], install=False, silent=True)
def run_analysis(self, analysis_type='full'): if not self.PREPARED: Log.e('Error: Analysis not prepared') return [] Log.w("Starting iOS Analysis") ### checks start here if self.UTILS.check_dependencies(['static'], silent=True, install=False): issues = self.run_static_analysis() if analysis_type != 'static' and self.UTILS.check_dependencies(['dynamic'], silent=True, install=False): issues += self.run_dynamic_analysis() ### get data from device Log.d('Getting data from device') self.UTILS.pull(self.IOS_DATA_PATH, self.LOCAL_DATA_CONTENT) issues += self.run_cordova_checks() # calculate and save md5 md5 = Utils.run('{md5sum} {ipa}'.format(md5sum=settings.md5sum, ipa=self.LOCAL_IPA))[0] with open('{working}/{ipa}.md5'.format(working=self.LOCAL_BIN_FOLDER, ipa=self.IPA.rsplit('/', 1)[-1]), 'w') as f: f.write(md5.split(' ', 1)[0].strip()) # print app information Log.w('******************** Application Info ********************') Log.w('Application: {app}'.format(app=self.APP_INFO['CFBundleName'])) Log.w('Version : {version}'.format(version=self.APP_INFO['CFBundleShortVersionString'])) Log.w('Binary : {binary}'.format(binary= self.APP_INFO['CFBundleExecutable'])) Log.w('MD5 : {md5}'.format(md5=md5.strip().split('\n')[0])) Log.w('******************** End Info ********************') self.clean_analysis() return issues
def prepare_analysis(self, decompile=True): Log.w('Preparing Android Analysis') if not self.UTILS.check_dependencies( ['static', 'dynamic'], install=True, silent=True): Log.e('Error: Not all ependencies met, run `-r` for more details') # Creates local folders to store the analysis data self.LOCAL_WORKING_FOLDER = '{output}/{work}-{uuid}'.format( output=settings.output, work=AndroidAnalysis.LOCAL_WORKING_FOLDER, uuid=(self.PACKAGE or self.WORKING_APK_FILE.rsplit( '/', 1)[-1].rsplit('.', 1)[0])) self.LOCAL_DATA_CONTENT = '{main}/{data}'.format( main=self.LOCAL_WORKING_FOLDER, data=AndroidAnalysis.LOCAL_DATA_CONTENT) self.LOCAL_DECOMPILED_APP = '{main}/{data}'.format( main=self.LOCAL_WORKING_FOLDER, data=AndroidAnalysis.LOCAL_DECOMPILED_APP) self.LOCAL_SOURCE = '{main}/{data}'.format( main=self.LOCAL_WORKING_FOLDER, data=AndroidAnalysis.LOCAL_SOURCE) local_paths = [ 'LOCAL_WORKING_FOLDER', 'LOCAL_DATA_CONTENT', 'LOCAL_DECOMPILED_APP', 'LOCAL_SOURCE' ] for local_path in local_paths: if not path.exists(getattr(self, local_path)): makedirs(getattr(self, local_path)) if self.WORKING_APK_FILE: original = self.WORKING_APK_FILE self.WORKING_APK_FILE = '{working}/{apk}'.format( working=self.LOCAL_WORKING_FOLDER, apk=self.WORKING_APK_FILE.rsplit('/', 1)[-1]) Utils.run('cp {oapk} {apk}'.format(oapk=original, apk=self.WORKING_APK_FILE)) if self.UTILS.device(): Log.w('Installing application') self.UTILS.install(self.WORKING_APK_FILE) elif self.PACKAGE: device_apk = self.UTILS.get_apk(self.PACKAGE) if not device_apk: Log.e('Error: Package not found on the device') return False self.WORKING_APK_FILE = '{working}/{package}.apk'.format( working=self.LOCAL_WORKING_FOLDER, package=self.PACKAGE) self.UTILS.pull(device_apk, self.WORKING_APK_FILE) if not self.WORKING_APK_FILE or not path.exists(self.WORKING_APK_FILE): Log.e('Error: Local APK file not found.') return False # decompile apk if decompile: Log.w('Decompiling {apk} to {dir}'.format( apk=self.WORKING_APK_FILE, dir=self.LOCAL_DECOMPILED_APP)) Utils.run('{apktool} -q d -f {apk} -o {out}'.format( apktool=settings.apktool, apk=self.WORKING_APK_FILE, out=self.LOCAL_DECOMPILED_APP)) self.MANIFEST = Manifest(self.LOCAL_DECOMPILED_APP, settings.apkfilename) self.PACKAGE = self.MANIFEST.package self.JAR_FILE = '{working}/{package}.jar'.format( working=self.LOCAL_WORKING_FOLDER, package=self.PACKAGE) self.LOCAL_SMALI = '{decompiled}/smali'.format( decompiled=self.LOCAL_DECOMPILED_APP) if decompile: Log.w('Converting {apk} classes to {jar}'.format( apk=self.WORKING_APK_FILE, jar=self.JAR_FILE)) Utils.run('{dex2jar} --force -o {jar} {apk}'.format( dex2jar=settings.dex2jar, apk=self.WORKING_APK_FILE, jar=self.JAR_FILE)) Log.d('Extrating java classes from {jar} to {src}'.format( src=self.LOCAL_SOURCE, jar=self.JAR_FILE)) Utils.run('{jdcli} {jar} -od {src}'.format(jdcli=settings.jdcli, src=self.LOCAL_SOURCE, jar=self.JAR_FILE)) return True
def run_analysis(self, analysis_type='full'): if not self.PREPARED: Log.e('Error: Analysis not prepared') return [] issues = [] Log.w('Starting Android Analysis') if self.UTILS.check_dependencies(['static'], silent=True, install=False): issues = self.run_static_analysis() issues += self.run_cordova_analysis() if analysis_type != 'static' and self.UTILS.check_dependencies( ['dynamic'], silent=True, install=False): Log.w('Starting Dynamic Analysis') issues += self.run_dynamic_analysis() # calculate and save md5 md5 = Utils.run('{md5sum} {working}'.format( md5sum=settings.md5sum, working=self.WORKING_APK_FILE))[0] with open('{working}.md5'.format(working=self.WORKING_APK_FILE), 'w') as f: f.write(md5.split(' ', 1)[0].strip()) # print app information Log.w('******************** Application Info ********************') Log.w('Package: {app}'.format(app=self.PACKAGE)) Log.w('Version: {version}'.format(version=self.MANIFEST.version)) Log.w('APK : {binary}'.format(binary=self.WORKING_APK_FILE)) Log.w('MD5 : {md5}'.format(md5=md5.strip().split('\n')[0])) Log.w('******************** End Info ********************') self.clean_analysis() return issues
def run(self): Log.w('Checking emulator detection (this may take a while)') if self.ANALYSIS.UTILS.check_dependencies(['avd'], install=True): # get devices devices = self.ANALYSIS.UTILS.devices() # start emulator sleep(2) process = Utils.emulator() Log.w('Waiting for emulator to start') sleep(30) if self.ANALYSIS.UTILS.CREATED_AVD: Log.w( 'AVD just created, allowing 3 more minutes before proceeding' ) sleep(180) # diff devices -> get emulator emulator = list(set(self.ANALYSIS.UTILS.devices()) - set(devices)) if len(emulator) == 1: emulator = emulator[0] Log.w('Waiting for {emulator}'.format(emulator=emulator)) while not self.ANALYSIS.UTILS.online(emulator): sleep(5) if not self.ANALYSIS.UTILS.unlocked(emulator): Log.w('Please unlock the emulator') while not self.ANALYSIS.UTILS.unlocked(emulator): sleep(5) # install and run the apk in emulator self.ANALYSIS.UTILS.install_on(emulator, self.ANALYSIS.WORKING_APK_FILE) self.ANALYSIS.UTILS.launch_app(device=emulator, package=self.ANALYSIS.PACKAGE) Log.w('Launching the app on the emulator') sleep(10) # check if app in ps if self.ANALYSIS.PACKAGE in self.ANALYSIS.UTILS.processes( emulator, root=False): self.REPORT = True else: Log.e( 'More than one new device detected - emulator checks not performed' ) # terminate emulator process.kill() Log.d('Checking for code that references to emulator checks') self.DETAILS = '' result = Utils.grep_command( '-arin -e "generic.*Build\.FINGERPRINT" -e "Build\.FINGERPRINT.*generic -e "sdk.*Build\.PRODUCT" -e "Build\.PRODUCT.*sdk" -e "Secure\.ANDROID_ID" -e "getSensorList" {src}' .format(src=self.ANALYSIS.LOCAL_SOURCE), self.ANALYSIS.LOCAL_SOURCE) if result: self.DETAILS += Utils.grep_details(result, self.ANALYSIS.LOCAL_SOURCE) self.REPORT = True