mirror of
https://github.com/MobSF/Mobile-Security-Framework-MobSF.git
synced 2026-10-12 02:06:59 +00:00
[EFR05] Enterprise Feature Request: AAR and JAR support (#2163)
* AAR and JAR support
This commit is contained in:
@@ -15,7 +15,6 @@ Made with ](https://github.com/MobSF/Mobile-Security-Framework-MobSF/actions)
|
||||
[](https://pyup.io/repos/github/MobSF/Mobile-Security-Framework-MobSF/)
|
||||
[](https://lgtm.com/projects/g/MobSF/Mobile-Security-Framework-MobSF/context:python)
|
||||
[](https://sonarcloud.io/dashboard?id=MobSF_Mobile-Security-Framework-MobSF)
|
||||

|
||||
[](https://bestpractices.coreinfrastructure.org/projects/6392)
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ from mobsf.install.windows.setup import windows_config_local
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
VERSION = '3.6.5'
|
||||
VERSION = '3.6.6'
|
||||
BANNER = """
|
||||
__ __ _ ____ _____ _____ __
|
||||
| \/ | ___ | |__/ ___|| ___|_ _|___ / / /_
|
||||
|
||||
@@ -69,6 +69,8 @@ ALLOWED_EXTENSIONS = {
|
||||
'.tar': 'application/x-tar',
|
||||
'.apk': 'application/octet-stream',
|
||||
'.ipa': 'application/octet-stream',
|
||||
'.jar': 'application/java-archive',
|
||||
'.aar': 'application/octet-stream',
|
||||
}
|
||||
# =============ALLOWED MIMETYPES=================
|
||||
APK_MIME = [
|
||||
@@ -76,6 +78,7 @@ APK_MIME = [
|
||||
'application/vnd.android.package-archive',
|
||||
'application/x-zip-compressed',
|
||||
'binary/octet-stream',
|
||||
'application/java-archive',
|
||||
]
|
||||
IPA_MIME = [
|
||||
'application/iphone',
|
||||
|
||||
@@ -29,7 +29,9 @@ class FileType(object):
|
||||
or self.is_zip()
|
||||
or self.is_ipa()
|
||||
or self.is_appx()
|
||||
or self.is_apks()):
|
||||
or self.is_apks()
|
||||
or self.is_jar()
|
||||
or self.is_aar()):
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -45,6 +47,14 @@ class FileType(object):
|
||||
return (self.file_type in settings.APK_MIME
|
||||
and self.file_name_lower.endswith('.apk'))
|
||||
|
||||
def is_jar(self):
|
||||
return (self.file_type in settings.APK_MIME
|
||||
and self.file_name_lower.endswith('.jar'))
|
||||
|
||||
def is_aar(self):
|
||||
return (self.file_type in settings.APK_MIME
|
||||
and self.file_name_lower.endswith('.aar'))
|
||||
|
||||
def is_zip(self):
|
||||
return (self.file_type in settings.ZIP_MIME
|
||||
and self.file_name_lower.endswith('.zip'))
|
||||
|
||||
@@ -137,6 +137,10 @@ class Upload(object):
|
||||
return scanning.scan_xapk()
|
||||
elif self.file_type.is_apks():
|
||||
return scanning.scan_apks()
|
||||
elif self.file_type.is_jar():
|
||||
return scanning.scan_jar()
|
||||
elif self.file_type.is_aar():
|
||||
return scanning.scan_aar()
|
||||
elif self.file_type.is_zip():
|
||||
return scanning.scan_zip()
|
||||
elif self.file_type.is_ipa():
|
||||
|
||||
@@ -31,7 +31,7 @@ def add_to_recent_scan(data):
|
||||
logger.exception('Adding Scan URL to Database')
|
||||
|
||||
|
||||
def handle_uploaded_file(content, typ):
|
||||
def handle_uploaded_file(content, extension):
|
||||
"""Write Uploaded File."""
|
||||
md5 = hashlib.md5()
|
||||
bfr = isinstance(content, io.BufferedReader)
|
||||
@@ -47,7 +47,7 @@ def handle_uploaded_file(content, typ):
|
||||
anal_dir = os.path.join(settings.UPLD_DIR, md5sum + '/')
|
||||
if not os.path.exists(anal_dir):
|
||||
os.makedirs(anal_dir)
|
||||
with open(anal_dir + md5sum + typ, 'wb+') as destination:
|
||||
with open(f'{anal_dir}{md5sum}{extension}', 'wb+') as destination:
|
||||
if bfr:
|
||||
content.seek(0, 0)
|
||||
while chunk := content.read(8192):
|
||||
@@ -63,87 +63,84 @@ class Scanning(object):
|
||||
def __init__(self, request):
|
||||
self.file = request.FILES['file']
|
||||
self.file_name = request.FILES['file'].name
|
||||
self.data = {
|
||||
'analyzer': 'static_analyzer',
|
||||
'status': 'success',
|
||||
'hash': '',
|
||||
'scan_type': '',
|
||||
'file_name': self.file_name,
|
||||
}
|
||||
|
||||
def scan_apk(self):
|
||||
"""Android APK."""
|
||||
md5 = handle_uploaded_file(self.file, '.apk')
|
||||
data = {
|
||||
'analyzer': 'static_analyzer',
|
||||
'status': 'success',
|
||||
'hash': md5,
|
||||
'scan_type': 'apk',
|
||||
'file_name': self.file_name,
|
||||
}
|
||||
add_to_recent_scan(data)
|
||||
self.data['hash'] = md5
|
||||
self.data['scan_type'] = 'apk'
|
||||
add_to_recent_scan(self.data)
|
||||
logger.info('Performing Static Analysis of Android APK')
|
||||
return data
|
||||
return self.data
|
||||
|
||||
def scan_xapk(self):
|
||||
"""Android XAPK."""
|
||||
md5 = handle_uploaded_file(self.file, '.xapk')
|
||||
data = {
|
||||
'analyzer': 'static_analyzer',
|
||||
'status': 'success',
|
||||
'hash': md5,
|
||||
'scan_type': 'xapk',
|
||||
'file_name': self.file_name,
|
||||
}
|
||||
add_to_recent_scan(data)
|
||||
self.data['hash'] = md5
|
||||
self.data['scan_type'] = 'xapk'
|
||||
add_to_recent_scan(self.data)
|
||||
logger.info('Performing Static Analysis of Android XAPK base APK')
|
||||
return data
|
||||
return self.data
|
||||
|
||||
def scan_apks(self):
|
||||
"""Android Split APK."""
|
||||
md5 = handle_uploaded_file(self.file, '.apk')
|
||||
data = {
|
||||
'analyzer': 'static_analyzer',
|
||||
'status': 'success',
|
||||
'hash': md5,
|
||||
'scan_type': 'apks',
|
||||
'file_name': self.file_name,
|
||||
}
|
||||
add_to_recent_scan(data)
|
||||
self.data['hash'] = md5
|
||||
self.data['scan_type'] = 'apks'
|
||||
add_to_recent_scan(self.data)
|
||||
logger.info('Performing Static Analysis of Android Split APK')
|
||||
return data
|
||||
return self.data
|
||||
|
||||
def scan_jar(self):
|
||||
"""Java JAR file."""
|
||||
md5 = handle_uploaded_file(self.file, '.jar')
|
||||
self.data['hash'] = md5
|
||||
self.data['scan_type'] = 'jar'
|
||||
add_to_recent_scan(self.data)
|
||||
logger.info('Performing Static Analysis of Java JAR')
|
||||
return self.data
|
||||
|
||||
def scan_aar(self):
|
||||
"""Android AAR file."""
|
||||
md5 = handle_uploaded_file(self.file, '.aar')
|
||||
self.data['hash'] = md5
|
||||
self.data['scan_type'] = 'aar'
|
||||
add_to_recent_scan(self.data)
|
||||
logger.info('Performing Static Analysis of Android AAR')
|
||||
return self.data
|
||||
|
||||
def scan_zip(self):
|
||||
"""Android /iOS Zipped Source."""
|
||||
md5 = handle_uploaded_file(self.file, '.zip')
|
||||
data = {
|
||||
'analyzer': 'static_analyzer',
|
||||
'status': 'success',
|
||||
'hash': md5,
|
||||
'scan_type': 'zip',
|
||||
'file_name': self.file_name,
|
||||
}
|
||||
add_to_recent_scan(data)
|
||||
self.data['hash'] = md5
|
||||
self.data['scan_type'] = 'zip'
|
||||
add_to_recent_scan(self.data)
|
||||
logger.info('Performing Static Analysis of Android/iOS Source Code')
|
||||
return data
|
||||
return self.data
|
||||
|
||||
def scan_ipa(self):
|
||||
"""IOS Binary."""
|
||||
md5 = handle_uploaded_file(self.file, '.ipa')
|
||||
data = {
|
||||
'analyzer': 'static_analyzer_ios',
|
||||
'hash': md5,
|
||||
'scan_type': 'ipa',
|
||||
'file_name': self.file_name,
|
||||
'status': 'success',
|
||||
}
|
||||
add_to_recent_scan(data)
|
||||
self.data['hash'] = md5
|
||||
self.data['scan_type'] = 'ipa'
|
||||
self.data['analyzer'] = 'static_analyzer_ios'
|
||||
add_to_recent_scan(self.data)
|
||||
logger.info('Performing Static Analysis of iOS IPA')
|
||||
return data
|
||||
return self.data
|
||||
|
||||
def scan_appx(self):
|
||||
"""Windows appx."""
|
||||
md5 = handle_uploaded_file(self.file, '.appx')
|
||||
data = {
|
||||
'analyzer': 'static_analyzer_windows',
|
||||
'hash': md5,
|
||||
'scan_type': 'appx',
|
||||
'file_name': self.file_name,
|
||||
'status': 'success',
|
||||
}
|
||||
add_to_recent_scan(data)
|
||||
self.data['hash'] = md5
|
||||
self.data['scan_type'] = 'appx'
|
||||
self.data['analyzer'] = 'static_analyzer_windows'
|
||||
add_to_recent_scan(self.data)
|
||||
logger.info('Performing Static Analysis of Windows APP')
|
||||
return data
|
||||
return self.data
|
||||
|
||||
@@ -64,7 +64,9 @@ class AndroidChecks(forms.Form):
|
||||
('studio', 'studio'),
|
||||
('java', 'java'),
|
||||
('smali', 'smali'),
|
||||
('apk', 'apk')))
|
||||
('apk', 'apk'),
|
||||
('jar', 'jar'),
|
||||
('aar', 'aar')))
|
||||
|
||||
def clean_file(self):
|
||||
"""Safe Extension."""
|
||||
|
||||
@@ -58,6 +58,7 @@ def cert_info(app_dir, app_file, man_dict):
|
||||
manidat = ''
|
||||
cert_info = ''
|
||||
certlist = []
|
||||
files = []
|
||||
summary = {HIGH: 0, WARNING: 0, INFO: 0}
|
||||
cert_path = os.path.join(app_dir, 'META-INF/')
|
||||
|
||||
@@ -68,8 +69,9 @@ def cert_info(app_dir, app_file, man_dict):
|
||||
'sha256': hashlib.sha256,
|
||||
'sha512': hashlib.sha512,
|
||||
}
|
||||
files = [f for f in os.listdir(
|
||||
cert_path) if os.path.isfile(os.path.join(cert_path, f))]
|
||||
if os.path.exists(cert_path):
|
||||
files = [f for f in os.listdir(
|
||||
cert_path) if os.path.isfile(os.path.join(cert_path, f))]
|
||||
a = APK(apk_file)
|
||||
if a.is_signed():
|
||||
certlist.append('APK is signed')
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
"""Generate Zipped downloads."""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
|
||||
from django.conf import settings
|
||||
from django.shortcuts import redirect
|
||||
@@ -15,39 +15,43 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def run(request):
|
||||
"""Generate downloads for apk, java and smali."""
|
||||
"""Generate downloads for apk, jar, aar, java zip and smali zip."""
|
||||
try:
|
||||
allowed = ('apk', 'smali', 'java', 'jar', 'aar')
|
||||
logger.info('Generating Downloads')
|
||||
md5 = request.GET['hash']
|
||||
file_type = request.GET['file_type']
|
||||
match = re.match('^[0-9a-f]{32}$', md5)
|
||||
if not match and file_type not in ['apk', 'smali', 'java']:
|
||||
logger.exception('Invalid options')
|
||||
return print_n_send_error_response(request,
|
||||
'Invalid options')
|
||||
app_dir = os.path.join(settings.UPLD_DIR, md5)
|
||||
if (not match
|
||||
or file_type not in allowed):
|
||||
msg = 'Invalid download type or hash'
|
||||
logger.exception(msg)
|
||||
return print_n_send_error_response(request, msg)
|
||||
app_dir = Path(settings.UPLD_DIR) / md5
|
||||
dwd_dir = Path(settings.DWD_DIR)
|
||||
file_name = ''
|
||||
if file_type == 'java':
|
||||
# For Java
|
||||
file_name = md5 + '-java'
|
||||
directory = os.path.join(app_dir, 'java_source/')
|
||||
dwd_dir = os.path.join(settings.DWD_DIR, file_name)
|
||||
shutil.make_archive(dwd_dir, 'zip', directory)
|
||||
file_name = file_name + '.zip'
|
||||
# For Java zipped source code
|
||||
directory = app_dir / 'java_source'
|
||||
dwd_file = dwd_dir / f'{md5}-java'
|
||||
shutil.make_archive(
|
||||
dwd_file.as_posix(), 'zip', directory.as_posix())
|
||||
file_name = f'{md5}-java.zip'
|
||||
elif file_type == 'smali':
|
||||
# For Smali
|
||||
file_name = md5 + '-smali'
|
||||
directory = os.path.join(app_dir, 'smali_source/')
|
||||
dwd_dir = os.path.join(settings.DWD_DIR, file_name)
|
||||
shutil.make_archive(dwd_dir, 'zip', directory)
|
||||
file_name = file_name + '.zip'
|
||||
elif file_type in ('apk', 'ipa'):
|
||||
# For Smali zipped source code
|
||||
directory = app_dir / 'smali_source'
|
||||
dwd_file = dwd_dir / f'{md5}-smali'
|
||||
shutil.make_archive(
|
||||
dwd_file.as_posix(), 'zip', directory.as_posix())
|
||||
file_name = f'{md5}-smali.zip'
|
||||
elif file_type in ('apk', 'ipa', 'jar', 'aar'):
|
||||
# Binaries
|
||||
file_name = f'{md5}.{file_type}'
|
||||
src = os.path.join(app_dir, file_name)
|
||||
dst = os.path.join(settings.DWD_DIR, file_name)
|
||||
shutil.copy2(src, dst)
|
||||
return redirect('/download/' + file_name)
|
||||
src = app_dir / file_name
|
||||
dst = dwd_dir / file_name
|
||||
shutil.copy2(src.as_posix(), dst.as_posix())
|
||||
return redirect(f'/download/{file_name}')
|
||||
except Exception:
|
||||
logger.exception('Generating Downloads')
|
||||
return print_n_send_error_response(request,
|
||||
'Generating Downloads')
|
||||
msg = 'Generating Downloads'
|
||||
logger.exception(msg)
|
||||
return print_n_send_error_response(request, msg)
|
||||
|
||||
@@ -0,0 +1,249 @@
|
||||
"""Handle JAR and AAR files."""
|
||||
import logging
|
||||
|
||||
from django.conf import settings
|
||||
from django.shortcuts import render
|
||||
|
||||
import mobsf.MalwareAnalyzer.views.Trackers as Trackers
|
||||
import mobsf.MalwareAnalyzer.views.VirusTotal as VirusTotal
|
||||
from mobsf.MobSF.utils import (
|
||||
file_size,
|
||||
print_n_send_error_response,
|
||||
)
|
||||
from mobsf.StaticAnalyzer.views.common.shared_func import (
|
||||
firebase_analysis,
|
||||
get_avg_cvss,
|
||||
hash_gen,
|
||||
unzip,
|
||||
update_scan_timestamp,
|
||||
)
|
||||
from mobsf.StaticAnalyzer.views.common.appsec import (
|
||||
get_android_dashboard,
|
||||
)
|
||||
from mobsf.StaticAnalyzer.views.android.manifest_analysis import (
|
||||
get_manifest,
|
||||
manifest_analysis,
|
||||
manifest_data,
|
||||
)
|
||||
from mobsf.StaticAnalyzer.views.android.strings import strings_from_apk
|
||||
from mobsf.StaticAnalyzer.views.android.cert_analysis import (
|
||||
cert_info,
|
||||
get_hardcoded_cert_keystore,
|
||||
)
|
||||
from mobsf.StaticAnalyzer.models import (
|
||||
StaticAnalyzerAndroid,
|
||||
)
|
||||
from mobsf.StaticAnalyzer.views.android.code_analysis import code_analysis
|
||||
from mobsf.StaticAnalyzer.views.android.converter import (
|
||||
apk_2_java,
|
||||
)
|
||||
from mobsf.StaticAnalyzer.views.android.db_interaction import (
|
||||
get_context_from_analysis,
|
||||
get_context_from_db_entry,
|
||||
save_or_update,
|
||||
)
|
||||
from mobsf.MalwareAnalyzer.views.MalwareDomainCheck import MalwareDomainCheck
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def common_analysis(request, app_dic, rescan, api, analysis_type):
|
||||
app_dic['app_file'] = f'{app_dic["md5"]}.{analysis_type}' # NEW FILENAME
|
||||
app_dic['app_path'] = (app_dic['app_dir'] / app_dic['app_file']).as_posix()
|
||||
app_dic['app_dir'] = app_dic['app_dir'].as_posix() + '/'
|
||||
db_entry = StaticAnalyzerAndroid.objects.filter(MD5=app_dic['md5'])
|
||||
if db_entry.exists() and not rescan:
|
||||
context = get_context_from_db_entry(db_entry)
|
||||
else:
|
||||
app_dic['size'] = f'{str(file_size(app_dic["app_path"]))}MB'
|
||||
app_dic['sha1'], app_dic['sha256'] = hash_gen(app_dic['app_path'])
|
||||
app_dic['files'] = unzip(app_dic['app_path'], app_dic['app_dir'])
|
||||
logger.info('%s Extracted', analysis_type.upper())
|
||||
if not app_dic['files']:
|
||||
return print_n_send_error_response(
|
||||
request,
|
||||
f'{analysis_type.upper()} file is invalid or corrupt',
|
||||
api)
|
||||
app_dic['certz'] = get_hardcoded_cert_keystore(app_dic['files'])
|
||||
app_dic['playstore'] = {'error': True}
|
||||
if analysis_type == 'aar':
|
||||
# AAR has manifest and sometimes certificate
|
||||
app_dic['manifest_file'], app_dic['parsed_xml'] = get_manifest(
|
||||
app_dic['app_path'],
|
||||
app_dic['app_dir'],
|
||||
app_dic['tools_dir'],
|
||||
'aar',
|
||||
)
|
||||
app_dic['mani'] = (
|
||||
f'../manifest_view/?md5={app_dic["md5"]}&type=aar')
|
||||
man_data_dic = manifest_data(app_dic['parsed_xml'])
|
||||
man_an_dic = manifest_analysis(
|
||||
app_dic['parsed_xml'],
|
||||
man_data_dic,
|
||||
'',
|
||||
app_dic['app_dir'],
|
||||
)
|
||||
cert_dic = cert_info(
|
||||
app_dic['app_dir'],
|
||||
app_dic['app_file'],
|
||||
man_data_dic)
|
||||
else:
|
||||
app_dic['manifest_file'] = None
|
||||
app_dic['parsed_xml'] = ''
|
||||
app_dic['mani'] = ''
|
||||
man_data_dic = {
|
||||
'services': [],
|
||||
'activities': [],
|
||||
'receivers': [],
|
||||
'providers': [],
|
||||
'libraries': [],
|
||||
'categories': [],
|
||||
'perm': {},
|
||||
'packagename': app_dic['app_name'],
|
||||
'mainactivity': '',
|
||||
'min_sdk': '',
|
||||
'max_sdk': '',
|
||||
'target_sdk': '',
|
||||
'androver': '',
|
||||
'androvername': '',
|
||||
'icons': [],
|
||||
}
|
||||
man_an_dic = {
|
||||
'manifest_anal': [],
|
||||
'exported_act': [],
|
||||
'exported_cnt': {
|
||||
'exported_activities': 0,
|
||||
'exported_services': 0,
|
||||
'exported_receivers': 0,
|
||||
'exported_providers': 0,
|
||||
},
|
||||
'browsable_activities': {},
|
||||
'permissions': {},
|
||||
'icon_hidden': True,
|
||||
'network_security': {
|
||||
'network_findings': [],
|
||||
'network_summary': {},
|
||||
},
|
||||
}
|
||||
cert_dic = {
|
||||
'certificate_info': '',
|
||||
'certificate_findings': [],
|
||||
'certificate_summary': {},
|
||||
}
|
||||
app_dic['real_name'] = ''
|
||||
elf_dict = {
|
||||
'elf_analysis': [],
|
||||
'elf_strings': [],
|
||||
}
|
||||
apkid_results = {}
|
||||
tracker = Trackers.Trackers(
|
||||
app_dic['app_dir'],
|
||||
app_dic['tools_dir'])
|
||||
tracker_res = tracker.get_trackers()
|
||||
|
||||
apk_2_java(
|
||||
app_dic['app_path'],
|
||||
app_dic['app_dir'],
|
||||
app_dic['tools_dir'])
|
||||
|
||||
code_an_dic = code_analysis(
|
||||
app_dic['app_dir'],
|
||||
'apk',
|
||||
app_dic['manifest_file'])
|
||||
|
||||
quark_results = []
|
||||
|
||||
# Get the strings from android resource and shared objects
|
||||
string_res = strings_from_apk(
|
||||
app_dic['app_file'],
|
||||
app_dic['app_dir'],
|
||||
elf_dict['elf_strings'])
|
||||
if string_res:
|
||||
app_dic['strings'] = string_res['strings']
|
||||
app_dic['secrets'] = string_res['secrets']
|
||||
code_an_dic['urls_list'].extend(
|
||||
string_res['urls_list'])
|
||||
code_an_dic['urls'].extend(string_res['url_nf'])
|
||||
code_an_dic['emails'].extend(string_res['emails_nf'])
|
||||
else:
|
||||
app_dic['strings'] = []
|
||||
app_dic['secrets'] = []
|
||||
# Firebase DB Check
|
||||
code_an_dic['firebase'] = firebase_analysis(
|
||||
list(set(code_an_dic['urls_list'])))
|
||||
# Domain Extraction and Malware Check
|
||||
logger.info(
|
||||
'Performing Malware Check on extracted Domains')
|
||||
code_an_dic['domains'] = MalwareDomainCheck().scan(
|
||||
list(set(code_an_dic['urls_list'])))
|
||||
app_dic['zipped'] = analysis_type
|
||||
app_dic['icon_hidden'] = True
|
||||
app_dic['icon_found'] = False
|
||||
logger.info('Connecting to Database')
|
||||
try:
|
||||
# SAVE TO DB
|
||||
if rescan:
|
||||
logger.info('Updating Database...')
|
||||
save_or_update(
|
||||
'update',
|
||||
app_dic,
|
||||
man_data_dic,
|
||||
man_an_dic,
|
||||
code_an_dic,
|
||||
cert_dic,
|
||||
elf_dict['elf_analysis'],
|
||||
apkid_results,
|
||||
quark_results,
|
||||
tracker_res,
|
||||
)
|
||||
update_scan_timestamp(app_dic['md5'])
|
||||
else:
|
||||
logger.info('Saving to Database')
|
||||
save_or_update(
|
||||
'save',
|
||||
app_dic,
|
||||
man_data_dic,
|
||||
man_an_dic,
|
||||
code_an_dic,
|
||||
cert_dic,
|
||||
elf_dict['elf_analysis'],
|
||||
apkid_results,
|
||||
quark_results,
|
||||
tracker_res,
|
||||
)
|
||||
except Exception:
|
||||
logger.exception('Saving to Database Failed')
|
||||
context = get_context_from_analysis(
|
||||
app_dic,
|
||||
man_data_dic,
|
||||
man_an_dic,
|
||||
code_an_dic,
|
||||
cert_dic,
|
||||
elf_dict['elf_analysis'],
|
||||
apkid_results,
|
||||
quark_results,
|
||||
tracker_res,
|
||||
)
|
||||
context['appsec'] = get_android_dashboard(context, True)
|
||||
context['average_cvss'] = get_avg_cvss(
|
||||
context['code_analysis'])
|
||||
context['dynamic_analysis_done'] = False
|
||||
context['virus_total'] = None
|
||||
if settings.VT_ENABLED:
|
||||
vt = VirusTotal.VirusTotal()
|
||||
context['virus_total'] = vt.get_result(
|
||||
app_dic['app_path'],
|
||||
app_dic['md5'])
|
||||
template = 'static_analysis/android_binary_analysis.html'
|
||||
if api:
|
||||
return context
|
||||
else:
|
||||
return render(request, template, context)
|
||||
|
||||
|
||||
def jar_analysis(request, app_dic, rescan, api):
|
||||
return common_analysis(request, app_dic, rescan, api, 'jar')
|
||||
|
||||
|
||||
def aar_analysis(request, app_dic, rescan, api):
|
||||
return common_analysis(request, app_dic, rescan, api, 'aar')
|
||||
@@ -28,17 +28,16 @@ logger = logging.getLogger(__name__)
|
||||
ANDROID_4_2_LEVEL = 17
|
||||
ANDROID_5_0_LEVEL = 21
|
||||
ANDROID_8_0_LEVEL = 26
|
||||
ANDROID_MANIFEST_FILE = 'AndroidManifest.xml'
|
||||
|
||||
|
||||
def get_manifest(app_path, app_dir, tools_dir, typ, binary):
|
||||
def get_manifest(app_path, app_dir, tools_dir, typ):
|
||||
"""Get the manifest file."""
|
||||
try:
|
||||
manifest_file = get_manifest_file(
|
||||
app_dir,
|
||||
app_path,
|
||||
tools_dir,
|
||||
typ,
|
||||
binary)
|
||||
typ)
|
||||
mfile = Path(manifest_file)
|
||||
if mfile.exists():
|
||||
manifest = mfile.read_text('utf-8', 'ignore')
|
||||
@@ -862,21 +861,24 @@ def manifest_analysis(mfxml, man_data_dic, src_type, app_dir):
|
||||
logger.exception('Performing Manifest Analysis')
|
||||
|
||||
|
||||
def get_manifest_file(app_dir, app_path, tools_dir, typ, apk):
|
||||
def get_manifest_file(app_dir, app_path, tools_dir, typ):
|
||||
"""Read the manifest file."""
|
||||
try:
|
||||
manifest = ''
|
||||
if apk:
|
||||
if typ == 'aar':
|
||||
logger.info('Getting AndroidManifest.xml from AAR')
|
||||
manifest = os.path.join(app_dir, ANDROID_MANIFEST_FILE)
|
||||
elif typ == 'apk':
|
||||
logger.info('Getting AndroidManifest.xml from APK')
|
||||
manifest = get_manifest_apk(app_path, app_dir, tools_dir)
|
||||
else:
|
||||
logger.info('Getting AndroidManifest.xml from Source Code')
|
||||
if typ == 'eclipse':
|
||||
manifest = os.path.join(app_dir, 'AndroidManifest.xml')
|
||||
manifest = os.path.join(app_dir, ANDROID_MANIFEST_FILE)
|
||||
elif typ == 'studio':
|
||||
manifest = os.path.join(
|
||||
app_dir,
|
||||
'app/src/main/AndroidManifest.xml')
|
||||
f'app/src/main/{ANDROID_MANIFEST_FILE}')
|
||||
return manifest
|
||||
except Exception:
|
||||
logger.exception('Getting AndroidManifest.xml file')
|
||||
@@ -905,7 +907,7 @@ def get_manifest_apk(app_path, app_dir, tools_dir):
|
||||
app_path,
|
||||
'-o',
|
||||
output_dir]
|
||||
manifest = os.path.join(output_dir, 'AndroidManifest.xml')
|
||||
manifest = os.path.join(output_dir, ANDROID_MANIFEST_FILE)
|
||||
if is_file_exists(manifest):
|
||||
# APKTool already created readable XML
|
||||
return manifest
|
||||
|
||||
@@ -23,26 +23,18 @@ def run(request):
|
||||
directory = settings.BASE_DIR # BASE DIR
|
||||
md5 = request.GET['md5'] # MD5
|
||||
typ = request.GET['type'] # APK or SOURCE
|
||||
binary = request.GET['bin']
|
||||
match = re.match('^[0-9a-f]{32}$', md5)
|
||||
if (match
|
||||
and (typ in ['eclipse', 'studio', 'apk'])
|
||||
and (binary in ['1', '0'])):
|
||||
if match and (typ in ['eclipse', 'studio', 'apk', 'aar']):
|
||||
app_dir = os.path.join(
|
||||
settings.UPLD_DIR, md5 + '/') # APP DIRECTORY
|
||||
tools_dir = os.path.join(
|
||||
directory, 'StaticAnalyzer/tools/') # TOOLS DIR
|
||||
if binary == '1':
|
||||
is_binary = True
|
||||
elif binary == '0':
|
||||
is_binary = False
|
||||
app_path = os.path.join(app_dir, md5 + '.apk')
|
||||
manifest_file = get_manifest_file(
|
||||
app_dir,
|
||||
app_path,
|
||||
tools_dir,
|
||||
typ,
|
||||
is_binary)
|
||||
typ)
|
||||
mfile = Path(manifest_file)
|
||||
if mfile.exists():
|
||||
manifest = mfile.read_text('utf-8', 'ignore')
|
||||
|
||||
@@ -60,6 +60,10 @@ from mobsf.StaticAnalyzer.views.android.xapk import (
|
||||
handle_split_apk,
|
||||
handle_xapk,
|
||||
)
|
||||
from mobsf.StaticAnalyzer.views.android.jar_aar import (
|
||||
aar_analysis,
|
||||
jar_analysis,
|
||||
)
|
||||
from mobsf.StaticAnalyzer.views.common.shared_func import (
|
||||
firebase_analysis,
|
||||
get_avg_cvss,
|
||||
@@ -101,8 +105,8 @@ def static_analyzer(request, api=False):
|
||||
match = re.match('^[0-9a-f]{32}$', checksum)
|
||||
if (match
|
||||
and filename.lower().endswith(
|
||||
('.apk', '.xapk', '.zip', '.apks'))
|
||||
and typ in ['zip', 'apk', 'xapk', 'apks']):
|
||||
('.apk', '.xapk', '.zip', '.apks', '.jar', '.aar'))
|
||||
and typ in ['zip', 'apk', 'xapk', 'apks', 'jar', 'aar']):
|
||||
app_dic['dir'] = Path(settings.BASE_DIR) # BASE DIR
|
||||
app_dic['app_name'] = filename # APP ORIGINAL NAME
|
||||
app_dic['md5'] = checksum # MD5
|
||||
@@ -145,17 +149,10 @@ def static_analyzer(request, api=False):
|
||||
logger.info('APK Extracted')
|
||||
if not app_dic['files']:
|
||||
# Can't Analyze APK, bail out.
|
||||
msg = 'APK file is invalid or corrupt'
|
||||
if api:
|
||||
return print_n_send_error_response(
|
||||
request,
|
||||
msg,
|
||||
True)
|
||||
else:
|
||||
return print_n_send_error_response(
|
||||
request,
|
||||
msg,
|
||||
False)
|
||||
return print_n_send_error_response(
|
||||
request,
|
||||
'APK file is invalid or corrupt',
|
||||
api)
|
||||
app_dic['certz'] = get_hardcoded_cert_keystore(app_dic[
|
||||
'files'])
|
||||
# Manifest XML
|
||||
@@ -163,8 +160,7 @@ def static_analyzer(request, api=False):
|
||||
app_dic['app_path'],
|
||||
app_dic['app_dir'],
|
||||
app_dic['tools_dir'],
|
||||
'',
|
||||
True,
|
||||
'apk',
|
||||
)
|
||||
app_dic['manifest_file'] = mani_file
|
||||
app_dic['parsed_xml'] = mani_xml
|
||||
@@ -173,7 +169,6 @@ def static_analyzer(request, api=False):
|
||||
app_dic['real_name'] = get_app_name(
|
||||
app_dic['app_path'],
|
||||
app_dic['app_dir'],
|
||||
app_dic['tools_dir'],
|
||||
True,
|
||||
)
|
||||
|
||||
@@ -182,9 +177,8 @@ def static_analyzer(request, api=False):
|
||||
get_icon_apk(app_dic)
|
||||
|
||||
# Set Manifest link
|
||||
app_dic['mani'] = ('../manifest_view/?md5='
|
||||
+ app_dic['md5']
|
||||
+ '&type=apk&bin=1')
|
||||
app_dic['mani'] = (
|
||||
f'../manifest_view/?md5={app_dic["md5"]}&type=apk')
|
||||
man_data_dic = manifest_data(app_dic['parsed_xml'])
|
||||
app_dic['playstore'] = get_app_details(
|
||||
man_data_dic['packagename'])
|
||||
@@ -306,6 +300,10 @@ def static_analyzer(request, api=False):
|
||||
return context
|
||||
else:
|
||||
return render(request, template, context)
|
||||
elif typ == 'jar':
|
||||
return jar_analysis(request, app_dic, rescan, api)
|
||||
elif typ == 'aar':
|
||||
return aar_analysis(request, app_dic, rescan, api)
|
||||
elif typ == 'zip':
|
||||
ret = (
|
||||
'/static_analyzer_ios/?name='
|
||||
@@ -369,7 +367,6 @@ def static_analyzer(request, api=False):
|
||||
app_dic['app_dir'],
|
||||
app_dic['tools_dir'],
|
||||
pro_type,
|
||||
False,
|
||||
)
|
||||
app_dic['manifest_file'] = mani_file
|
||||
app_dic['parsed_xml'] = mani_xml
|
||||
@@ -378,17 +375,13 @@ def static_analyzer(request, api=False):
|
||||
app_dic['real_name'] = get_app_name(
|
||||
app_dic['app_path'],
|
||||
app_dic['app_dir'],
|
||||
app_dic['tools_dir'],
|
||||
False,
|
||||
)
|
||||
|
||||
# Set manifest view link
|
||||
app_dic['mani'] = (
|
||||
'../manifest_view/?md5='
|
||||
+ app_dic['md5'] + '&type='
|
||||
+ pro_type + '&bin=0'
|
||||
)
|
||||
|
||||
f'../manifest_view/?md5={app_dic["md5"]}'
|
||||
f'&type={pro_type}')
|
||||
man_data_dic = manifest_data(app_dic['parsed_xml'])
|
||||
app_dic['playstore'] = get_app_details(
|
||||
man_data_dic['packagename'])
|
||||
@@ -513,7 +506,7 @@ def static_analyzer(request, api=False):
|
||||
else:
|
||||
return render(request, template, context)
|
||||
else:
|
||||
err = ('Only APK,IPA and Zipped '
|
||||
err = ('Only APK, JAR, AAR, IPA and Zipped '
|
||||
'Android/iOS Source code supported now!')
|
||||
logger.error(err)
|
||||
else:
|
||||
@@ -591,7 +584,7 @@ def move_to_parent(inside, app_dir):
|
||||
shutil.rmtree(inside)
|
||||
|
||||
|
||||
def get_app_name(app_path, app_dir, tools_dir, is_apk):
|
||||
def get_app_name(app_path, app_dir, is_apk):
|
||||
"""Get app name."""
|
||||
if is_apk:
|
||||
a = apk.APK(app_path)
|
||||
|
||||
@@ -28,7 +28,7 @@ logger = logging.getLogger(__name__)
|
||||
def run(request, api=False):
|
||||
"""View the source of a file."""
|
||||
try:
|
||||
logger.info('View Android Source File')
|
||||
logger.info('View Java Source File')
|
||||
exp = 'Error Description'
|
||||
if api:
|
||||
fil = request.POST['file']
|
||||
|
||||
+2
-2
File diff suppressed because one or more lines are too long
@@ -225,10 +225,10 @@
|
||||
// Is valid file extensions
|
||||
function isValidExt(file_name){
|
||||
var val = file_name.toLowerCase();
|
||||
var regex = new RegExp("(.*?)\.(ipa|apk|apks|xapk|zip|appx)$");
|
||||
var regex = new RegExp("(.*?)\.(ipa|apk|apks|xapk|jar|aar|zip|appx)$");
|
||||
val = val.replace(/^.*[\\\/]/, '');
|
||||
if (!(regex.test(val))) {
|
||||
_('status').innerText = "Please upload APK/APKS/XAPK/IPA/ZIP/APPX only!";
|
||||
_('status').innerText = "Please upload APK/APKS/XAPK/JAR/AAR/IPA/ZIP/APPX only!";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -74,6 +74,8 @@
|
||||
{% if '.apk' == e.FILE_NAME|slice:"-4:"%}<i class="fab fa-android fa-3x"></i>
|
||||
{% elif '.xapk' == e.FILE_NAME|slice:"-5:"%}<i class="fab fa-android fa-3x"></i>
|
||||
{% elif '.apks' == e.FILE_NAME|slice:"-5:"%}<i class="fab fa-android fa-3x"></i>
|
||||
{% elif '.jar' == e.FILE_NAME|slice:"-4:"%}<i class="fab fa-java fa-3x"></i>
|
||||
{% elif '.aar' == e.FILE_NAME|slice:"-4:"%}<i class="fas fa-table fa-3x"></i>
|
||||
{% elif '.ipa' == e.FILE_NAME|slice:"-4:"%}<i class="fab fa-apple fa-3x"></i>
|
||||
{% elif '.zip' == e.FILE_NAME|slice:"-4:"%}<i class="fas fa-file-archive fa-3x"></i>
|
||||
{% elif '.appx' == e.FILE_NAME|slice:"-5:"%}<i class="fab fa-windows fa-3x"></i>
|
||||
|
||||
@@ -182,7 +182,8 @@
|
||||
<h5>Max SDK:</h5> {{ max_sdk }}</br>
|
||||
<h5>Android Version Name:</h5> {{ version_name }}</br>
|
||||
<h5>Android Version Code:</h5> {{ version_code }}</br>
|
||||
|
||||
|
||||
{% if app_type not in 'jar,aar' %}
|
||||
<h2><i class="fas fa-th-large"></i> APP COMPONENTS </h2>
|
||||
|
||||
<h5>Activities:</h5> {{ activities | length }}</br>
|
||||
@@ -193,7 +194,7 @@
|
||||
<h5>Exported Services:</h5> <span {% if exported_count.exported_services > 0 %} class="danger" {% endif %}> {{ exported_count.exported_services }}</span></br>
|
||||
<h5>Exported Receivers:</h5> <span {% if exported_count.exported_receivers > 0 %} class="danger" {% endif %}> {{ exported_count.exported_receivers }}</span></br>
|
||||
<h5>Exported Providers:</h5> <span {% if exported_count.exported_providers > 0 %} class="danger" {% endif %}> {{ exported_count.exported_providers }}</span></br>
|
||||
|
||||
{% endif %}
|
||||
<h2><i class="fa fa-certificate"></i> CERTIFICATE INFORMATION</h2>
|
||||
{% if certificate_analysis.certificate_info %}
|
||||
<div class="panel-body">
|
||||
@@ -238,7 +239,6 @@
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if virus_total and virus_total.items|length > 9 and 'request successfully queued' not in virus_total.verbose_msg %}
|
||||
<h2><i class="fas fa-spider"></i> VIRUSTOTAL SCAN</h2>
|
||||
|
||||
@@ -328,6 +328,7 @@
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
{% if app_type not in 'jar,aar' %}
|
||||
<li class="nav-item">
|
||||
<a onclick="dynamic_loader()" href="../android_dynamic/{{md5}}" class="nav-link">
|
||||
<i class="nav-icon fa fa-play-circle"></i>
|
||||
@@ -336,6 +337,7 @@
|
||||
</p>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</ul>
|
||||
</nav>
|
||||
@@ -484,6 +486,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if app_type not in 'jar,aar' %}
|
||||
<!-- Boxes -->
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
@@ -619,10 +622,9 @@
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
{% endif %}
|
||||
<!-- =========================end information==================================== -->
|
||||
|
||||
|
||||
|
||||
<a id="scan_options" class="anchor"></a>
|
||||
<section class="content">
|
||||
<div class="container-fluid">
|
||||
@@ -633,12 +635,14 @@
|
||||
<p>
|
||||
<strong><i class="fas fa-cog"></i> SCAN OPTIONS</strong>
|
||||
</p>
|
||||
<p> <a href="../static_analyzer/?checksum={{ md5 }}&name={{ file_name }}&type=apk&rescan=1" class="btn btn-info" role="button"><i class="fa fa-sync"></i> Rescan</a>
|
||||
<p> <a href="../static_analyzer/?checksum={{ md5 }}&name={{ file_name }}&type={{ app_type }}&rescan=1" class="btn btn-info" role="button"><i class="fa fa-sync"></i> Rescan</a>
|
||||
<a id="supbtn" onclick="list_suppressions()" role="button" class="btn btn-primary" data-target="#sup_list" data-toggle="modal" href="#"><i class="fa fa-list"></i> Manage Suppressions</a>
|
||||
</p>
|
||||
{% if app_type not in 'jar,aar' %}
|
||||
<p>
|
||||
<a onclick="dynamic_loader()" href="../android_dynamic/{{md5}}" class="btn btn-success" role="button"><i class="fa fa-play-circle"></i> Start Dynamic Analysis</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div><!-- /.card -->
|
||||
</div>
|
||||
@@ -649,14 +653,20 @@
|
||||
<strong><i class="fas fa-file-code"></i> DECOMPILED CODE</strong>
|
||||
</p>
|
||||
<p>
|
||||
<a target="_blank" href="../manifest_view/?md5={{ md5 }}&type={{ app_type }}&bin=1" role="button" class="btn btn-primary"><i class="fa fa-eye"></i> View AndroidManifest.xml</a>
|
||||
{% if app_type not in 'jar' %}
|
||||
<a target="_blank" href="../manifest_view/?md5={{ md5 }}&type={{ app_type }}" role="button" class="btn btn-primary"><i class="fa fa-eye"></i> View AndroidManifest.xml</a>
|
||||
{% endif %}
|
||||
<a href="{% url "tree_view" %}?md5={{ md5 }}&type=java" class="btn btn-info" role="button"><i class="fa fa-code"></i> View Source</a>
|
||||
{% if app_type not in 'jar,aar' %}
|
||||
<a href="{% url "tree_view" %}?md5={{ md5 }}&type=smali" class="btn btn-info" role="button"><i class="fa fa-code"></i> View Smali</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
<p>
|
||||
<a href="../generate_downloads/?hash={{ md5 }}&file_type=java" class="btn btn-warning" role="button"> <i class="fa fa-download"></i> Download Java Code</a>
|
||||
{% if app_type not in 'jar,aar' %}
|
||||
<a href="../generate_downloads/?hash={{ md5 }}&file_type=smali" class="btn btn-warning"> <i class="fa fa-download"></i> Download Smali Code</a>
|
||||
<a href="../generate_downloads/?hash={{ md5 }}&file_type=apk" class="btn btn-warning"> <i class="fa fa-download"></i> Download APK</a>
|
||||
{% endif %}
|
||||
<a href="../generate_downloads/?hash={{ md5 }}&file_type={{ app_type }}" class="btn btn-warning"> <i class="fa fa-download"></i> Download {{ app_type | upper}}</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -535,7 +535,7 @@
|
||||
<p align="center">
|
||||
<a href="../static_analyzer/?checksum={{ md5 }}&name={{ file_name }}&type=zip&rescan=1" class="btn btn-info" role="button"><i class="fa fa-sync"></i> Rescan</a>
|
||||
<a id="supbtn" onclick="list_suppressions()" role="button" class="btn btn-primary" data-target="#sup_list" data-toggle="modal" href="#"><i class="fa fa-list"></i> Manage Suppressions</a>
|
||||
<a target="_blank" href="../manifest_view/?md5={{ md5 }}&type={{ app_type }}&bin=0" role="button" class="btn btn-primary"><i class="fa fa-eye"></i> View AndroidManifest.xml</a>
|
||||
<a target="_blank" href="../manifest_view/?md5={{ md5 }}&type={{ app_type }}" role="button" class="btn btn-primary"><i class="fa fa-eye"></i> View AndroidManifest.xml</a>
|
||||
<a href="{% url "tree_view" %}?md5={{ md5 }}&type=java" class="btn btn-info" role="button"><i class="fa fa-code"></i> View Source</a>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user