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:
Ajin Abraham
2017-04-24 01:34:34 +05:30
committed by GitHub
parent 7626c6da90
commit 6cd9c2eadf
18 changed files with 2296 additions and 1307 deletions
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")
+22 -15
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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/')
+12 -10
View File
@@ -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
![api-fuzzer-start-report](https://cloud.githubusercontent.com/assets/4301109/13615236/5d8df210-e59a-11e5-827a-ccf642e96609.png)
## 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
View File
@@ -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
View File
@@ -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())
File diff suppressed because one or more lines are too long
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");
+58 -3
View File
@@ -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>