mirror of
https://github.com/MobSF/Mobile-Security-Framework-MobSF.git
synced 2026-10-12 02:06:59 +00:00
AVD test locally (#389)
This PR add support for using AVD with MobSF by @matandobr Code QA and Refactoring of Android Dynamic Analysis Added functionality to remove scan results
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,192 @@
|
||||
"""
|
||||
Android Dynamic Analyzer for Android AVD (ARM) VM
|
||||
"""
|
||||
import os
|
||||
import io
|
||||
import time
|
||||
import platform
|
||||
import shutil
|
||||
import subprocess
|
||||
|
||||
from DynamicAnalyzer.views.android.android_dyn_shared import get_identifier
|
||||
from MobSF.utils import PrintException
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
def stop_avd(adb):
|
||||
"""Stop AVD"""
|
||||
print "\n[INFO] Stopping MobSF Emulator"
|
||||
try:
|
||||
# adb -s emulator-xxxx emu kill
|
||||
FNULL = open(os.devnull, 'w')
|
||||
args = [adb, '-s', get_identifier(), 'emu', 'kill']
|
||||
subprocess.call(args, stderr=FNULL)
|
||||
except:
|
||||
PrintException("[ERROR] Stopping MobSF Emulator")
|
||||
|
||||
|
||||
def delete_avd(avd_path, avd_name):
|
||||
"""Delete AVD"""
|
||||
print "\n[INFO] Deleting emulator files"
|
||||
try:
|
||||
config_file = os.path.join(avd_path, avd_name + '.ini')
|
||||
if os.path.exists(config_file):
|
||||
os.remove(config_file)
|
||||
'''
|
||||
# todo: Sometimes there is an error here because of the locks that avd
|
||||
# does - check this out
|
||||
'''
|
||||
avd_folder = os.path.join(avd_path, avd_name + '.avd')
|
||||
if os.path.isdir(avd_folder):
|
||||
shutil.rmtree(avd_folder)
|
||||
except:
|
||||
PrintException("[ERROR] Deleting emulator files")
|
||||
|
||||
|
||||
def duplicate_avd(avd_path, reference_name, dup_name):
|
||||
"""Duplicate AVD"""
|
||||
print "\n[INFO] Duplicating MobSF Emulator"
|
||||
try:
|
||||
reference_ini = os.path.join(avd_path, reference_name + '.ini')
|
||||
dup_ini = os.path.join(avd_path, dup_name + '.ini')
|
||||
reference_avd = os.path.join(avd_path, reference_name + '.avd')
|
||||
dup_avd = os.path.join(avd_path, dup_name + '.avd')
|
||||
|
||||
# Copy the files from the referenve avd to the one-time analysis avd
|
||||
shutil.copyfile(reference_ini, dup_ini)
|
||||
shutil.copytree(reference_avd, dup_avd)
|
||||
|
||||
# Replacing every occuration of the reference avd name to the dup one
|
||||
for path_to_update in [dup_ini,
|
||||
os.path.join(dup_avd, 'hardware-qemu.ini'),
|
||||
os.path.join(dup_avd, 'config.ini')
|
||||
]:
|
||||
with io.open(path_to_update, mode='r', encoding="utf8", errors="ignore") as fled:
|
||||
replaced_file = fled.read()
|
||||
replaced_file = replaced_file.replace(reference_name, dup_name)
|
||||
with io.open(path_to_update, 'w') as fled:
|
||||
fled.write(replaced_file)
|
||||
except:
|
||||
PrintException("[ERROR] Duplicating MobSF Emulator")
|
||||
|
||||
|
||||
def start_avd(emulator, avd_name, emulator_port):
|
||||
"""Start AVD"""
|
||||
print "\n[INFO] Starting MobSF Emulator"
|
||||
try:
|
||||
args = [
|
||||
emulator,
|
||||
'-avd',
|
||||
avd_name,
|
||||
"-no-snapshot-save",
|
||||
"-netspeed",
|
||||
"full",
|
||||
"-netdelay",
|
||||
"none",
|
||||
"-port",
|
||||
str(emulator_port),
|
||||
]
|
||||
|
||||
if platform.system() == 'Darwin':
|
||||
# There is a strage error in mac with the dyld one in a while..
|
||||
# this should fix it..
|
||||
if 'DYLD_FALLBACK_LIBRARY_PATH' in os.environ.keys():
|
||||
del os.environ['DYLD_FALLBACK_LIBRARY_PATH']
|
||||
|
||||
subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
except:
|
||||
PrintException("[ERROR] Starting MobSF Emulator")
|
||||
|
||||
|
||||
def refresh_avd(adb, avd_path, reference_name, dup_name, emulator):
|
||||
"""Refresh AVD"""
|
||||
print "\n[INFO] Refreshing MobSF Emulator"
|
||||
try:
|
||||
# Stop existing emulator on the spesified port
|
||||
stop_avd(adb)
|
||||
|
||||
# Windows has annoying lock system, it takes time for it to remove the locks after we stopped the emulator
|
||||
if platform.system() == 'Windows':
|
||||
time.sleep(3)
|
||||
|
||||
# Delete old emulator
|
||||
delete_avd(avd_path, dup_name)
|
||||
|
||||
# Copy and replace the contents of the reference machine
|
||||
duplicate_avd(avd_path, reference_name, dup_name)
|
||||
|
||||
# Start emulator
|
||||
start_avd(emulator, dup_name, settings.AVD_ADB_PORT)
|
||||
except:
|
||||
PrintException("[ERROR] Refreshing MobSF VM")
|
||||
|
||||
|
||||
def avd_load_wait(adb):
|
||||
"""Wait for AVD Load"""
|
||||
try:
|
||||
emulator = get_identifier()
|
||||
|
||||
print "[INFO] Wait for emulator to load"
|
||||
args = [adb,
|
||||
"-s",
|
||||
emulator,
|
||||
"wait-for-device"]
|
||||
subprocess.call(args)
|
||||
|
||||
print "[INFO] Wait for dev.boot_complete loop"
|
||||
while True:
|
||||
args = [adb,
|
||||
"-s",
|
||||
emulator,
|
||||
"shell",
|
||||
"getprop",
|
||||
"dev.bootcomplete"]
|
||||
try:
|
||||
result = subprocess.check_output(args)
|
||||
except:
|
||||
result = None
|
||||
if result is not None and result.strip() == "1":
|
||||
break
|
||||
else:
|
||||
time.sleep(1)
|
||||
|
||||
print "[INFO] Wait for sys.boot_complete loop"
|
||||
while True:
|
||||
args = [adb,
|
||||
"-s",
|
||||
emulator,
|
||||
"shell",
|
||||
"getprop",
|
||||
"sys.boot_completed"]
|
||||
try:
|
||||
result = subprocess.check_output(args)
|
||||
except:
|
||||
result = None
|
||||
if result is not None and result.strip() == "1":
|
||||
break
|
||||
else:
|
||||
time.sleep(1)
|
||||
|
||||
print "[INFO] Wait for svc.boot_complete loop"
|
||||
while True:
|
||||
args = [adb,
|
||||
"-s",
|
||||
emulator,
|
||||
"shell",
|
||||
"getprop",
|
||||
"init.svc.bootanim"]
|
||||
try:
|
||||
result = subprocess.check_output(args)
|
||||
except:
|
||||
result = None
|
||||
if result is not None and result.strip() == "stopped":
|
||||
break
|
||||
else:
|
||||
time.sleep(1)
|
||||
time.sleep(5)
|
||||
# Remount the partitions for RW
|
||||
subprocess.call([adb, "-s", emulator, "remount"])
|
||||
return True
|
||||
except:
|
||||
PrintException("[ERROR] emulator did not boot properly")
|
||||
return False
|
||||
@@ -0,0 +1,110 @@
|
||||
"""Shared Functions for Android Dynamic Analyzer"""
|
||||
# -*- coding: utf_8 -*-
|
||||
import subprocess
|
||||
import os
|
||||
import time
|
||||
from django.conf import settings
|
||||
from DynamicAnalyzer.pyWebProxy.pywebproxy import Proxy
|
||||
from MobSF.utils import PrintException, getADB
|
||||
|
||||
def connect(toolsdir):
|
||||
"""Connect to VM/Device"""
|
||||
print "\n[INFO] Connecting to VM/Device"
|
||||
try:
|
||||
adb = getADB(toolsdir)
|
||||
subprocess.call([adb, "kill-server"])
|
||||
subprocess.call([adb, "start-server"])
|
||||
print "\n[INFO] ADB Started"
|
||||
wait(5)
|
||||
print "\n[INFO] Connecting to VM/Device"
|
||||
subprocess.call([adb, "connect", get_identifier()])
|
||||
subprocess.call([adb, "-s", get_identifier(), "wait-for-device"])
|
||||
print "\n[INFO] Mounting"
|
||||
if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_REAL_DEVICE":
|
||||
subprocess.call([adb, "-s", get_identifier(), "shell",
|
||||
"su", "-c", "mount", "-o", "rw,remount,rw", "/system"])
|
||||
else:
|
||||
subprocess.call([adb, "-s", get_identifier(), "shell",
|
||||
"su", "-c", "mount", "-o", "rw,remount,rw", "/system"])
|
||||
# This may not work for VMs other than the default MobSF VM
|
||||
subprocess.call([adb, "-s", get_identifier(), "shell", "mount",
|
||||
"-o", "rw,remount", "-t", "rfs", "/dev/block/sda6", "/system"])
|
||||
except:
|
||||
PrintException("[ERROR] Connecting to VM/Device")
|
||||
|
||||
|
||||
def install_and_run(toolsdir, apk_path, package, launcher, is_activity):
|
||||
"""Install APK and Run it"""
|
||||
print "\n[INFO] Starting App for Dynamic Analysis"
|
||||
try:
|
||||
adb = getADB(toolsdir)
|
||||
print "\n[INFO] Installing APK"
|
||||
subprocess.call([adb, "-s", get_identifier(),
|
||||
"install", "-r", apk_path])
|
||||
if is_activity:
|
||||
run_app = package + "/" + launcher
|
||||
print "\n[INFO] Launching APK Main Activity"
|
||||
subprocess.call([adb, "-s", get_identifier(),
|
||||
"shell", "am", "start", "-n", run_app])
|
||||
else:
|
||||
print "\n[INFO] App Doesn't have a Main Activity"
|
||||
# Handle Service or Give Choice to Select in Future.
|
||||
print "[INFO] Testing Environment is Ready!"
|
||||
except:
|
||||
PrintException("[ERROR] Starting App for Dynamic Analysis")
|
||||
|
||||
|
||||
def wait(sec):
|
||||
"""Wait in Seconds"""
|
||||
print "\n[INFO] Waiting for " + str(sec) + " seconds..."
|
||||
time.sleep(sec)
|
||||
|
||||
|
||||
def web_proxy(apk_dir, ip_address, port):
|
||||
"""Run MITM Proxy"""
|
||||
print "\n[INFO] Starting Web Proxy"
|
||||
try:
|
||||
Proxy(ip_address, port, apk_dir, "on")
|
||||
except:
|
||||
PrintException("[ERROR] Starting Web Proxy")
|
||||
|
||||
|
||||
def get_res():
|
||||
"""Get Screen Resolution or Device or VM"""
|
||||
print "\n[INFO] Getting Screen Resolution"
|
||||
try:
|
||||
toolsdir = os.path.join(
|
||||
settings.BASE_DIR, 'DynamicAnalyzer/tools/') # TOOLS DIR
|
||||
adb = getADB(toolsdir)
|
||||
resp = subprocess.check_output(
|
||||
[adb, "-s", get_identifier(), "shell", "dumpsys", "window"])
|
||||
resp = resp.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:
|
||||
PrintException("[ERROR] Getting Screen Resolution")
|
||||
return "", ""
|
||||
|
||||
|
||||
def get_identifier():
|
||||
"""Get Device Type"""
|
||||
try:
|
||||
if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_REAL_DEVICE":
|
||||
return settings.DEVICE_IP + ":" + str(settings.DEVICE_ADB_PORT)
|
||||
elif settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_AVD":
|
||||
return 'emulator-' + str(settings.AVD_ADB_PORT)
|
||||
else:
|
||||
return settings.VM_IP + ":" + str(settings.VM_ADB_PORT)
|
||||
except:
|
||||
PrintException(
|
||||
"[ERROR] Getting ADB Connection Identifier for Device/VM")
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,22 @@
|
||||
import subprocess
|
||||
from MobSF.utils import PrintException
|
||||
|
||||
|
||||
def refresh_vm(uuid, snapshot_uuid, vbox_exe):
|
||||
"""Refresh VirtualBox based VMs"""
|
||||
print "\n[INFO] Refreshing MobSF VM"
|
||||
try:
|
||||
# Close VM
|
||||
args = [vbox_exe, 'controlvm', uuid, 'poweroff']
|
||||
subprocess.call(args)
|
||||
print "\n[INFO] VM Closed"
|
||||
# Restore Snapshot
|
||||
args = [vbox_exe, 'snapshot', uuid, 'restore', snapshot_uuid]
|
||||
subprocess.call(args)
|
||||
print "\n[INFO] VM Restore Snapshot"
|
||||
# Start Fresh VM
|
||||
args = [vbox_exe, 'startvm', uuid]
|
||||
subprocess.call(args)
|
||||
print "\n[INFO] VM Starting"
|
||||
except:
|
||||
PrintException("[ERROR] Refreshing MobSF VM")
|
||||
@@ -2,28 +2,34 @@
|
||||
Standalone Android Dynamic Analysis
|
||||
"""
|
||||
# -*- coding: utf_8 -*-
|
||||
import os
|
||||
import subprocess
|
||||
from django.shortcuts import render
|
||||
from django.conf import settings
|
||||
from django.http import HttpResponseRedirect, HttpResponse
|
||||
from django.utils.html import escape
|
||||
from DynamicAnalyzer.views.android import RefreshVM, getADB, getIdentifier, Connect
|
||||
from DynamicAnalyzer.pyWebProxy.pywebproxy import *
|
||||
|
||||
import subprocess
|
||||
from DynamicAnalyzer.views.android.android_virtualbox_vm import (
|
||||
refresh_vm
|
||||
)
|
||||
from DynamicAnalyzer.views.android.android_dyn_shared import (
|
||||
connect,
|
||||
get_identifier,
|
||||
)
|
||||
from DynamicAnalyzer.pyWebProxy.pywebproxy import Proxy
|
||||
from MobSF.utils import getADB
|
||||
|
||||
|
||||
def DynamicAnalyzer(request):
|
||||
def dynamic_analyzer_standalone(request):
|
||||
"""Standalone Dynamic Analysis"""
|
||||
print "\n[INFO] Starting Standalone Android Dynamic Analyzer"
|
||||
TOOLS_DIR = os.path.join(
|
||||
toolsdir = os.path.join(
|
||||
settings.BASE_DIR, 'DynamicAnalyzer/tools/') # TOOLS DIR
|
||||
Proxy("", "", "", "")
|
||||
if settings.REAL_DEVICE:
|
||||
if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_REAL_DEVICE":
|
||||
print "\n[INFO] MobSF will perform Dynamic Analysis on real Android Device"
|
||||
else:
|
||||
# Refersh VM
|
||||
RefreshVM(settings.UUID, settings.SUUID, settings.VBOX)
|
||||
Connect(TOOLS_DIR)
|
||||
print GetPackages(TOOLS_DIR)
|
||||
refresh_vm(settings.UUID, settings.SUUID, settings.VBOX)
|
||||
connect(toolsdir)
|
||||
print get_packages(toolsdir)
|
||||
context = {'md5': '',
|
||||
'pkg': '',
|
||||
'lng': '',
|
||||
@@ -32,9 +38,10 @@ def DynamicAnalyzer(request):
|
||||
return render(request, template, context)
|
||||
|
||||
|
||||
def GetPackages(TOOLSDIR):
|
||||
adb = getADB(TOOLSDIR)
|
||||
args = [adb, "-s", getIdentifier(), "shell", "ls", "/data/data"]
|
||||
def get_packages(toolsdir):
|
||||
"""Get List of Pacakges"""
|
||||
adb = getADB(toolsdir)
|
||||
args = [adb, "-s", get_identifier(), "shell", "ls", "/data/data"]
|
||||
# prolly a better way to get packages is needed
|
||||
try:
|
||||
return subprocess.check_output(args)
|
||||
|
||||
+150
-105
@@ -21,14 +21,14 @@ from install.windows.setup import windows_config_local
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
#==============================================
|
||||
|
||||
MOBSF_VER = "v0.9.4.3 Beta"
|
||||
MOBSF_VER = "v0.9.5.1 Beta"
|
||||
BANNER = """
|
||||
__ __ _ ____ _____ ___ ___ _ _
|
||||
| \/ | ___ | |__/ ___|| ___|_ __/ _ \ / _ \| || |
|
||||
| |\/| |/ _ \| '_ \___ \| |_ \ \ / / | | | (_) | || |_
|
||||
| | | | (_) | |_) |__) | _| \ V /| |_| |\__, |__ _|
|
||||
|_| |_|\___/|_.__/____/|_| \_/ \___(_) /_(_) |_|
|
||||
|
||||
__ __ _ ____ _____ ___ ___ ____
|
||||
| \/ | ___ | |__/ ___|| ___|_ __/ _ \ / _ \ | ___|
|
||||
| |\/| |/ _ \| '_ \___ \| |_ \ \ / / | | | (_) ||___ \
|
||||
| | | | (_) | |_) |__) | _| \ V /| |_| |\__, | ___) |
|
||||
|_| |_|\___/|_.__/____/|_| \_/ \___(_) /_(_)____/
|
||||
|
||||
"""
|
||||
#==============================================
|
||||
|
||||
@@ -148,7 +148,7 @@ except NameError:
|
||||
Exception('Please create a %s file with random characters \
|
||||
to generate your secret key!' % SECRET_FILE)
|
||||
# Run Once
|
||||
#Windows Setup
|
||||
# Windows Setup
|
||||
windows_config_local(MobSF_HOME)
|
||||
utils.make_migrations(BASE_DIR)
|
||||
utils.migrate(BASE_DIR)
|
||||
@@ -219,7 +219,10 @@ STATICFILES_DIRS = (
|
||||
# https://docs.djangoproject.com/en/dev/howto/static-files/
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
#===============================================
|
||||
#===================
|
||||
# USER CONFIGURATION
|
||||
#===================
|
||||
|
||||
if CONFIG_HOME:
|
||||
print "[INFO] Loading User config from: " + USER_CONFIG
|
||||
else:
|
||||
@@ -233,7 +236,11 @@ else:
|
||||
# MOBSF USER CONFIGURATIONS
|
||||
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
|
||||
#==========SKIP CLASSES==========================
|
||||
#-------------------------
|
||||
# STATIC ANALYZER SETTINGS
|
||||
#-------------------------
|
||||
|
||||
#==========ANDROID SKIP CLASSES==========================
|
||||
|
||||
SKIP_CLASSES = [
|
||||
'android/support/', 'com/google/', 'android/content/',
|
||||
@@ -242,99 +249,6 @@ else:
|
||||
'oauth/signpost/', 'org/chromium/'
|
||||
]
|
||||
|
||||
#==============3rd Party Tools=================
|
||||
'''
|
||||
If you want to use a different version of 3rd party tools used by MobSF.
|
||||
You can do that by specifying the path here. If specified, MobSF will run
|
||||
the tool from this location.
|
||||
'''
|
||||
|
||||
# Android 3P Tools
|
||||
DEX2JAR_BINARY = ""
|
||||
BACKSMALI_BINARY = ""
|
||||
AXMLPRINTER_BINARY = ""
|
||||
CFR_DECOMPILER_BINARY = ""
|
||||
JD_CORE_DECOMPILER_BINARY = ""
|
||||
PROCYON_DECOMPILER_BINARY = ""
|
||||
ADB_BINARY = ""
|
||||
ENJARIFY_DIRECTORY = ""
|
||||
|
||||
# iOS 3P Tools
|
||||
OTOOL_BINARY = ""
|
||||
CLASSDUMPZ_BINARY = ""
|
||||
|
||||
# COMMON
|
||||
JAVA_DIRECTORY = ""
|
||||
VBOXMANAGE_BINARY = ""
|
||||
|
||||
'''
|
||||
Examples:
|
||||
JAVA_DIRECTORY = "C:/Program Files/Java/jdk1.7.0_17/bin/"
|
||||
JAVA_DIRECTORY = "/usr/bin/"
|
||||
DEX2JAR_BINARY = "/Users/ajin/dex2jar/d2j-dex2jar.sh"
|
||||
ENJARIFY_DIRECTORY = "D:/enjarify/"
|
||||
VBOXMANAGE_BINARY = "/usr/bin/VBoxManage"
|
||||
CFR_DECOMPILER_BINARY = "/home/ajin/tools/cfr.jar"
|
||||
'''
|
||||
#===============================================
|
||||
|
||||
#==============RESPONSE VALIDATION==============
|
||||
XXE_VALIDATE_STRING = "m0bsfxx3"
|
||||
#===============================================
|
||||
|
||||
#=========Path Traversal - API Testing==========
|
||||
CHECK_FILE = "/etc/passwd"
|
||||
RESPONSE_REGEX = "root:|nobody:"
|
||||
#===============================================
|
||||
|
||||
#=========Rate Limit Check - API Testing========
|
||||
RATE_REGISTER = 20
|
||||
RATE_LOGIN = 20
|
||||
#===============================================
|
||||
|
||||
#===============MobSF Cloud Settings============
|
||||
CLOUD_SERVER = 'http://opensecurity.in:8080'
|
||||
'''
|
||||
This server validates SSRF and XXE during Web API Testing
|
||||
See the source code of the cloud server from APITester/cloud/cloud_server.py
|
||||
You can also host the cloud server. Host it on a public IP and point CLOUD_SERVER to that IP.
|
||||
'''
|
||||
|
||||
#===============DEVICE SETTINGS=================
|
||||
REAL_DEVICE = False
|
||||
DEVICE_IP = '192.168.1.18'
|
||||
DEVICE_ADB_PORT = 5555
|
||||
DEVICE_TIMEOUT = 300
|
||||
#===============================================
|
||||
#================VM SETTINGS ===================
|
||||
|
||||
# VM UUID
|
||||
UUID = '408e1874-759f-4417-9453-53ef21dc2ade'
|
||||
# Snapshot UUID
|
||||
SUUID = '5c9deb28-def6-49c0-9233-b5e03edd85c6'
|
||||
# IP of the MobSF VM
|
||||
VM_IP = '192.168.56.101'
|
||||
VM_ADB_PORT = 5555
|
||||
VM_TIMEOUT = 100
|
||||
#==============================================
|
||||
#================HOST/PROXY SETTINGS ==========
|
||||
|
||||
PROXY_IP = '192.168.56.1' # Host/Server/Proxy IP
|
||||
PORT = 1337 # Proxy Port
|
||||
ROOT_CA = '0025aabb.0'
|
||||
SCREEN_IP = PROXY_IP # ScreenCast IP
|
||||
SCREEN_PORT = 9339 # ScreenCast Port
|
||||
|
||||
#==============================================
|
||||
|
||||
#========UPSTREAM PROXY SETTINGS ==============
|
||||
# If you are behind a Proxy
|
||||
UPSTREAM_PROXY_IP = None
|
||||
UPSTREAM_PROXY_PORT = None
|
||||
UPSTREAM_PROXY_USERNAME = None
|
||||
UPSTREAM_PROXY_PASSWORD = None
|
||||
#==============================================
|
||||
|
||||
#==========DECOMPILER SETTINGS=================
|
||||
|
||||
DECOMPILER = "cfr"
|
||||
@@ -371,15 +285,146 @@ else:
|
||||
# python setup.py install
|
||||
#==============================================
|
||||
|
||||
#================WINDOWS-Analysis-Settings ====
|
||||
#======WINDOWS STATIC ANALYSIS SETTINGS ===========
|
||||
|
||||
# Private key if rpc server is needed
|
||||
# Private key
|
||||
WINDOWS_VM_SECRET = 'MobSF/windows_vm_priv_key.asc'
|
||||
# IP and Port of the MobSF Windows VM
|
||||
# eg: WINDOWS_VM_IP = '127.0.0.1'
|
||||
WINDOWS_VM_IP = None
|
||||
WINDOWS_VM_PORT = '8000'
|
||||
#==================================================
|
||||
|
||||
#==============3rd Party Tools=================
|
||||
'''
|
||||
If you want to use a different version of 3rd party tools used by MobSF.
|
||||
You can do that by specifying the path here. If specified, MobSF will run
|
||||
the tool from this location.
|
||||
'''
|
||||
|
||||
# Android 3P Tools
|
||||
DEX2JAR_BINARY = ""
|
||||
BACKSMALI_BINARY = ""
|
||||
AXMLPRINTER_BINARY = ""
|
||||
CFR_DECOMPILER_BINARY = ""
|
||||
JD_CORE_DECOMPILER_BINARY = ""
|
||||
PROCYON_DECOMPILER_BINARY = ""
|
||||
ADB_BINARY = ""
|
||||
ENJARIFY_DIRECTORY = ""
|
||||
|
||||
# iOS 3P Tools
|
||||
OTOOL_BINARY = ""
|
||||
CLASSDUMPZ_BINARY = ""
|
||||
|
||||
# COMMON
|
||||
JAVA_DIRECTORY = ""
|
||||
VBOXMANAGE_BINARY = ""
|
||||
|
||||
'''
|
||||
Examples:
|
||||
JAVA_DIRECTORY = "C:/Program Files/Java/jdk1.7.0_17/bin/"
|
||||
JAVA_DIRECTORY = "/usr/bin/"
|
||||
DEX2JAR_BINARY = "/Users/ajin/dex2jar/d2j-dex2jar.sh"
|
||||
ENJARIFY_DIRECTORY = "D:/enjarify/"
|
||||
VBOXMANAGE_BINARY = "/usr/bin/VBoxManage"
|
||||
CFR_DECOMPILER_BINARY = "/home/ajin/tools/cfr.jar"
|
||||
'''
|
||||
#===============================================
|
||||
|
||||
#-------------------------
|
||||
# DYNAMIC ANALYZER SETTINGS
|
||||
#-------------------------
|
||||
|
||||
#========ANDROID DYNAMIC ANALYSIS SETTINGS================================
|
||||
|
||||
ANDROID_DYNAMIC_ANALYZER = "MobSF_VM"
|
||||
|
||||
# You can choose any of the below
|
||||
# 1. MobSF_VM
|
||||
# 2. MobSF_AVD
|
||||
# 3. MobSF_REAL_DEVICE
|
||||
|
||||
'''
|
||||
MobSF_VM - x86 Android 4.4.2 running on VirtualBox (Fast, not all Apps work)
|
||||
MobSF_AVD - ARM Android 4.1.2 running on Android Emulator (Slow, Most Apps work)
|
||||
MobSF_REAL_DEVICE - Rooted Android 4.03 - 4.4 Device (Very Fast, All Apps work)
|
||||
'''
|
||||
|
||||
#=========================================================================
|
||||
|
||||
#=======ANDROID REAL DEVICE SETTINGS===========
|
||||
DEVICE_IP = '192.168.1.18'
|
||||
DEVICE_ADB_PORT = 5555
|
||||
DEVICE_TIMEOUT = 300
|
||||
#==============================================
|
||||
|
||||
#===========ANDROID EMULATOR SETTINGS ===========
|
||||
# generated by mobsfy_AVD.py, do not edit the
|
||||
# below AVD settings yourself.
|
||||
AVD_EMULATOR = "avd_emulator"
|
||||
AVD_PATH = "avd_path"
|
||||
AVD_REFERENCE_NAME = r'Nexus5API16'
|
||||
AVD_DUP_NAME = r'Nexus5API16_1'
|
||||
AVD_ADB_PORT = 5554
|
||||
#================================================
|
||||
|
||||
#====ANDROID MOBSF VIRTUALBOX VM SETTINGS =====
|
||||
# VM UUID
|
||||
UUID = '408e1874-759f-4417-9453-53ef21dc2ade'
|
||||
# Snapshot UUID
|
||||
SUUID = '5c9deb28-def6-49c0-9233-b5e03edd85c6'
|
||||
# IP of the MobSF VM
|
||||
VM_IP = '192.168.56.101'
|
||||
VM_ADB_PORT = 5555
|
||||
VM_TIMEOUT = 100
|
||||
#==============================================
|
||||
|
||||
#--------------------------
|
||||
# MobSF MITM PROXY SETTINGS
|
||||
#--------------------------
|
||||
|
||||
#================HOST/PROXY SETTINGS ===============
|
||||
PROXY_IP = '192.168.56.1' # Host/Server/Proxy IP
|
||||
PORT = 1337 # Proxy Port
|
||||
ROOT_CA = '0025aabb.0'
|
||||
SCREEN_IP = PROXY_IP # ScreenCast IP
|
||||
SCREEN_PORT = 9339 # ScreenCast Port(Do not Change)
|
||||
#===================================================
|
||||
|
||||
#========UPSTREAM PROXY SETTINGS ==============
|
||||
# If you are behind a Proxy
|
||||
UPSTREAM_PROXY_IP = None
|
||||
UPSTREAM_PROXY_PORT = None
|
||||
UPSTREAM_PROXY_USERNAME = None
|
||||
UPSTREAM_PROXY_PASSWORD = None
|
||||
#==============================================
|
||||
|
||||
#------------------------
|
||||
# WEB API FUZZER SETTINGS
|
||||
#------------------------
|
||||
|
||||
#==============RESPONSE VALIDATION==============
|
||||
XXE_VALIDATE_STRING = "m0bsfxx3"
|
||||
#===============================================
|
||||
|
||||
#=========Path Traversal - API Testing==========
|
||||
CHECK_FILE = "/etc/passwd"
|
||||
RESPONSE_REGEX = "root:|nobody:"
|
||||
#===============================================
|
||||
|
||||
#=========Rate Limit Check - API Testing========
|
||||
RATE_REGISTER = 20
|
||||
RATE_LOGIN = 20
|
||||
#===============================================
|
||||
|
||||
#===============MobSF Cloud Settings============
|
||||
CLOUD_SERVER = 'http://opensecurity.in:8080'
|
||||
'''
|
||||
This server validates SSRF and XXE during Web API Testing
|
||||
See the source code of the cloud server from APITester/cloud/cloud_server.py
|
||||
You can also host the cloud server. Host it on a public IP and point CLOUD_SERVER to that IP.
|
||||
'''
|
||||
|
||||
#^CONFIG-END^: Do not edit this line
|
||||
|
||||
# The below code should be loaded last.
|
||||
|
||||
+27
-20
@@ -1,7 +1,7 @@
|
||||
from django.conf.urls import url
|
||||
import MobSF.views
|
||||
import APITester.views
|
||||
import DynamicAnalyzer.views.android
|
||||
import DynamicAnalyzer.views.android.android_dynamic
|
||||
import DynamicAnalyzer.views.android_standalone
|
||||
import StaticAnalyzer.views.android.static_analyzer
|
||||
import StaticAnalyzer.views.android.java
|
||||
@@ -23,15 +23,19 @@ urlpatterns = [
|
||||
url(r'^download/', MobSF.views.download),
|
||||
url(r'^about/$', MobSF.views.about),
|
||||
url(r'^recent_scans/$', MobSF.views.recent_scans),
|
||||
url(r'^delete_scan/$', MobSF.views.delete_scan),
|
||||
url(r'^search/$', MobSF.views.search),
|
||||
url(r'^error/$', MobSF.views.error),
|
||||
url(r'^not_found/$', MobSF.views.not_found),
|
||||
url(r'^zip_format/$', MobSF.views.zip_format),
|
||||
url(r'^mac_only/$', MobSF.views.mac_only),
|
||||
|
||||
url(r'^StaticAnalyzer/$', StaticAnalyzer.views.android.static_analyzer.static_analyzer),
|
||||
url(r'^StaticAnalyzer_iOS/$', StaticAnalyzer.views.ios.static_analyzer.static_analyzer_ios),
|
||||
url(r'^StaticAnalyzer_Windows/$', StaticAnalyzer.views.windows.staticanalyzer_windows),
|
||||
url(r'^StaticAnalyzer/$',
|
||||
StaticAnalyzer.views.android.static_analyzer.static_analyzer),
|
||||
url(r'^StaticAnalyzer_iOS/$',
|
||||
StaticAnalyzer.views.ios.static_analyzer.static_analyzer_ios),
|
||||
url(r'^StaticAnalyzer_Windows/$',
|
||||
StaticAnalyzer.views.windows.staticanalyzer_windows),
|
||||
url(r'^ViewFile/$', StaticAnalyzer.views.ios.static_analyzer.view_file),
|
||||
url(r'^ViewSource/$', StaticAnalyzer.views.android.view_source.run),
|
||||
url(r'^PDF/$', StaticAnalyzer.views.shared_func.PDF),
|
||||
@@ -40,27 +44,30 @@ urlpatterns = [
|
||||
url(r'^Find/$', StaticAnalyzer.views.android.find.run),
|
||||
url(r'^ManifestView/$', StaticAnalyzer.views.android.manifest_view.run),
|
||||
|
||||
url(r'^DynamicAnalyzer/$', DynamicAnalyzer.views.android.DynamicAnalyzer),
|
||||
url(r'^GetEnv/$', DynamicAnalyzer.views.android.GetEnv),
|
||||
url(r'^GetRes/$', DynamicAnalyzer.views.android.GetRes),
|
||||
url(r'^MobSFCA/$', DynamicAnalyzer.views.android.MobSFCA),
|
||||
url(r'^TakeScreenShot/$', DynamicAnalyzer.views.android.TakeScreenShot),
|
||||
url(r'^ClipDump/$', DynamicAnalyzer.views.android.clip_dump),
|
||||
url(r'^DynamicAnalyzer/$',
|
||||
DynamicAnalyzer.views.android.android_dynamic.android_dynamic_analyzer),
|
||||
url(r'^GetEnv/$', DynamicAnalyzer.views.android.android_dynamic.get_env),
|
||||
url(r'^GetRes/$', DynamicAnalyzer.views.android.android_dynamic.get_res),
|
||||
url(r'^MobSFCA/$', DynamicAnalyzer.views.android.android_dynamic.mobsf_ca),
|
||||
url(r'^TakeScreenShot/$',
|
||||
DynamicAnalyzer.views.android.android_dynamic.take_screenshot),
|
||||
url(r'^ClipDump/$', DynamicAnalyzer.views.android.android_dynamic.clip_dump),
|
||||
url(r'^ExportedActivityTester/$',
|
||||
DynamicAnalyzer.views.android.ExportedActivityTester),
|
||||
url(r'^ActivityTester/$', DynamicAnalyzer.views.android.ActivityTester),
|
||||
url(r'^FinalTest/$', DynamicAnalyzer.views.android.FinalTest),
|
||||
url(r'^DumpData/$', DynamicAnalyzer.views.android.DumpData),
|
||||
url(r'^ExecuteADB/$', DynamicAnalyzer.views.android.ExecuteADB),
|
||||
url(r'^Report/$', DynamicAnalyzer.views.android.Report),
|
||||
url(r'^View/$', DynamicAnalyzer.views.android.View),
|
||||
url(r'^ScreenCast/$', DynamicAnalyzer.views.android.ScreenCast),
|
||||
url(r'^Touch/$', DynamicAnalyzer.views.android.Touch),
|
||||
DynamicAnalyzer.views.android.android_dynamic.exported_activity_tester),
|
||||
url(r'^ActivityTester/$',
|
||||
DynamicAnalyzer.views.android.android_dynamic.activity_tester),
|
||||
url(r'^FinalTest/$', DynamicAnalyzer.views.android.android_dynamic.final_test),
|
||||
url(r'^DumpData/$', DynamicAnalyzer.views.android.android_dynamic.dump_data),
|
||||
url(r'^ExecuteADB/$', DynamicAnalyzer.views.android.android_dynamic.execute_adb),
|
||||
url(r'^Report/$', DynamicAnalyzer.views.android.android_dynamic.report),
|
||||
url(r'^View/$', DynamicAnalyzer.views.android.android_dynamic.view),
|
||||
url(r'^ScreenCast/$', DynamicAnalyzer.views.android.android_dynamic.screen_cast),
|
||||
url(r'^Touch/$', DynamicAnalyzer.views.android.android_dynamic.touch),
|
||||
|
||||
url(r'^APIFuzzer/$', APITester.views.APIFuzzer),
|
||||
url(r'^StartScan/$', APITester.views.StartScan),
|
||||
url(r'^NoAPI/$', APITester.views.NoAPI),
|
||||
#Test
|
||||
# Test
|
||||
url(r'^runtest/$', StaticAnalyzer.tests.start_test),
|
||||
]
|
||||
|
||||
|
||||
+1
-1
@@ -157,7 +157,7 @@ def kali_fix(BASE_DIR):
|
||||
|
||||
def FindVbox(debug=False):
|
||||
try:
|
||||
if settings.REAL_DEVICE == False:
|
||||
if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_VM":
|
||||
if len(settings.VBOXMANAGE_BINARY) > 0 and isFileExists(settings.VBOXMANAGE_BINARY):
|
||||
return settings.VBOXMANAGE_BINARY
|
||||
if platform.system() == "Windows":
|
||||
|
||||
+53
-5
@@ -4,6 +4,7 @@ MobSF File Upload and Home Routes
|
||||
"""
|
||||
import os
|
||||
import hashlib
|
||||
import shutil
|
||||
import platform
|
||||
import json
|
||||
import re
|
||||
@@ -14,8 +15,15 @@ from django.http import HttpResponse
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.conf import settings
|
||||
from django.utils import timezone
|
||||
from MobSF.utils import PrintException
|
||||
from MobSF.utils import PrintException, isDirExists, isFileExists
|
||||
from MobSF.models import RecentScansDB
|
||||
from APITester.models import ScopeURLSandTests
|
||||
from StaticAnalyzer.models import (
|
||||
StaticAnalyzerAndroid,
|
||||
StaticAnalyzerIPA,
|
||||
StaticAnalyzerIOSZIP,
|
||||
StaticAnalyzerWindows,
|
||||
)
|
||||
from .forms import UploadFileForm
|
||||
|
||||
|
||||
@@ -110,12 +118,15 @@ def upload(request):
|
||||
response_data['url'] = 'mac_only/'
|
||||
response_data['status'] = 'success'
|
||||
print "\n[ERROR] Static Analysis of iOS IPA requires OSX"
|
||||
elif (file_type in settings.APPX_MIME) and request.FILES['file'].name.lower().endswith('.appx'): #Windows APPX
|
||||
md5=handle_uploaded_file(request.FILES['file'],'.appx')
|
||||
response_data['url'] = 'StaticAnalyzer_Windows/?name='+request.FILES['file'].name+'&type=appx&checksum='+md5
|
||||
# Windows APPX
|
||||
elif (file_type in settings.APPX_MIME) and request.FILES['file'].name.lower().endswith('.appx'):
|
||||
md5 = handle_uploaded_file(request.FILES['file'], '.appx')
|
||||
response_data['url'] = 'StaticAnalyzer_Windows/?name=' + \
|
||||
request.FILES['file'].name + \
|
||||
'&type=appx&checksum=' + md5
|
||||
response_data['status'] = 'success'
|
||||
add_to_recent_scan(
|
||||
request.FILES['file'].name,md5,response_data['url'])
|
||||
request.FILES['file'].name, md5, response_data['url'])
|
||||
print "\n[INFO] Performing Static Analysis of Windows APP"
|
||||
else:
|
||||
response_data['url'] = ''
|
||||
@@ -235,3 +246,40 @@ def download(request):
|
||||
except:
|
||||
PrintException("Error Downloading File")
|
||||
return HttpResponseRedirect('/error/')
|
||||
|
||||
|
||||
def delete_scan(request):
|
||||
"""
|
||||
Delete Scan from DB and remove the scan related files
|
||||
"""
|
||||
try:
|
||||
if request.method == 'POST':
|
||||
md5_hash = request.POST['md5']
|
||||
data = {'deleted': 'no'}
|
||||
if re.match('[0-9a-f]{32}', md5_hash):
|
||||
# Delete DB Entries
|
||||
RecentScansDB.objects.filter(MD5=md5_hash).delete()
|
||||
ScopeURLSandTests.objects.filter(MD5=md5_hash).delete()
|
||||
StaticAnalyzerAndroid.objects.filter(MD5=md5_hash).delete()
|
||||
StaticAnalyzerIPA.objects.filter(MD5=md5_hash).delete()
|
||||
StaticAnalyzerIOSZIP.objects.filter(MD5=md5_hash).delete()
|
||||
StaticAnalyzerWindows.objects.filter(MD5=md5_hash).delete()
|
||||
# Delete Upload Dir Contents
|
||||
app_upload_dir = os.path.join(settings.UPLD_DIR, md5_hash)
|
||||
if isDirExists(app_upload_dir):
|
||||
shutil.rmtree(app_upload_dir)
|
||||
# Delete Download Dir Contents
|
||||
dw_dir = settings.DWD_DIR
|
||||
for item in os.listdir(dw_dir):
|
||||
item_path = os.path.join(dw_dir, item)
|
||||
# Delete all related files
|
||||
if isFileExists(item_path) and item.startswith(md5_hash + "-"):
|
||||
os.remove(item_path)
|
||||
# Delete related directories
|
||||
if isDirExists(item_path) and item.startswith(md5_hash + "-"):
|
||||
shutil.rmtree(item_path)
|
||||
data = {'deleted': 'yes'}
|
||||
return HttpResponse(json.dumps(data), content_type='application/json')
|
||||
except:
|
||||
PrintException("Error Deleting Scan")
|
||||
return HttpResponseRedirect('/error/')
|
||||
|
||||
@@ -27,6 +27,7 @@ MobSF is also bundled with [Android Tamer](https://androidtamer.com/tamer4-relea
|
||||
|
||||
* [Ajin Abraham](https://in.linkedin.com/in/ajinabraham)
|
||||
* [Dominik Schlecht](https://github.com/DominikSchlecht)
|
||||
* [Matan Dobrushin](https://github.com/matandobr)
|
||||
|
||||
## Presentations
|
||||
* OWASP APPSEC EU 2016 - [Slides](http://www.slideshare.net/ajin25/automated-mobile-application-security-assessment-with-mobsf) | [Video](https://www.youtube.com/watch?v=h00v1euuFXg)
|
||||
@@ -73,15 +74,16 @@ MobSF is also bundled with [Android Tamer](https://androidtamer.com/tamer4-relea
|
||||

|
||||
|
||||
## Credits
|
||||
* Dominik Schlecht - For the awesome work on adding Windows Phone App Static Analysis to MobSF
|
||||
* Bharadwaj Machiraju (@tunnelshade_) - For writing pyWebProxy from scratch
|
||||
* MindMac - For writing Android Blue Pill
|
||||
* Thomas Abraham - For JS Hacks on UI.
|
||||
* Anto Joseph (@antojosep007) - For the help with SuperSU.
|
||||
* Tim Brown (@timb_machine) - For the iOS Binary Analysis Ruleset.
|
||||
* Abhinav Sejpal (@Abhinav_Sejpal) - For poking me with bugs and feature requests.
|
||||
* Anant Srivastava (@anantshri) - For Activity Tester Idea
|
||||
* Abhinav Sejpal (@Abhinav_Sejpal) - For poking me with bugs, feature requests, and UI & UX suggestions.
|
||||
* Amrutha VC (@amruthavc) - For the new MobSF logo
|
||||
* Rahul (@c0dist) - Kali Support
|
||||
* shuxin - Android Binary Analysis
|
||||
* Anant Srivastava (@anantshri) - For Activity Tester Idea
|
||||
* Anto Joseph (@antojosep007) - For the help with SuperSU.
|
||||
* Bharadwaj Machiraju (@tunnelshade_) - For writing pyWebProxy from scratch
|
||||
* Dominik Schlecht - For the awesome work on adding Windows Phone App Static Analysis to MobSF
|
||||
* Esteban - Better Android Manifest Analysis and Static Analysis Improvement.
|
||||
* Matan Dobrushin - For adding Android ARM Emulator support to MobSF - Special thanks goes for cuckoo-droid, I got inspierd by their code and idea for this implementation.
|
||||
* MindMac - For writing Android Blue Pill
|
||||
* Rahul (@c0dist) - Kali Support
|
||||
* Shuxin - Android Binary Analysis
|
||||
* Thomas Abraham - For JS Hacks on UI.
|
||||
* Tim Brown (@timb_machine) - For the iOS Binary Analysis Ruleset.
|
||||
|
||||
+26
-7
@@ -10,14 +10,15 @@ from django.http import HttpResponse
|
||||
from MobSF.utils import PrintException
|
||||
|
||||
RESCAN = False
|
||||
#Set RESCAN to True if Static Analyzer Code is modified
|
||||
# Set RESCAN to True if Static Analyzer Code is modified
|
||||
|
||||
|
||||
def static_analysis():
|
||||
"""Test Static Analyzer"""
|
||||
failed = False
|
||||
ERR_MSG = '%s'
|
||||
err_msg = '%s'
|
||||
if platform.system() != "Windows":
|
||||
ERR_MSG = '\033[91m \033[1m %s \033[0m'
|
||||
err_msg = '\033[91m \033[1m %s \033[0m'
|
||||
try:
|
||||
uploaded = []
|
||||
print "[INFO] Running Upload Test"
|
||||
@@ -32,7 +33,7 @@ def static_analysis():
|
||||
print "[OK] Upload OK: " + filename
|
||||
uploaded.append(obj["url"])
|
||||
else:
|
||||
print ERR_MSG % "[ERROR] Performing Upload" + filename
|
||||
print err_msg % "[ERROR] Performing Upload" + filename
|
||||
failed = True
|
||||
print "[OK] Completed Upload test"
|
||||
print "[INFO] Running Static Analysis Test"
|
||||
@@ -45,7 +46,7 @@ def static_analysis():
|
||||
if resp.status_code == 200:
|
||||
print "[OK] Static Analysis Complete: " + upl
|
||||
else:
|
||||
print ERR_MSG % "[ERROR] Performing Static Analysis: " + upl
|
||||
print err_msg % "[ERROR] Performing Static Analysis: " + upl
|
||||
failed = True
|
||||
print "[OK] Static Analysis test completed"
|
||||
print "[INFO] Running PDF Generation Test"
|
||||
@@ -60,14 +61,31 @@ def static_analysis():
|
||||
for pdf in pdfs:
|
||||
resp = http_client.get(pdf)
|
||||
if (resp.status_code == 200 and
|
||||
resp._headers['content-type'][1] == "application/pdf"
|
||||
resp._headers['content-type'][1] == "application/pdf"
|
||||
):
|
||||
print "[OK] PDF Report Generated: " + pdf
|
||||
else:
|
||||
print ERR_MSG % "[ERROR] Generating PDF: " + pdf
|
||||
print err_msg % "[ERROR] Generating PDF: " + pdf
|
||||
print resp.content
|
||||
failed = True
|
||||
print "[OK] PDF Generation test completed"
|
||||
print "[INFO] Running Delete Scan Results test"
|
||||
# Deleting Scan Results
|
||||
scan_md5s = ["3a552566097a8de588b8184b059b0158", "6c23c2970551be15f32bbab0b5db0c71",
|
||||
"52c50ae824e329ba8b5b7a0f523efffe", "57bb5be0ea44a755ada4a93885c3825e", "8179b557433835827a70510584f3143e"]
|
||||
for md5 in scan_md5s:
|
||||
resp = http_client.post('/delete_scan/', {'md5': md5})
|
||||
if resp.status_code == 200:
|
||||
dat = json.loads(resp.content)
|
||||
if dat["deleted"] == "yes":
|
||||
print "[OK] Deleted Scan: " + md5
|
||||
else:
|
||||
print err_msg % "[ERROR] Deleting Scan: " + md5
|
||||
failed = True
|
||||
else:
|
||||
print err_msg % "[ERROR] Deleting Scan: " + md5
|
||||
failed = True
|
||||
print "[INFO] Delete Scan Results test completed"
|
||||
except:
|
||||
PrintException("[ERROR] Completing Static Analyzer Test")
|
||||
return failed
|
||||
@@ -85,5 +103,6 @@ def start_test(request):
|
||||
except:
|
||||
message = "error"
|
||||
print "\n\n[INFO] ALL TESTS COMPLETED!"
|
||||
print "[INFO] Test Status: " + message
|
||||
return HttpResponse(json.dumps({"static_analyzer_test": message}),
|
||||
content_type="application/json")
|
||||
|
||||
Executable
+317
@@ -0,0 +1,317 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf_8 -*-
|
||||
import os
|
||||
import platform
|
||||
import subprocess
|
||||
import sys
|
||||
import getpass
|
||||
import shutil
|
||||
import io
|
||||
import string
|
||||
import re
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
|
||||
def get_windows_drive():
|
||||
drive = os.getenv('WINDIR')[:1] + ':'
|
||||
if not drive:
|
||||
return 'C:'
|
||||
return drive
|
||||
|
||||
|
||||
def print_log(msg, log_type='INFO'):
|
||||
print '\n[' + log_type + '] ' + msg + '\n'
|
||||
|
||||
|
||||
def execute_cmd(args, ret=False):
|
||||
try:
|
||||
print "\n[INFO] Executing Command - " + ' '.join(args)
|
||||
if ret:
|
||||
return subprocess.check_output(args)
|
||||
else:
|
||||
subprocess.call(args)
|
||||
except Exception as e:
|
||||
print "\n[ERROR] Executing Command - " + str(e)
|
||||
|
||||
|
||||
def verify_path(help_msg):
|
||||
path = raw_input(help_msg + ': ')
|
||||
path = path.strip()
|
||||
while not os.path.exists(path):
|
||||
print_log('Path specified does not exists \ no access', 'ERROR')
|
||||
path = raw_input(help_msg)
|
||||
return path
|
||||
|
||||
|
||||
def guess_android_avd_folder():
|
||||
system = platform.system()
|
||||
|
||||
if system == 'Darwin':
|
||||
username = getpass.getuser()
|
||||
first_guess = os.path.join('/Users', username, '.android/avd')
|
||||
if os.path.exists(first_guess):
|
||||
return first_guess
|
||||
|
||||
elif system == "Linux":
|
||||
for path in [os.path.expanduser('~/.android/avd/')]:
|
||||
if os.path.exists(path):
|
||||
return path
|
||||
|
||||
elif system == 'Windows':
|
||||
username = getpass.getuser()
|
||||
drive = get_windows_drive()
|
||||
for path in [os.path.join(drive + '\\Documents and Settings', username, '.android\\avd'),
|
||||
os.path.join(drive + '\\Users', username, '.android\\avd')]:
|
||||
if os.path.exists(path):
|
||||
return path
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def guess_android_sdk_folder():
|
||||
system = platform.system()
|
||||
username = getpass.getuser()
|
||||
|
||||
if system == 'Darwin':
|
||||
for path in [os.path.join('/Users', username, 'Library/Android/Sdk/'),
|
||||
os.path.join('/Users', username, 'Library/Android/sdk/')]:
|
||||
if os.path.exists(path):
|
||||
return path
|
||||
|
||||
elif system == "Linux":
|
||||
for path in ['/usr/local/android-sdk',
|
||||
'/usr/local/android',
|
||||
'/usr/local/Android',
|
||||
os.path.expanduser('~/Android/Sdk'),
|
||||
os.path.expanduser('~/Android/sdk'),
|
||||
os.path.expanduser('~/android/Sdk'),
|
||||
os.path.expanduser('~/android/sdk')]:
|
||||
if os.path.exists(path):
|
||||
return path
|
||||
|
||||
elif system == 'Windows':
|
||||
drive = get_windows_drive()
|
||||
for path in [os.path.join(drive + '\\Users', username, 'AppData\\Local\\Android\\sdk'),
|
||||
os.path.join(drive + '\\Users', username,
|
||||
'AppData\\Local\\Android\\Sdk'),
|
||||
os.path.join(drive + '\\Documents and Settings',
|
||||
username, 'AppData\\Local\\Android\\sdk'),
|
||||
os.path.join(drive + '\\Documents and Settings', username, 'AppData\\Local\\Android\\Sdk')]:
|
||||
if os.path.exists(path):
|
||||
return path
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def find_emulator_binary(sdk):
|
||||
system = platform.system()
|
||||
|
||||
if system in ['Darwin', 'Linux']:
|
||||
# Prefer emulator folder on tools folder
|
||||
for path in [os.path.join(sdk, 'emulator', 'emulator'),
|
||||
os.path.join(sdk, 'tools', 'emulator')]:
|
||||
if os.path.exists(path):
|
||||
return path
|
||||
|
||||
elif system == 'Windows':
|
||||
for path in [os.path.join(sdk, 'emulator', 'emulator.exe'),
|
||||
os.path.join(sdk, 'tools', 'emulator.exe')]:
|
||||
if os.path.exists(path):
|
||||
return path
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def find_adb_binary(sdk):
|
||||
system = platform.system()
|
||||
|
||||
if system in ['Darwin', 'Linux']:
|
||||
guess = os.path.join(sdk, 'platform-tools', 'adb')
|
||||
if os.path.exists(guess):
|
||||
return guess
|
||||
|
||||
elif system == 'Windows':
|
||||
guess = os.path.join(sdk, 'platform-tools', 'adb.exe')
|
||||
if os.path.exists(guess):
|
||||
return guess
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def find_skin(sdk):
|
||||
# Just a basic check
|
||||
system = platform.system()
|
||||
|
||||
if system == 'Darwin':
|
||||
guess = r'/Applications/Android Studio.app/Contents/plugins/android/lib/device-art-resources/nexus_5'
|
||||
if os.path.exists(guess):
|
||||
return guess
|
||||
|
||||
elif system in ['Windows', 'Linux']:
|
||||
guess = os.path.join(sdk, 'skins', 'nexus_5')
|
||||
if os.path.exists(guess):
|
||||
return guess
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def is_file_exists(file_path):
|
||||
"""Check if File Exists"""
|
||||
return bool(os.path.isfile(file_path))
|
||||
|
||||
|
||||
# returns an array of [str(tabs_string), str(rest_of_the_string)]
|
||||
def split_tabs(inp_string):
|
||||
rgx = re.compile(r"([\s]+)(.*)")
|
||||
match = rgx.match(inp_string)
|
||||
if match:
|
||||
return [match.group(1), match.group(2)]
|
||||
else:
|
||||
return ['', inp_string]
|
||||
|
||||
|
||||
# path to modify, replace dict = {'field_to_replace1':'value1',
|
||||
# 'field_to_replace2': 'value2'}
|
||||
def replace_values_by_fieldnames(path, replace_dict):
|
||||
replaced_lines = []
|
||||
with io.open(path, mode='r', encoding="utf8", errors="ignore") as fild:
|
||||
for line in fild.readlines():
|
||||
tmp_line = line
|
||||
if path.endswith('.py'):
|
||||
tabs_and_str = split_tabs(line)
|
||||
for field_to_replace in replace_dict.keys():
|
||||
# Python files has annoying tabs that we should consider
|
||||
if path.endswith('.py'):
|
||||
if tabs_and_str[1].lower().startswith(field_to_replace.lower()):
|
||||
tmp_line = tabs_and_str[0] + field_to_replace + " = r\"" + replace_dict[
|
||||
field_to_replace].strip(" \"'").lstrip("r\"") + "\"\n"
|
||||
else:
|
||||
if line.startswith(field_to_replace + '='):
|
||||
tmp_line = field_to_replace + '=' + \
|
||||
replace_dict[field_to_replace].strip() + '\n'
|
||||
replaced_lines.append(tmp_line)
|
||||
with io.open(path, 'w') as fild:
|
||||
# newlines are validated before
|
||||
fild.write(string.join(replaced_lines, ''))
|
||||
|
||||
|
||||
def main():
|
||||
sdk_path = ''
|
||||
avd_path = ''
|
||||
adb_path = ''
|
||||
emulator_binary = ''
|
||||
mobsf_arm_folder = ''
|
||||
settings_py = ''
|
||||
|
||||
print "\nMobSFy_AVD Script\n\n"
|
||||
print_log('Starting MobSF - AVD interactive configuration script')
|
||||
print_log('Make sure to run this script ONLY after you successfuly installed leatest AndroidStudio & downloaded MobSF_ARM_Emulator.zip')
|
||||
|
||||
# First gather all the paths needed to make to copy opera
|
||||
|
||||
print_log('Please specify the path to MobSF_ARM_Emulator extracted folder')
|
||||
mobsf_arm_folder = verify_path('MobSF_ARM_Emulator folder')
|
||||
|
||||
# Give the user the ability to change the sdk and avd folder, let me guess
|
||||
# the other tools
|
||||
print_log('This script will overwrite any previously generated files.')
|
||||
guessd_sdk_path = guess_android_sdk_folder()
|
||||
if guessd_sdk_path:
|
||||
user_approve = raw_input(
|
||||
"Guessing Android sdk path: " + guessd_sdk_path + '\n Press Enter/alternative path')
|
||||
if user_approve.strip() == '':
|
||||
sdk_path = guessd_sdk_path
|
||||
elif os.path.exists(user_approve):
|
||||
sdk_path = user_approve
|
||||
if not sdk_path:
|
||||
sdk_path = verify_path('Android SDK path')
|
||||
|
||||
guessd_avd_path = guess_android_avd_folder()
|
||||
if guessd_avd_path:
|
||||
user_approve = raw_input(
|
||||
"Guessing Android AVD folder: " + guessd_avd_path + '\n Press Enter/alternative path')
|
||||
if user_approve.strip() == '':
|
||||
avd_path = guessd_avd_path
|
||||
elif os.path.exists(user_approve):
|
||||
avd_path = user_approve
|
||||
if not avd_path:
|
||||
avd_path = verify_path('Android AVD path')
|
||||
|
||||
emulator_binary = find_emulator_binary(sdk_path)
|
||||
if not emulator_binary:
|
||||
emulator_binary = verify_path('emulator binary')
|
||||
|
||||
adb_path = find_adb_binary(sdk_path)
|
||||
if not adb_path:
|
||||
adb_path = verify_path('adb binary')
|
||||
|
||||
settings_py = os.path.join(BASE_DIR, 'MobSF', 'settings.py')
|
||||
if not os.path.exists(settings_py):
|
||||
settings_py = verify_path('MobSF/settings.py file')
|
||||
|
||||
skin_path = find_skin(sdk_path)
|
||||
if not skin_path:
|
||||
skin_path = verify_path('nexus 5 skin path')
|
||||
|
||||
print_log('Finished finding all the paths needed')
|
||||
|
||||
################## Copy the downloaded emulator and system image #########
|
||||
|
||||
emulator_avd = os.path.join(mobsf_arm_folder, 'Nexus5API16.avd')
|
||||
emulator_ini = os.path.join(mobsf_arm_folder, 'Nexus5API16.ini')
|
||||
new_emulator_avd = os.path.join(avd_path, 'Nexus5API16.avd')
|
||||
new_emulator_ini = os.path.join(avd_path, 'Nexus5API16.ini')
|
||||
print_log('Copying emulator files to avd folder: ' + avd_path)
|
||||
if is_file_exists(new_emulator_ini):
|
||||
print_log("Replacing old Emulator INI")
|
||||
os.remove(new_emulator_ini)
|
||||
shutil.copyfile(emulator_ini, new_emulator_ini)
|
||||
if os.path.isdir(new_emulator_avd):
|
||||
print_log("Replacing old Emulator AVD")
|
||||
shutil.rmtree(new_emulator_avd)
|
||||
shutil.copytree(emulator_avd, new_emulator_avd)
|
||||
system_images = os.path.join(sdk_path, 'system-images')
|
||||
xposed_image_path = os.path.join(system_images, 'Xposed-android-16')
|
||||
downloaded_xposed_image = os.path.join(
|
||||
mobsf_arm_folder, 'Xposed-android-16')
|
||||
if os.path.isdir(xposed_image_path):
|
||||
print_log("Replacing old Xposed image")
|
||||
shutil.rmtree(xposed_image_path)
|
||||
shutil.copytree(downloaded_xposed_image, xposed_image_path)
|
||||
|
||||
################## Modify all the config files ###########################
|
||||
|
||||
print_log('Modifying config files')
|
||||
|
||||
# Nexus5API16.ini
|
||||
replace_values_by_fieldnames(new_emulator_ini, {
|
||||
'path': new_emulator_avd,
|
||||
'skin.path': skin_path
|
||||
})
|
||||
|
||||
# Nexus5API16.avd/config.ini
|
||||
replace_values_by_fieldnames(os.path.join(new_emulator_avd, 'config.ini'), {
|
||||
'skin.path': skin_path
|
||||
})
|
||||
|
||||
# Nexus5API16.avd/hardware-qemu.ini
|
||||
replace_values_by_fieldnames(os.path.join(new_emulator_avd, 'hardware-qemu.ini'), {
|
||||
'hw.sdCard.path': os.path.join(new_emulator_avd, 'sdcard.img'),
|
||||
'disk.cachePartition.path': os.path.join(new_emulator_avd, 'cache.img'),
|
||||
'kernel.path': os.path.join(xposed_image_path, 'kernel-qemu'),
|
||||
'disk.ramdisk.path': os.path.join(xposed_image_path, 'ramdisk.img'),
|
||||
'disk.systemPartition.initPath': os.path.join(xposed_image_path, 'system.img'),
|
||||
'disk.dataPartition.path': os.path.join(new_emulator_avd, 'userdata.img'),
|
||||
})
|
||||
|
||||
replace_values_by_fieldnames(settings_py, {
|
||||
'AVD_EMULATOR': emulator_binary,
|
||||
'AVD_PATH': avd_path,
|
||||
'ADB_BINARY': 'r"' + adb_path + '"'
|
||||
})
|
||||
|
||||
print "\n\nAll Done! you can now use MobSF AVD Emulator :)\n\n"
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
@@ -194,6 +194,12 @@ textarea:focus {
|
||||
$('#start').text("Environment Created");
|
||||
$('#stat').append("\nRunning HTTPS Proxy");
|
||||
|
||||
{% comment %}
|
||||
AVD throws error if we overwrite files
|
||||
{% endcomment %}
|
||||
{% if AVD == True %}
|
||||
$('#stat').append("\nMobSF RootCA Installed Successfully");
|
||||
{% else %}
|
||||
//Install MobSF RootCA
|
||||
$.ajax({
|
||||
url : "../MobSFCA/",
|
||||
@@ -213,6 +219,7 @@ textarea:focus {
|
||||
document.getElementById("er").srcdoc = xhr.responseText;
|
||||
}
|
||||
});
|
||||
{% endif %}
|
||||
|
||||
$('#stat').append("\nConnecting to VM");
|
||||
$('#stat').append("\nMounting");
|
||||
|
||||
@@ -1,7 +1,61 @@
|
||||
|
||||
{% extends "base_top_only.html" %}
|
||||
{% block content %}
|
||||
|
||||
<link href="/static/dash/css/sweetalert2.min.css" rel="stylesheet">
|
||||
<script src="/static/dash/js/sweetalert2.min.js"></script>
|
||||
<script>
|
||||
function delete_scan(item){
|
||||
swal({
|
||||
title: 'Are you sure?',
|
||||
text: "This will permanently remove the scan results from MobSF",
|
||||
type: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#3085d6',
|
||||
cancelButtonColor: '#d33',
|
||||
confirmButtonText: 'Yes',
|
||||
cancelButtonText: 'No',
|
||||
confirmButtonClass: 'btn btn-success',
|
||||
cancelButtonClass: 'btn btn-danger',
|
||||
buttonsStyling: false
|
||||
}).then(function () {
|
||||
var md5_hash = item.id;
|
||||
$.ajax({
|
||||
url : '../delete_scan/',
|
||||
type : 'POST',
|
||||
dataType: 'json',
|
||||
data : {
|
||||
csrfmiddlewaretoken: '{{ csrf_token }}',
|
||||
md5: md5_hash,
|
||||
},
|
||||
success : function(json) {
|
||||
if (json.deleted==='yes'){
|
||||
swal(
|
||||
'Deleted!',
|
||||
'The scan result is deleted!',
|
||||
'success'
|
||||
).then(function () {
|
||||
location.reload();
|
||||
})
|
||||
}
|
||||
else {
|
||||
swal(
|
||||
'Delete Failed',
|
||||
'Cannot delete the scan result!',
|
||||
'error'
|
||||
)
|
||||
}
|
||||
},
|
||||
error : function(xhr,errmsg,err) {
|
||||
swal(
|
||||
'Delete Failed',
|
||||
errmsg,
|
||||
'error'
|
||||
)
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="box box-default">
|
||||
<div class="box-header with-border">
|
||||
@@ -16,7 +70,7 @@
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>MD5</th>
|
||||
<th>View Report</th>
|
||||
<th>Report</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -24,7 +78,8 @@
|
||||
<tr>
|
||||
<td>{{ e.NAME }}</td>
|
||||
<td>{{ e.MD5 }}</td>
|
||||
<td><a href="../{{ e.URL }}"><i class="fa fa-eye"></i> Open Report</a></td>
|
||||
<td><a href="../{{ e.URL }}"><i class="fa fa-eye"></i> View</a> |
|
||||
<a id="{{ e.MD5 }}" onclick="delete_scan(this)"><i class="fa fa-trash"></i> Delete</a></td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
||||
Reference in New Issue
Block a user