diff --git a/Dockerfile b/Dockerfile index 3ac52f889b..8e742fcfea 100644 --- a/Dockerfile +++ b/Dockerfile @@ -32,6 +32,7 @@ RUN apt update -y && apt install -y --no-install-recommends \ curl \ git \ jq \ + unzip \ android-tools-adb && \ locale-gen en_US.UTF-8 && \ apt upgrade -y diff --git a/mobsf/DynamicAnalyzer/views/ios/corellium_apis.py b/mobsf/DynamicAnalyzer/views/ios/corellium_apis.py index bd9ab30bba..073f443c53 100644 --- a/mobsf/DynamicAnalyzer/views/ios/corellium_apis.py +++ b/mobsf/DynamicAnalyzer/views/ios/corellium_apis.py @@ -2,10 +2,10 @@ """Corellium APIs.""" import logging from copy import deepcopy +from socket import gethostname import requests - SUCCESS_RESP = (200, 204) ERROR_RESP = (400, 403, 404, 409) OK = 'ok' @@ -60,6 +60,31 @@ def get_projects(self): return True return False + def get_authorized_keys(self): + """Get SSH public keys associated with a project.""" + r = requests.get( + f'{self.api}/projects/{self.project_id}/keys', + headers=self.headers) + if r.status_code in SUCCESS_RESP: + return r.json() + return False + + def add_authorized_key(self, key): + """Add SSH public key to the Project.""" + logger.info('Adding SSH public key to Corellium project') + data = { + 'kind': 'ssh', + 'label': f'MobSF SSH Key - {gethostname()}', + 'key': key, + } + r = requests.post( + f'{self.api}/projects/{self.project_id}/keys', + headers=self.headers, + json=data) + if r.status_code in SUCCESS_RESP: + return r.json()['identifier'] + return False + def get_instances(self): """Get Instances.""" logger.info('Getting iOS instances') diff --git a/mobsf/DynamicAnalyzer/views/ios/corellium_instance.py b/mobsf/DynamicAnalyzer/views/ios/corellium_instance.py index d497b19152..6a9c793807 100644 --- a/mobsf/DynamicAnalyzer/views/ios/corellium_instance.py +++ b/mobsf/DynamicAnalyzer/views/ios/corellium_instance.py @@ -29,7 +29,7 @@ invalid_params, send_response, ) -from mobsf.DynamicAnalyzer.views.ios.corellium_frida_ssh import ( +from mobsf.DynamicAnalyzer.views.ios.corellium_ssh import ( ssh_execute_cmd, ssh_file_upload, ssh_jump_host, diff --git a/mobsf/DynamicAnalyzer/views/ios/corellium_frida_ssh.py b/mobsf/DynamicAnalyzer/views/ios/corellium_ssh.py similarity index 79% rename from mobsf/DynamicAnalyzer/views/ios/corellium_frida_ssh.py rename to mobsf/DynamicAnalyzer/views/ios/corellium_ssh.py index 1fbcd8e80e..d4c1467fb9 100644 --- a/mobsf/DynamicAnalyzer/views/ios/corellium_frida_ssh.py +++ b/mobsf/DynamicAnalyzer/views/ios/corellium_ssh.py @@ -29,10 +29,42 @@ import paramiko +from django.conf import settings + +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey + logger = logging.getLogger(__name__) +def generate_keypair_if_not_exists(location): + """Generate RSA key pair.""" + prv = location / 'ssh_key.private' + pub = location / 'ssh_key.public' + if prv.exists() and pub.exists(): + # Keys Exists + return prv.read_bytes(), pub.read_bytes() + logger.info('Generating RSA key pair for Corellium SSH') + + # Generate private/public key pair + private_key = Ed25519PrivateKey.generate() + public_key = private_key.public_key() + + # OpenSSH friendly + private_bytes = private_key.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.OpenSSH, + encryption_algorithm=serialization.NoEncryption()) + + public_bytes = public_key.public_bytes( + encoding=serialization.Encoding.OpenSSH, + format=serialization.PublicFormat.OpenSSH) + prv.write_bytes(private_bytes) + pub.write_bytes(public_bytes) + return private_bytes, public_bytes + + def parse_ssh_string(ssh): """Parse SSH connection string.""" ssh_dict = {} @@ -124,9 +156,15 @@ def ssh_jump_host(ssh_string): user = ssh_dict['private_user'] private_ip = ssh_dict['private_ip'] + home = Path(settings.UPLD_DIR).parent + generate_keypair_if_not_exists(home) + keyf = home / 'ssh_key.private' jumpbox = paramiko.SSHClient() jumpbox.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - jumpbox.connect(bastion_host, username=bastion_user) + jumpbox.connect( + bastion_host, + username=bastion_user, + key_filename=keyf.as_posix()) jumpbox_transport = jumpbox.get_transport() src_addr = (private_ip, 22) @@ -136,7 +174,11 @@ def ssh_jump_host(ssh_string): target = paramiko.SSHClient() target.set_missing_host_key_policy(paramiko.AutoAddPolicy()) - target.connect(private_ip, username=user, sock=jumpbox_channel) + target.connect( + private_ip, + username=user, + sock=jumpbox_channel, + password='alpine') return target, jumpbox diff --git a/mobsf/DynamicAnalyzer/views/ios/dynamic_analyzer.py b/mobsf/DynamicAnalyzer/views/ios/dynamic_analyzer.py index b8c6dc7d65..9d4ec20bf3 100644 --- a/mobsf/DynamicAnalyzer/views/ios/dynamic_analyzer.py +++ b/mobsf/DynamicAnalyzer/views/ios/dynamic_analyzer.py @@ -15,6 +15,9 @@ ) from mobsf.StaticAnalyzer.models import StaticAnalyzerIOS from mobsf.DynamicAnalyzer.forms import UploadFileForm +from mobsf.DynamicAnalyzer.views.ios.corellium_ssh import ( + generate_keypair_if_not_exists, +) from mobsf.DynamicAnalyzer.views.ios.corellium_apis import ( CorelliumAPI, ) @@ -57,6 +60,7 @@ def dynamic_analysis(request, api=False): if c.api_ready() and c.api_auth() and c.get_projects(): instances = c.get_instances() project_id = c.project_id + setup_ssh_keys(c) context = {'apps': scan_apps, 'dynamic_analyzer': ios_dynamic, 'project_id': project_id, @@ -110,3 +114,35 @@ def dynamic_analyzer(request, api=False): request, 'iOS Dynamic Analysis Failed.', api) + + +def setup_ssh_keys(c): + # Get Authorized keys for the project + pkeys = c.get_authorized_keys() + location = Path(settings.UPLD_DIR).parent + _prv, pub = generate_keypair_if_not_exists(location) + add_keys = False + if not pkeys: + # No SSH Keys associated with the project + # let's add one + add_keys = True + else: + # SSH Keys are already associated with the project + # Check if our key is associated + pub_key_exists = False + for pkey in pkeys: + if pkey['project'] == c.project_id: + ckey = get_md5(pkey['key'].encode('utf-8')) + lkey = get_md5(pub) + if ckey == lkey: + pub_key_exists = True + break + # Out key is not asscoiated with the project, let's add it + if not pub_key_exists: + add_keys = True + if add_keys: + iden = c.add_authorized_key(pub) + if not iden: + logger.error('Failed to add SSH Key to Corellium project') + return + logger.info('Added SSH Key to Corellium project') diff --git a/mobsf/DynamicAnalyzer/views/ios/frida_core.py b/mobsf/DynamicAnalyzer/views/ios/frida_core.py index 8875ffcb1b..d703729aed 100644 --- a/mobsf/DynamicAnalyzer/views/ios/frida_core.py +++ b/mobsf/DynamicAnalyzer/views/ios/frida_core.py @@ -18,7 +18,7 @@ string_capture, string_compare, ) -from mobsf.DynamicAnalyzer.views.ios.corellium_frida_ssh import ( +from mobsf.DynamicAnalyzer.views.ios.corellium_ssh import ( ssh_jumphost_port_forward, )