From 743f4e557fc739df7d63e43bf117bfa03a1b1726 Mon Sep 17 00:00:00 2001 From: "Ajin.Abraham" Date: Fri, 24 Nov 2023 23:55:40 -0800 Subject: [PATCH] Remove app, recent scans report, frida err handling --- .../views/ios/corellium_instance.py | 28 +++++++++ mobsf/DynamicAnalyzer/views/ios/frida_core.py | 11 ++++ mobsf/MobSF/urls.py | 3 + mobsf/MobSF/utils.py | 4 +- mobsf/MobSF/views/home.py | 11 +++- .../ios/dynamic_analysis.html | 63 ++++++++++++++++++- .../dynamic_analysis/ios/dynamic_report.html | 50 +++++++-------- mobsf/templates/general/recent.html | 2 + 8 files changed, 140 insertions(+), 32 deletions(-) diff --git a/mobsf/DynamicAnalyzer/views/ios/corellium_instance.py b/mobsf/DynamicAnalyzer/views/ios/corellium_instance.py index f350250eee..e6bb3003e3 100644 --- a/mobsf/DynamicAnalyzer/views/ios/corellium_instance.py +++ b/mobsf/DynamicAnalyzer/views/ios/corellium_instance.py @@ -401,6 +401,34 @@ def run_app(request, api=False): # AJAX +@require_http_methods(['POST']) +def remove_app(request, api=False): + """Remove an app from the device.""" + data = { + 'status': 'failed', + 'message': 'Failed to uninstall the app'} + try: + instance_id = request.POST['instance_id'] + bundle_id = request.POST['bundle_id'] + failed = common_check(instance_id) + if failed: + return send_response(failed, api) + apikey = getattr(settings, 'CORELLIUM_API_KEY', '') + if not strict_package_check(bundle_id): + data['message'] = 'Invalid iOS Bundle id' + return send_response(data, api) + ca = CorelliumAgentAPI(apikey, instance_id) + if (ca.agent_ready() + and ca.remove_app(bundle_id) == OK): + data['status'] = OK + data['message'] = 'App uninstalled' + except Exception as exp: + logger.exception('Failed to uninstall the app') + data['message'] = str(exp) + return send_response(data, api) +# AJAX + + @require_http_methods(['POST']) def take_screenshot(request, api=False): """Take a Screenshot.""" diff --git a/mobsf/DynamicAnalyzer/views/ios/frida_core.py b/mobsf/DynamicAnalyzer/views/ios/frida_core.py index 5ebb641ff2..808167099c 100644 --- a/mobsf/DynamicAnalyzer/views/ios/frida_core.py +++ b/mobsf/DynamicAnalyzer/views/ios/frida_core.py @@ -167,6 +167,9 @@ def spawn(self): try: _DEVICE = frida.get_remote_device() _PID = _DEVICE.spawn([self.bundle_id]) + except frida.NotSupportedError: + logger.exception('Not Supported Error') + return except frida.ServerNotRunningError: self.frida_ssh_forward() if not _PID: @@ -175,6 +178,9 @@ def spawn(self): time.sleep(2) except frida.TimedOutError: logger.error('Timed out while waiting for device to appear') + except frida.NotSupportedError: + logger.exception('Not Supported Error') + return except (frida.ProcessNotFoundError, frida.TransportError, frida.InvalidOperationError): @@ -203,6 +209,9 @@ def session(self, pid, bundle_id): _PID = _DEVICE.spawn([self.bundle_id]) # pid is the forntmost app session = _DEVICE.attach(_PID) + except frida.NotSupportedError: + logger.exception('Not Supported Error') + return except Exception: logger.warning('Cannot attach to pid, spawning again') self.spawn() @@ -218,6 +227,8 @@ def session(self, pid, bundle_id): sys.stdin.read() script.unload() session.detach() + except frida.NotSupportedError: + logger.exception('Not Supported Error') except (frida.ProcessNotFoundError, frida.TransportError, frida.InvalidOperationError): diff --git a/mobsf/MobSF/urls.py b/mobsf/MobSF/urls.py index c39a68d86e..862e176590 100755 --- a/mobsf/MobSF/urls.py +++ b/mobsf/MobSF/urls.py @@ -235,6 +235,9 @@ re_path(r'^ios/run_app/$', instance.run_app, name='run_app'), + re_path(r'^ios/remove_app/$', + instance.remove_app, + name='remove_app'), re_path(r'^ios/take_screenshot/$', instance.take_screenshot, name='take_screenshot'), diff --git a/mobsf/MobSF/utils.py b/mobsf/MobSF/utils.py index 7ed9d5b5b8..c4bc06c97e 100755 --- a/mobsf/MobSF/utils.py +++ b/mobsf/MobSF/utils.py @@ -734,12 +734,10 @@ def base64_decode(value): if is_base64(value) or value.startswith(commonb64s): decoded = base64.b64decode( value).decode('ISO-8859-1') - if set(decoded).difference(string.printable): - decoded = None except Exception: pass if decoded: - return f'{value}\nBase64 Decoded: {decoded}' + return f'{value}\n\nBase64 Decoded: {decoded}' return value diff --git a/mobsf/MobSF/views/home.py b/mobsf/MobSF/views/home.py index 4aa85e517f..6f071416db 100755 --- a/mobsf/MobSF/views/home.py +++ b/mobsf/MobSF/views/home.py @@ -22,6 +22,7 @@ from mobsf.MobSF.forms import FormUtil, UploadFileForm from mobsf.MobSF.utils import ( api_key, + get_md5, is_dir_exists, is_file_exists, is_safe_path, @@ -236,6 +237,7 @@ def recent_scans(request): db_obj = RecentScansDB.objects.all().order_by('-TIMESTAMP').values() android = StaticAnalyzerAndroid.objects.all() ios = StaticAnalyzerIOS.objects.all() + updir = Path(settings.UPLD_DIR) icon_mapping = {} package_mapping = {} for item in android: @@ -249,8 +251,13 @@ def recent_scans(request): else: entry['PACKAGE'] = '' entry['ICON_PATH'] = icon_mapping.get(entry['MD5'], '') - logcat = Path(settings.UPLD_DIR) / entry['MD5'] / 'logcat.txt' - entry['DYNAMIC_REPORT_EXISTS'] = logcat.exists() + if entry['FILE_NAME'].endswith('.ipa'): + entry['BUNDLE_HASH'] = get_md5( + entry['PACKAGE_NAME'].encode('utf-8')) + report_file = updir / entry['BUNDLE_HASH'] / 'mobsf_dump_file.txt' + else: + report_file = updir / entry['MD5'] / 'logcat.txt' + entry['DYNAMIC_REPORT_EXISTS'] = report_file.exists() entries.append(entry) context = { 'title': 'Recent Scans', diff --git a/mobsf/templates/dynamic_analysis/ios/dynamic_analysis.html b/mobsf/templates/dynamic_analysis/ios/dynamic_analysis.html index 28ba8ac152..0aa515fd3e 100644 --- a/mobsf/templates/dynamic_analysis/ios/dynamic_analysis.html +++ b/mobsf/templates/dynamic_analysis/ios/dynamic_analysis.html @@ -398,8 +398,13 @@ var url = `{% url 'dynamic_analyzer_ios'%}?bundleid=${escapeHtml(bundle)}&instance_id=${$('#ios_dynamic').val()}`; $('#in_device > tbody:' + order + '-child').append( - `
${escapeHtml(name)}${escapeHtml(bundle)}${escapeHtml(type)}

Start Dynamic Analysis View Report

`); - + ` +
+ ${escapeHtml(name)}${escapeHtml(bundle)} + ${escapeHtml(type)} +

Start Dynamic Analysis + View Report + Uninstall

`); } } else { @@ -415,6 +420,60 @@ } }); } + +// Remove app from device +function remove_app(item, bundle_id){ + Swal.fire({ + title: 'Are you sure?', + text: "This will remove the app from the device", + type: 'warning', + showCancelButton: true, + confirmButtonText: 'Yes', + cancelButtonText: 'No', + confirmButtonColor: '#d33', + cancelButtonColor: '#2da532', + }).then((result) => { + if (result.value) { + + $.ajax({ + url: '{% url 'remove_app' %}', + type : 'POST', + dataType: 'json', + data : { + csrfmiddlewaretoken: '{{ csrf_token }}', + instance_id: item.id, + bundle_id: bundle_id, + }, + success : function(json) { + if (json.status==='ok'){ + Swal.fire( + 'Uninstalled!', + 'Application is uninstalled', + 'success' + ).then(function () { + location.reload(); + }) + } + else { + Swal.fire( + 'Uninstall Failed', + 'Failed to uninstall the app: ' + json.message, + 'error' + ) + } + }, + error : function(xhr,errmsg,err) { + Swal.fire( + 'Uninstall Errored', + errmsg, + 'error' + ) + } + }); + } + }); +} + //Start VM function start_vm(item){ Swal.fire({ diff --git a/mobsf/templates/dynamic_analysis/ios/dynamic_report.html b/mobsf/templates/dynamic_analysis/ios/dynamic_report.html index 1b89c83281..ce5f8ec7e8 100644 --- a/mobsf/templates/dynamic_analysis/ios/dynamic_report.html +++ b/mobsf/templates/dynamic_analysis/ios/dynamic_report.html @@ -66,7 +66,7 @@