mirror of
https://github.com/MobSF/Mobile-Security-Framework-MobSF.git
synced 2026-10-12 02:06:59 +00:00
260 lines
7.2 KiB
Python
260 lines
7.2 KiB
Python
# -*- coding: utf_8 -*-
|
|
"""Dynamic Analyzer Operations."""
|
|
import json
|
|
import logging
|
|
import os
|
|
import random
|
|
import re
|
|
import subprocess
|
|
import threading
|
|
|
|
from django.conf import settings
|
|
from django.http import HttpResponse
|
|
from django.views.decorators.http import require_http_methods
|
|
|
|
from mobsf.DynamicAnalyzer.views.android.environment import (
|
|
Environment,
|
|
)
|
|
from mobsf.MobSF.utils import (
|
|
get_adb,
|
|
get_device,
|
|
is_md5,
|
|
is_number,
|
|
)
|
|
from mobsf.StaticAnalyzer.models import StaticAnalyzerAndroid
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
# Helpers
|
|
|
|
def get_package_name(checksum):
|
|
"""Get Package NAme from DB."""
|
|
try:
|
|
static_android_db = StaticAnalyzerAndroid.objects.get(
|
|
MD5=checksum)
|
|
return static_android_db.PACKAGE_NAME
|
|
except Exception:
|
|
return None
|
|
|
|
|
|
def send_response(data, api=False):
|
|
"""Return JSON Response."""
|
|
if api:
|
|
return data
|
|
return HttpResponse(json.dumps(data),
|
|
content_type='application/json')
|
|
|
|
|
|
def is_attack_pattern(user_input):
|
|
"""Check for attacks."""
|
|
atk_pattern = re.compile(r';|\$\(|\|\||&&')
|
|
stat = re.findall(atk_pattern, user_input)
|
|
if stat:
|
|
logger.error('Possible RCE attack detected')
|
|
return stat
|
|
|
|
|
|
def strict_package_check(user_input):
|
|
"""Strict package name check."""
|
|
pat = re.compile(r'^\w+\.*[\w\.\$]+$')
|
|
resp = re.match(pat, user_input)
|
|
if not resp:
|
|
logger.error('Invalid package/class name')
|
|
return resp
|
|
|
|
|
|
def is_path_traversal(user_input):
|
|
"""Check for path traversal."""
|
|
if (('../' in user_input)
|
|
or ('%2e%2e' in user_input)
|
|
or ('..' in user_input)
|
|
or ('%252e' in user_input)):
|
|
logger.error('Path traversal attack detected')
|
|
return True
|
|
return False
|
|
|
|
|
|
def invalid_params(api=False):
|
|
"""Standard response for invalid params."""
|
|
msg = 'Invalid Parameters'
|
|
logger.error(msg)
|
|
data = {'status': 'failed', 'message': msg}
|
|
if api:
|
|
return data
|
|
return send_response(data)
|
|
|
|
# AJAX
|
|
|
|
|
|
@require_http_methods(['POST'])
|
|
def mobsfy(request, api=False):
|
|
"""Configure Instance for Dynamic Analysis."""
|
|
logger.info('MobSFying Android instance')
|
|
data = {}
|
|
try:
|
|
identifier = request.POST['identifier']
|
|
create_env = Environment(identifier)
|
|
if not create_env.connect_n_mount():
|
|
msg = 'Connection failed'
|
|
data = {'status': 'failed', 'message': msg}
|
|
return send_response(data, api)
|
|
version = create_env.mobsfy_init()
|
|
if not version:
|
|
msg = 'Connection failed'
|
|
data = {'status': 'failed', 'message': msg}
|
|
return send_response(data, api)
|
|
else:
|
|
data = {'status': 'ok', 'android_version': version}
|
|
except Exception as exp:
|
|
logger.exception('MobSFying Android instance failed')
|
|
data = {'status': 'failed', 'message': str(exp)}
|
|
return send_response(data, api)
|
|
|
|
# AJAX
|
|
|
|
|
|
@require_http_methods(['POST'])
|
|
def execute_adb(request, api=False):
|
|
"""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 send_response(data, api)
|
|
|
|
# AJAX
|
|
|
|
|
|
@require_http_methods(['POST'])
|
|
def get_component(request):
|
|
"""Get Android Component."""
|
|
data = {}
|
|
try:
|
|
env = Environment()
|
|
comp = request.POST['component']
|
|
bin_hash = request.POST['hash']
|
|
if is_attack_pattern(comp) or not is_md5(bin_hash):
|
|
return invalid_params()
|
|
comp = env.android_component(bin_hash, comp)
|
|
data = {'status': 'ok', 'message': comp}
|
|
except Exception as exp:
|
|
logger.exception('Getting Android Component')
|
|
data = {'status': 'failed', 'message': str(exp)}
|
|
return send_response(data)
|
|
|
|
# AJAX
|
|
|
|
|
|
@require_http_methods(['POST'])
|
|
def take_screenshot(request, api=False):
|
|
"""Take Screenshot."""
|
|
logger.info('Taking screenshot')
|
|
data = {}
|
|
try:
|
|
env = Environment()
|
|
bin_hash = request.POST['hash']
|
|
if not is_md5(bin_hash):
|
|
return invalid_params(api)
|
|
data = {}
|
|
rand_int = random.randint(1, 1000000)
|
|
screen_dir = os.path.join(settings.UPLD_DIR,
|
|
bin_hash + '/screenshots-apk/')
|
|
if not os.path.exists(screen_dir):
|
|
os.makedirs(screen_dir)
|
|
outile = '{}screenshot-{}.png'.format(
|
|
screen_dir,
|
|
str(rand_int))
|
|
env.screen_shot(outile)
|
|
logger.info('Screenshot captured')
|
|
data = {'status': 'ok'}
|
|
except Exception as exp:
|
|
logger.exception('Taking screenshot')
|
|
data = {'status': 'failed', 'message': str(exp)}
|
|
return send_response(data, api)
|
|
# AJAX
|
|
|
|
|
|
@require_http_methods(['POST'])
|
|
def screen_cast(request):
|
|
"""ScreenCast."""
|
|
data = {}
|
|
try:
|
|
env = Environment()
|
|
trd = threading.Thread(target=env.screen_stream)
|
|
trd.daemon = True
|
|
trd.start()
|
|
data = {'status': 'ok'}
|
|
except Exception as exp:
|
|
logger.exception('Screen streaming')
|
|
data = {'status': 'failed', 'message': str(exp)}
|
|
return send_response(data)
|
|
|
|
# AJAX
|
|
|
|
|
|
@require_http_methods(['POST'])
|
|
def touch(request):
|
|
"""Sending Touch Events."""
|
|
data = {}
|
|
try:
|
|
env = Environment()
|
|
x_axis = request.POST['x']
|
|
y_axis = request.POST['y']
|
|
if not is_number(x_axis) and not is_number(y_axis):
|
|
logger.error('Axis parameters must be numbers')
|
|
return invalid_params()
|
|
args = ['input',
|
|
'tap',
|
|
x_axis,
|
|
y_axis]
|
|
trd = threading.Thread(target=env.adb_command,
|
|
args=(args, True))
|
|
trd.daemon = True
|
|
trd.start()
|
|
data = {'status': 'ok'}
|
|
except Exception as exp:
|
|
logger.exception('Sending Touch Events')
|
|
data = {'status': 'failed', 'message': str(exp)}
|
|
return send_response(data)
|
|
|
|
|
|
# AJAX
|
|
|
|
|
|
@require_http_methods(['POST'])
|
|
def mobsf_ca(request, api=False):
|
|
"""Install and Remove MobSF Proxy RootCA."""
|
|
data = {}
|
|
try:
|
|
env = Environment()
|
|
action = request.POST['action']
|
|
if action == 'install':
|
|
env.install_mobsf_ca(action)
|
|
data = {'status': 'ok', 'message': 'installed'}
|
|
elif action == 'remove':
|
|
env.install_mobsf_ca(action)
|
|
data = {'status': 'ok', 'message': 'removed'}
|
|
else:
|
|
data = {'status': 'failed',
|
|
'message': 'Action not supported'}
|
|
except Exception as exp:
|
|
logger.exception('MobSF RootCA Handler')
|
|
data = {'status': 'failed', 'message': str(exp)}
|
|
return send_response(data, api)
|