def connect_n_mount(self): """Test ADB Connection.""" self.adb_command(['kill-server']) self.adb_command(['start-server']) logger.info('ADB Restarted') self.wait(2) logger.info('Connecting to Android %s', self.identifier) if not self.run_subprocess_verify_output( [get_adb(), 'connect', self.identifier]): return False logger.info('Restarting ADB Daemon as root') if not self.run_subprocess_verify_output( [get_adb(), '-s', self.identifier, 'root']): return False logger.info('Reconnecting to Android Device') # connect again with root adb if not self.run_subprocess_verify_output( [get_adb(), 'connect', self.identifier]): return False # identify environment runtime = self.get_environment() logger.info('Remounting') # Allow non supported environments also self.adb_command(['remount']) logger.info('Performing System check') if not self.system_check(runtime): return False return True
def connect_n_mount(self): """Test ADB Connection.""" self.adb_command(['kill-server']) self.adb_command(['start-server']) logger.info('ADB Restarted') self.wait(2) logger.info('Connecting to Android %s', self.identifier) if not self.run_subprocess_verify_output([get_adb(), 'connect', self.identifier]): return False logger.info('Restarting ADB Daemon as root') if not self.run_subprocess_verify_output([get_adb(), 'root']): return False logger.info('Reconnect to Android Device') # connect again with root adb if not self.run_subprocess_verify_output([get_adb(), 'connect', self.identifier]): return False # mount system logger.info('Remounting /system') self.adb_command(['mount', '-o', 'rw,remount', '/system'], True) return True
def system_check(self, runtime): """Check if /system is writable.""" try: try: out = self.adb_command(['getprop', 'ro.build.version.sdk'], True) if out: api = int(out.decode('utf-8').strip()) logger.info('Android API Level ' 'identified as %s', api) if api > ANDROID_API_SUPPORTED: logger.error('This API Level is not supported' ' for Dynamic Analysis.') return False except Exception: pass err_msg = ('VM\'s /system is not writable. ' 'This VM cannot be used for ' 'Dynamic Analysis.') proc = subprocess.Popen([ get_adb(), '-s', self.identifier, 'shell', 'touch', '/system/test' ], stdout=subprocess.PIPE, stderr=subprocess.PIPE) _, stderr = proc.communicate() if b'Read-only' in stderr: logger.error(err_msg) if runtime == 'emulator': logger.error('Please start the AVD as per ' 'MobSF documentation!') return False except Exception: logger.error(err_msg) return False return True
def connect(): """Connect to VM/Device.""" logger.info('Connecting to VM/Device') adb = get_adb() subprocess.call([adb, 'kill-server']) subprocess.call([adb, 'start-server']) logger.info('ADB Started') wait(5) logger.info('Connecting to VM/Device') out = subprocess.check_output([adb, 'connect', get_identifier()]) if b'unable to connect' in out: raise ValueError('ERROR Connecting to VM/Device. ', out.decode('utf-8').replace('\n', '')) try: subprocess.call([adb, '-s', get_identifier(), 'wait-for-device']) logger.info('Mounting') if settings.ANDROID_DYNAMIC_ANALYZER == 'MobSF_REAL_DEVICE': adb_command( ['su', '-c', 'mount', '-o', 'rw,remount,rw', '/system'], True) else: adb_command( ['su', '-c', 'mount', '-o', 'rw,remount,rw', '/system'], True) # This may not work for VMs other than the default MobSF VM adb_command([ 'mount', '-o', 'rw,remount', '-t', 'rfs', '/dev/block/sda6', '/system' ], True) except Exception: logger.exception('Connecting to VM/Device')
def start_frida(): fnull = open(os.devnull, 'w') argz = [get_adb(), '-s', self.identifier, 'shell', '/system/fd_server'] subprocess.call(argz, stdout=fnull, stderr=subprocess.STDOUT)
def final_test(request): """Collecting Data and Cleanup.""" global TCP_SERVER_MODE logger.info('Collecting Data and Cleaning Up') try: if request.method == 'POST': data = {} md5_hash = request.POST['md5'] package = request.POST['pkg'] if re.findall(r';|\$\(|\|\||&&', package): return print_n_send_error_response(request, 'Possible RCE Attack', True) if re.match('^[0-9a-f]{32}$', md5_hash): # Stop ScreenCast Client if it is running TCP_SERVER_MODE = 'off' apk_dir = os.path.join(settings.UPLD_DIR, md5_hash + '/') adb = get_adb() # Change to check output of subprocess when analysis is done # Can't RCE cmd = ('{} -s {} logcat -d dalvikvm:' 'W ActivityManager:I > "{}logact.txt"').format( adb, get_identifier(), apk_dir) os.system(cmd) logger.info('Downloading Logcat logs') xposed_out = ('/data/data/' 'de.robv.android.xposed.installer' '/log/error.log') adb_command(['pull', xposed_out, apk_dir + 'x_logcat.txt']) logger.info('Downloading Droidmon API Monitor Logcat logs') # Can't RCE cmd = '{} -s {} shell dumpsys > "{}dump.txt"'.format( adb, get_identifier(), apk_dir) os.system(cmd) logger.info('Downloading Dumpsys logs') adb_command(['am', 'force-stop', package], True) logger.info('Stopping Application') adb_command(['am', 'force-stop', 'opensecurity.screencast'], True) logger.info('Stopping ScreenCast Service') data = {'final': 'yes'} return HttpResponse(json.dumps(data), content_type='application/json') else: return print_n_send_error_response(request, 'Invalid Scan Hash', True) else: return print_n_send_error_response(request, 'Only POST allowed', True) except Exception: err = 'Data Collection & Clean Up failed' logger.exception(err) return print_n_send_error_response(request, err, True)
def connect_n_mount(self): """Test ADB Connection.""" self.adb_command(['kill-server']) self.adb_command(['start-server']) logger.info('ADB Restarted') self.wait(2) logger.info('Connecting to Android %s', self.identifier) if not self.run_subprocess_verify_output([get_adb(), 'connect', self.identifier]): return False logger.info('Restarting ADB Daemon as root') if not self.run_subprocess_verify_output([get_adb(), 'root']): return False logger.info('Reconnecting to Android Device') # connect again with root adb if not self.run_subprocess_verify_output([get_adb(), 'connect', self.identifier]): return False # identify environment runtime = self.get_environment() if runtime == 'emulator': logger.info('Found Android Studio Emulator') # mount system logger.info('Remounting') self.adb_command(['remount']) elif runtime == 'genymotion': logger.info('Found Genymotion x86 VM') # mount system logger.info('Remounting /system') self.adb_command(['mount', '-o', 'rw,remount', '/system'], True) else: logger.error('Only Genymotion VM/Android Studio Emulator' ' is supported') return False logger.info('Performing System check') if not self.system_check(runtime): return False return True
def adb_command(self, cmd_list, shell=False, silent=False): """ADB Command wrapper.""" args = [get_adb(), '-s', self.identifier] if shell: args += ['shell'] args += cmd_list try: result = subprocess.check_output(args, stderr=subprocess.STDOUT) return result except Exception: if not silent: logger.exception('Error Running ADB Command') return None
def connect_n_mount(self): """Test ADB Connection.""" self.adb_command(['kill-server']) self.adb_command(['start-server']) logger.info('ADB Restarted') self.wait(2) logger.info('Connecting to Android %s', self.identifier) out = subprocess.check_output([get_adb(), 'connect', self.identifier]) if b'unable to connect' in out or b'failed to connect' in out: logger.error('%s', out.decode('utf-8').replace('\n', '')) return False else: logger.info('Remounting /system') self.adb_command(['mount', '-o', 'rw,remount', '/system'], True) return True
def adb_command(cmd_list, shell=False, silent=False): emulator = get_identifier() adb = get_adb() args = [adb, '-s', emulator] if shell: args += ['shell'] args += cmd_list try: result = subprocess.check_output(args) return result except Exception: if not silent: logger.exception('Running ADB Command') return None
def is_mobsfyied(self, android_version): """Check is Device is MobSFyed.""" logger.info('Environment MobSFyed Check') if android_version < 5: agent_file = '.mobsf-x' agent_str = self.xposed_str else: agent_file = '.mobsf-f' agent_str = self.frida_str try: out = subprocess.check_output([ get_adb(), '-s', self.identifier, 'shell', 'cat', '/system/' + agent_file ]) if agent_str not in out: return False except Exception: return False return True
def execute_adb(request): """Execute ADB Commands.""" data = {'status': 'ok', 'message': ''} cmd = request.POST['cmd'] if cmd: args = [get_adb(), '-s', get_device()] try: proc = subprocess.Popen(args + cmd.split(' '), stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = proc.communicate() except Exception: logger.exception('Executing ADB Commands') if stdout or stderr: out = stdout or stderr out = out.decode('utf8', 'ignore') else: out = '' data = {'status': 'ok', 'message': out} return json_response(data)
def enable_adb_reverse_tcp(self, version): """Enable ADB Reverse TCP for Proxy.""" # Androd 5+ supported if not version >= 5: return proxy_port = settings.PROXY_PORT logger.info('Enabling ADB Reverse TCP on %s', proxy_port) tcp = 'tcp:{}'.format(proxy_port) try: proc = subprocess.Popen( [get_adb(), '-s', self.identifier, 'reverse', tcp, tcp], stdout=subprocess.PIPE, stderr=subprocess.PIPE) _, stderr = proc.communicate() if b'error: closed' in stderr: logger.warning('ADB Reverse TCP works only on' ' Android 5.0 and above. Please ' 'configure a reachable IP Address' ' in Android proxy settings.') elif stderr: logger.error(stderr.decode('utf-8').replace('\n', '')) except Exception: logger.exception('Enabling ADB Reverse TCP')
def get_res(): """Get Screen Resolution or Device or VM.""" logger.info('Getting Screen Resolution') try: adb = get_adb() resp = subprocess.check_output( [adb, '-s', get_identifier(), 'shell', 'dumpsys', 'window']) resp = resp.decode('utf-8').split('\n') res = '' for line in resp: if 'mUnrestrictedScreen' in line: res = line break res = res.split('(0,0)')[1] res = res.strip() res = res.split('x') if len(res) == 2: return res[0], res[1] # width, height return '', '' except Exception: logger.exception('Getting Screen Resolution') return '', ''