diff --git a/mobsf/DynamicAnalyzer/views/ios/corellium_instance.py b/mobsf/DynamicAnalyzer/views/ios/corellium_instance.py index ce7b997598..254f87fe5a 100644 --- a/mobsf/DynamicAnalyzer/views/ios/corellium_instance.py +++ b/mobsf/DynamicAnalyzer/views/ios/corellium_instance.py @@ -11,8 +11,12 @@ from django.conf import settings from django.views.decorators.http import require_http_methods -from django.http import HttpResponse -from django.shortcuts import render +from django.http import ( + HttpResponse, +) +from django.shortcuts import ( + render, +) from mobsf.MobSF.utils import ( common_check, @@ -34,6 +38,7 @@ ) from mobsf.DynamicAnalyzer.views.ios.corellium_ssh import ( ssh_execute_cmd, + ssh_file_download, ssh_file_upload, ssh_jump_host, ) @@ -776,7 +781,7 @@ def system_logs(request, api=False): @require_http_methods(['POST']) def upload_file(request, api=False): - """Upload files to device.""" + """Upload file to device.""" err_msg = 'Failed to upload file' data = { 'status': 'failed', @@ -800,3 +805,35 @@ def upload_file(request, api=False): logger.exception(err_msg) data['message'] = str(exp) return send_response(data) +# File Download + + +@require_http_methods(['POST']) +def download_file(request, api=False): + """Download file from device.""" + try: + global SSH_TARGET + instance_id = request.POST['instance_id'] + rfile = request.POST['file'] + failed = common_check(instance_id) + if failed: + return send_response(failed, api) + ci = CorelliumInstanceAPI(instance_id) + if not SSH_TARGET: + logger.info('Setting up SSH tunnel') + SSH_TARGET, _jmp = ssh_jump_host( + ci.get_ssh_connection_string()) + try: + fl = ssh_file_download(SSH_TARGET, rfile) + except SSHException: + logger.info('SSH session not active, setting up again') + SSH_TARGET, _jmp = ssh_jump_host( + ci.get_ssh_connection_string()) + fl = ssh_file_download(SSH_TARGET, rfile) + if not fl: + fl = b'File not found' + except Exception: + logger.exception('Failed to download file') + response = HttpResponse(fl, content_type='application/octet-stream') + response['Content-Disposition'] = f'inline; filename={Path(rfile).name}' + return response diff --git a/mobsf/DynamicAnalyzer/views/ios/corellium_ssh.py b/mobsf/DynamicAnalyzer/views/ios/corellium_ssh.py index daeea71927..b768fe37ed 100644 --- a/mobsf/DynamicAnalyzer/views/ios/corellium_ssh.py +++ b/mobsf/DynamicAnalyzer/views/ios/corellium_ssh.py @@ -27,7 +27,7 @@ # along with Paramiko; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # Modified for MobSF. - +import io import logging import select import socket @@ -282,10 +282,13 @@ def ssh_file_upload(ssh_conn_string, fobject, fname): jumpbox.close() -def ssh_file_download(ssh_conn_string, remote_path, local_path): +def ssh_file_download(target, remote_path): """File Download over SFTP.""" - target, jumpbox = ssh_jump_host(ssh_conn_string) - with target.open_sftp() as sftp: - sftp.get(remote_path, local_path) - target.close() - jumpbox.close() + try: + with io.BytesIO() as fl: + with target.open_sftp() as sftp: + sftp.getfo(remote_path, fl) + fl.seek(0) + return fl.read() + except Exception: + return None diff --git a/mobsf/MobSF/urls.py b/mobsf/MobSF/urls.py index ba75b441f3..077823b35e 100755 --- a/mobsf/MobSF/urls.py +++ b/mobsf/MobSF/urls.py @@ -263,6 +263,9 @@ re_path(r'^ios/upload_file/$', instance.upload_file, name='upload_file'), + re_path(r'^ios/download_file/$', + instance.download_file, + name='download_file'), re_path(r'^ios/touch/$', instance.touch, name='ios_touch'), diff --git a/mobsf/MobSF/views/api/api_dynamic_analysis.py b/mobsf/MobSF/views/api/api_dynamic_analysis.py index 8682fd0044..5d0c3ca29e 100644 --- a/mobsf/MobSF/views/api/api_dynamic_analysis.py +++ b/mobsf/MobSF/views/api/api_dynamic_analysis.py @@ -23,7 +23,7 @@ @csrf_exempt def api_get_apps(request): """GET - Get Apps for dynamic analysis API.""" - resp = dynamic_analyzer.dynamic_analysis(request, True) + resp = dynamic_analyzer.android_dynamic_analysis(request, True) if 'error' in resp: return make_api_response(resp, 500) return make_api_response(resp, 200) diff --git a/mobsf/templates/dynamic_analysis/ios/dynamic_report.html b/mobsf/templates/dynamic_analysis/ios/dynamic_report.html index d9c58b728a..718a1411bf 100644 --- a/mobsf/templates/dynamic_analysis/ios/dynamic_report.html +++ b/mobsf/templates/dynamic_analysis/ios/dynamic_report.html @@ -450,6 +450,7 @@
FILE PATH + DOWNLOAD @@ -458,6 +459,9 @@
{{item}} + + + {% endfor %} @@ -490,6 +494,7 @@
FILE PATH + DOWNLOAD FILE PROTECTION @@ -499,6 +504,9 @@
{{ item.path | replace:"/private/var/mobile/Containers/Data/Application/|" }} + + + {{ item.fileProtectionKey }} @@ -1432,5 +1440,39 @@

$('#cat').modal('toggle'); }); } + + // Download file + function download_file(path){ + // action('{% url 'download_file' %}', {instance_id: '{{ instance_id }}', file: path }, function(json) { + // alert(json); + // }); + + var form = document.createElement("form"); + var element1 = document.createElement("input"); + var element2 = document.createElement("input"); + var element3 = document.createElement("input"); + + form.method = "POST"; + form.action = "{% url 'download_file' %}"; + + element1.value= "{{ instance_id }}"; + element1.name="instance_id"; + form.appendChild(element1); + + + element2.value=path; + element2.name="file"; + form.appendChild(element2); + + element3.value= "{{ csrf_token }}"; + element3.name="csrf_token"; + form.appendChild(element3); + + document.body.appendChild(form); + + form.submit(); + form.remove(); + + } {% endblock %} \ No newline at end of file