def read_log(self, file): # clear the log in iphone Utils.cmd_block('cat /dev/null > /var/log/syslog') log_file = open(file) while 1: line = log_file.readline() self.check_log_line(line)
def check(self): log_file = ['/var/log/syslog'] # start check log sensitive data check = Checker(log_file, 'LOG') check.start() data.log_file_results = check.results Utils.printy_result('Log Check.', 1)
def finish_dynamic_check(self): self.t_socket.join() data.dynamic_json = self.app_dynamic_info Utils.printy_result("Dynamic Check .", 1) self.analyse() IOS.storage_check() data.status ^= 0b0001 return True
def on(self): try: self.con = sqlite3.connect("task.db") self.c = self.con.cursor() except sqlite3.Error as e: # print e.args[0] data.logger.debug("Can't Connect to Database") Utils.shutdown()
def via_sftp(src): cmd = 'cp {} /tmp/temp.binary'.format(src) Utils.cmd_block(data.client, cmd) src = '/tmp/temp.binary' des = '{}/temp/{}/binary/'.format( os.path.abspath('.'), data.start_time) + data.metadata['bundle_id'] Utils.sftp_get(config.mobile_ip, config.ssh_port, config.mobile_user, config.mobile_password, src, des) return des
def connect(connector): if connector == "u": thread.start_new_thread(tcprelay.main, (['-t', '22:2222'], )) time.sleep(5) while True: try: Utils.printy('Conneting..', 0) data.client = ssh.set_ssh_conn(config.mobile_ip, config.ssh_port, config.mobile_user, config.mobile_password) break except socket.error: time.sleep(5) Utils.printy_result('Operation timed out.', 0)
def stand_alone_entrance(self): # self.start_dynamic_check() IOS.binary_check() # self.server_scan(','.join(String().get_url(data.strings))) # nessus self.start_static_analyse() # 静态引擎是独立的引擎,可生成独立的报告 # self.check_status() # 动态检测timeout data.dynamic_json = self.app_dynamic_info self.analyse() IOS.storage_check() report_gen = Generator() # 生成报告 report_gen.generate() Utils.printy("Analyze Done.", 4) # 分析结束 self.clean()
def __init__(self, ipa_path, bundle_id): if not data.logger: data.logger = logging.getLogger('root') self.status = 0 self.need_connection = False Utils.build() pre_status = IOSs.prepare_for_basic_info(ipa_path, bundle_id) if pre_status == 4: self.status = 4 elif pre_status == 5: self.status = 5 self.t_static = static_analyze.static_analyzer() self.server = Nessus()
def stand_alone_entrance(self): self.start_dynamic_check() IOSs.binary_check() self.server_scan(','.join(String().get_url(data.strings))) self.start_static_analyse() self.check_status() data.dynamic_json = self.app_dynamic_info self.analyse() IOSs.storage_check() report_gen = Generator() report_gen.generate() Utils.printy("Analyze Done.", 4) self.clean()
def do_analyse(self): data.static_process_id = os.getpid() exec "from staticAnalyzer import StaticAnalyze" exec "from staticAnalyzer.ttypes import *" Utils.printy('Start static analysis', 0) time.sleep(1) try: transport = TSocket.TSocket(config.thrift_ip, config.thrift_port) transport = TTransport.TBufferedTransport(transport) protocol = TBinaryProtocol.TBinaryProtocol(transport) client = StaticAnalyze.Client(protocol) transport.open() while True: if client.connect() == "Connected": Utils.printy_result("Connect to IDA Server", 1) break report_dir = "{}/temp/{}/report".format(data.root, data.start_time) msg = client.analyze(data.static_file_path, report_dir, report_type='pdf') if msg == "Fail": Utils.printy_result("Static Analyse", 0) else: Utils.printy_result('Static Analyse.', 1) data.static_report = msg transport.close() data.status ^= 0b0010 except Thrift.TException, ex: print "%s" % ex.message
def sql_check(): try: files = get_files() if not files: Utils.printy("No SQL files found ", 2) return retrieved_files = Utils.get_dataprotection(files) data.local_file_protection.extend(retrieved_files) check = Checker(files, 'SQL') check.start() Utils.printy_result('Database Check.', 1) return check.results except Exception, e: data.logger.warn(e)
def check(self): try: files = self.get_files() if not files: Utils.printy("No Plist files found ", 2) return # Add data protection class retrieved_files = Utils.get_dataprotection(files) data.local_file_protection.extend(retrieved_files) # start check plist sensitive data check = Checker(files, 'PLIST') check.start() data.plist_file_results = check.results except Exception, e: data.logger.warn(e)
def get_files(): files = [] dirs = [data.metadata['bundle_directory'], data.metadata['data_directory']] dirs_str = ' '.join(dirs) cmd = '{bin} {dirs_str} -type f -name "*.sqlite"'.format( bin=data.DEVICE_TOOLS['FIND'], dirs_str=dirs_str) temp = Utils.cmd_block(data.client, cmd).split("\n") cmd = '{bin} {dirs_str} -type f -name "*.db"'.format( bin=data.DEVICE_TOOLS['FIND'], dirs_str=dirs_str) temp.extend(Utils.cmd_block(data.client, cmd).split("\n")) for db in temp: if db != '': files.append(db) return files
def crashed(self): cmd = 'find {} -type f | grep {}'.format(data.crash_report_folder, self.app) if Utils.cmd_block(data.client, cmd).split("\n")[0]: return True else: return False
def __init__(self, ipa_path, bundle_id, connector, static_type=None): data.static_type = static_type if not data.logger: data.logger = logging.getLogger('root') self.status = 0 # 作为检测任务,与server.py中对应 IOS.connect(connector) # 与测试机建立连接 Utils.build() # 在测试机中建立文件夹,用于检测的中间文件存储 pre_status = IOS.prepare_for_basic_info(ipa_path, bundle_id) if pre_status == 4: self.status = 4 elif pre_status == 5: self.status = 5 self.t_static = static_analyze.static_analyzer() # 静态分析入口 do_analyse self.app_dynamic_info = AppDynamicInfo(data.app_bundleID) self.t_socket = socketServer.SocketServerThread(self.app_dynamic_info) self.server = Nessus()
def check_status(self): process_time = 0 while True: time.sleep(10) process_time += 10 status = data.status & 0b11 if status == 0b11: break # dynamic not finished elif status == 0b10: if process_time >= 180: self.t_socket.stop() # self.t_socket.join() Utils.printy_result("Stop Dynamic Analysis, Timeout", 0) break else: continue
def parse_plist(self, plist): """Given a plist file, copy it to temp folder, convert it to XML, and run plutil on it.""" # Copy the plist plist_temp = self.build_temp_path_for_file(plist.strip("'")) plist_copy = Utils.escape_path(plist_temp) self.file_copy(plist, plist_copy) # Convert to xml cmd = '{plutil} -convert xml1 {plist}'.format( plutil=data.DEVICE_TOOLS['PLUTIL'], plist=plist_copy) Utils.cmd_block(self.client, cmd) # Cat the content cmd = 'cat {}'.format(plist_copy) out = Utils.cmd_block(self.client, cmd) # Parse it with plistlib out = str(''.join(out).encode('utf-8')) pl = plistlib.readPlistFromString(out) return pl
def __run_otool(self, query, grep=None): """Run otool against a specific architecture.""" cmd = '{bin} {query} {app}'.format(bin=data.DEVICE_TOOLS['OTOOL'], query=query, app=data.metadata['binary_path']) if grep: cmd = "%s | grep -Ei \"%s\"" % (cmd, grep) out = Utils.cmd_block(self.client, cmd).split("\n") return out
def prepare_for_basic_info(ipa_path, bundle_id): # data.app_dict = Utils.ret_LastLaunch() # set app_dict # if ipa_path: # should_install.install_ipa_from_local(ipa_path) # set bundleID # elif bundle_id: # data.app_bundleID = bundle_id # else: # should_install.ask_for_user_choose() # Utils.getInstalledAppList() # set bundle_ID # Metadata().get_metadata() # print data.app_bundleID # pre_clutch.clutch() if ipa_path: try: should_install.install_ipa_from_local(ipa_path) # set bundleID except Exception, e: Utils.printy("Cannot install ipa ", 2) data.logger.debug(e) return 4
def _detect_architectures(self, binary): """Use lipo to detect supported architectures.""" # Run lipo cmd = '{lipo} -info {binary}'.format(lipo=data.DEVICE_TOOLS['LIPO'], binary=binary) out = Utils.cmd_block(self.client, cmd) # Parse output msg = out.strip() res = msg.rsplit(': ')[-1].split(' ') return res
def start_server(self): HOST = config.socket_ip PORT = config.socket_port self.dynamic_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.dynamic_socket.bind((HOST, int(PORT))) self.dynamic_socket.listen(1) Utils.printy('Start server to receive data from application.', 0) while not self.stopped(): conn, addr = self.dynamic_socket.accept() input_data = conn.recv(2048) input_data = input_data[0:-1] if input_data == ('DONE:' + data.app_bundleID): Utils.printy_result("Dynamic Check .", 1) self.dynamic_socket.close() break elif input_data == 'Timeout': self.dynamic_socket.close() break self.parse_json(self.app_info, input_data) data.status ^= 0b0001
def paltform_entrance(self): self.start_dynamic_check() IOSs.binary_check() self.server_scan(','.join(String().get_url(data.strings))) self.start_static_analyse() # data.status ^= 0b0010 self.check_status() data.dynamic_json = self.app_dynamic_info self.analyse() IOSs.storage_check() report_gen = Generator() report_gen.generate() Utils.printy("Analyze Done.", 4) # if self.finish_dynamic_check(): # self.analyse() # IOS.storage_check() # if self.finish_static_analyse(): # report_gen = Generator() # report_gen.generate() # if self.finish_server_scan(): self.clean()
def get_files(self): files = [] dirs = [ data.metadata['bundle_directory'], data.metadata['data_directory'] ] dirs_str = ' '.join(dirs) cmd = '{bin} {dirs_str} -type f -name "*.plist"'.format( bin=data.DEVICE_TOOLS['FIND'], dirs_str=dirs_str) temp = Utils.cmd_block(self.client, cmd).split("\n") for f in temp: if f != '': files.append(f) return files
def dump_binary(): try: target_doc_path = data.metadata['data_directory'] + '/Documents' target_doc_file = target_doc_path + '/dumpdecrypted.dylib' Utils.sftp_put(ip=config.mobile_ip, port=config.ssh_port, username=config.mobile_user, password=config.mobile_password, remote_path=target_doc_file, local_file='./tools/dumpdecrypted.dylib') target_bin_path = data.metadata['binary_path'] dump_cmd = 'DYLD_INSERT_LIBRARIES={} {}'.format( target_doc_file, target_bin_path) Utils.cmd_block(data.client, dump_cmd) # get decrypted file from iphone remote_file = './{}.decrypted'.format(data.metadata['binary_name']) data.static_file_path = bin_get.via_sftp(remote_file) return True except Exception: return False
def dump(self): try: cmd = './keychain_dumper' out = Utils.cmd_block(self.client, cmd) lines = out.split('\n') for line in lines: if line.startswith('Keychain Data:') and not '(null)' in line: content = line[15:] if content: self.all_keychain_values.append(content) self.filter() except Exception, e: data.logger.warn(e)
def ask_for_user_choose(): Utils.printy('[1]: I have installed the app .', 1) Utils.printy('[2]: I have the ipa file local to install.', 1) while True: user_choose_input = raw_input(clint.textui.colored.yellow("> >> >>> Enter your choice please [1/2]: > ")) if user_choose_input == '1': Utils.getInstalledAppList() break elif user_choose_input == '2': if install_ipa_from_local(""): break else: continue else: Utils.printy('Invalid input!', 2)
def prepare_for_basic_info(ipa_path, bundle_id): # data.app_dict = Utils.ret_LastLaunch() # set app_dict # if ipa_path: # should_install.install_ipa_from_local(ipa_path) # set bundleID # elif bundle_id: # data.app_bundleID = bundle_id # else: # should_install.ask_for_user_choose() # Utils.getInstalledAppList() # set bundle_ID # Metadata().get_metadata() # print data.app_bundleID # pre_clutch.clutch() # data.app_dict = Utils.ret_last_launch() !!! NOT SUPPORTED BY iOS9 ANYMORE if not data.app_dict: data.app_dict = Utils.ret_last_launch_9() # 获取当前已安装应用列表 if ipa_path: # 来自于平台 try: should_install.install_ipa_from_local(ipa_path) # set bundleID except Exception, e: Utils.printy("Cannot install ipa ", 2) data.logger.debug(e) return 4 # 安装失败
def get(self): cmd = '{bin} -L {app}'.format(bin=data.DEVICE_TOOLS['OTOOL'], app=data.metadata['binary_path']) out = Utils.cmd_block(self.client, cmd).split("\n") if out: try: del out[0] for i in out: i = i.strip('\t') if len(i) > 0: data.shared_lib.append(i) # print "--------------------shared_library-------------------" return True except AttributeError: return False else: return False
def fuzz(self): total_count = len(self.fuzz_inputs) count = 0 for url in self.fuzz_inputs: count += 1 # print '[{}/{}]fuzzing...[{}]'.format(count, total_count, url) time.sleep(1) self.delete_old_reports() Utils.openurl(url) time.sleep(2) Utils.kill_by_name(self.app) self.results[url] = self.crashed() Utils.printy_result('Fuzz', True) data.fuzz_result = self.results
def install_ipa_from_local(ipa_path): if ipa_path: # 从平台下发的任务,经由这个方法,ipa_path有值 ipa = zipfile.ZipFile(ipa_path) pat = re.compile("Payload[/\\\][\w.]+[/\\\]Info.plist") for name in ipa.namelist(): if pat.search(name): plist_path = name break # plist_path = ipa.extract(name) # plist = plistlib.readPlist(plist_path) # data.app_bundleID = plistlib.readPlist(plist_path)["CFBundleIdentifier"] # print data.app_bundleID else: # 从单机版入口,ipa_path为空,需要实时要求用户输入 while True: ipa_path = raw_input(clint.textui.colored.yellow("> >> >>> Input the Path: > ")).strip() if not os.path.exists(ipa_path): Utils.printy_result('No such file ', 0) elif not ipa_path.endswith("ipa"): Utils.printy_result('Not ipa file ', 0) else: break # sftp to iPhone Utils.sftp_put(config.mobile_ip, config.ssh_port, config.mobile_user, config.mobile_password, '/tmp/detect/temp.ipa', ipa_path) if ipa_path: ipa = zipfile.ZipFile(ipa_path) pat = re.compile("Payload[/\\\][\w.]+[/\\\]Info.plist") for name in ipa.namelist(): if pat.search(name): break plist_path = ipa.extract(name) tmp = plist_path + '.tmp' data.app_bundleID = commands.getstatusoutput( 'plutil -extract CFBundleIdentifier xml1 {} -o {}; plutil -p {}'. format(plist_path, tmp, tmp))[1].strip('"') Utils.cmd_block(data.client, 'ipainstaller {}'.format('/tmp/detect/temp.ipa')) return True