Bug Fixes + Improvements (#2307)

* Replace Android test APK
* Added tests for Library analysis from binary (scan_library route)
* iOS merge findings from swift and objective c rules with same rule identifier. Fixes #2287 
* iOS Binary analysis, sort regex matches. Fixes #2252
* Framework dylibs with no extensions to skip PIE checks. Fixes #2307
* Select correct network_security config. Fixes #2049
* Android Manifest Analysis added support for detecting task hijacking (StrandHogg 1.0 and StrandHogg 2.0) . Fixes #2124
* Added new manifest analysis rule to warn on apps targeting older Android OS
* Updated severity of findings
* UI improvement for AppSec dashboard to show a loader
* UI changes in Static Analysis to collapse large no of files in API and Code Analysis for better real estate
* Improved certificate file analysis for android, jar, aar, and ios
* MobSF version Bump
This commit is contained in:
Ajin Abraham
2023-12-16 22:19:09 -08:00
committed by GitHub
parent 78e9563f90
commit c6f037103d
24 changed files with 354 additions and 116 deletions
+1 -1
View File
@@ -10,7 +10,7 @@ from mobsf.install.windows.setup import windows_config_local
logger = logging.getLogger(__name__)
VERSION = '3.8.7'
VERSION = '3.8.8'
BANNER = """
__ __ _ ____ _____ _____ ___
| \/ | ___ | |__/ ___|| ___|_ _|___ / ( _ )
+2 -1
View File
@@ -492,7 +492,8 @@ def update_local_db(db_name, url, local_file):
else:
logger.info('%s Database is up-to-date', db_name)
return update
except requests.exceptions.ReadTimeout:
except (requests.exceptions.ReadTimeout,
requests.exceptions.ConnectionError):
logger.warning('Failed to download %s DB.', db_name)
except Exception:
logger.exception('[ERROR] %s DB Update', db_name)
+1 -1
View File
@@ -164,7 +164,7 @@ class Upload(object):
def api_docs(request):
"""Api Docs Route."""
context = {
'title': 'REST API Docs',
'title': 'API Docs',
'api_key': api_key(),
'version': settings.MOBSF_VER,
}
+28 -14
View File
@@ -71,7 +71,7 @@ def static_analysis_test():
if platform.system() in ['Darwin', 'Linux']:
pdfs = [
'/pdf/02e7989c457ab67eb514a8328779f256/',
'/pdf/3a552566097a8de588b8184b059b0158/',
'/pdf/82ab8b2193b3cfb1c737e3a786be363a/',
'/pdf/6c23c2970551be15f32bbab0b5db0c71/',
'/pdf/52c50ae824e329ba8b5b7a0f523efffe/',
'/pdf/57bb5be0ea44a755ada4a93885c3825e/',
@@ -81,7 +81,7 @@ def static_analysis_test():
else:
pdfs = [
'/pdf/02e7989c457ab67eb514a8328779f256/',
'/pdf/3a552566097a8de588b8184b059b0158/',
'/pdf/82ab8b2193b3cfb1c737e3a786be363a/',
'/pdf/52c50ae824e329ba8b5b7a0f523efffe/',
'/pdf/57bb5be0ea44a755ada4a93885c3825e/',
'/pdf/8179b557433835827a70510584f3143e/',
@@ -101,7 +101,7 @@ def static_analysis_test():
# Compare apps test
logger.info('Running App Compare tests')
first_app = '3a552566097a8de588b8184b059b0158'
first_app = '82ab8b2193b3cfb1c737e3a786be363a'
second_app = '52c50ae824e329ba8b5b7a0f523efffe'
url = '/compare/{}/{}/'.format(first_app, second_app)
resp = http_client.get(url, follow=True)
@@ -113,10 +113,24 @@ def static_analysis_test():
logger.info(resp.content)
return True
# Scan shared object or dylib from binaries.
logger.info('Running Library Analysis test')
md5 = '82ab8b2193b3cfb1c737e3a786be363a'
lib = 'apktool_out/lib/arm64-v8a/libdivajni.so'
url = f'/scan_library/{md5}?library={lib}'
resp = http_client.get(url, follow=True)
assert (resp.status_code == 200)
if resp.status_code == 200:
logger.info('[OK] Library Analysis test passed successfully')
else:
logger.error('Library Analysis test failed')
logger.info(resp.content)
return True
# Search by MD5
if platform.system() in ['Darwin', 'Linux']:
scan_md5s = ['02e7989c457ab67eb514a8328779f256',
'3a552566097a8de588b8184b059b0158',
'82ab8b2193b3cfb1c737e3a786be363a',
'6c23c2970551be15f32bbab0b5db0c71',
'52c50ae824e329ba8b5b7a0f523efffe',
'57bb5be0ea44a755ada4a93885c3825e',
@@ -124,7 +138,7 @@ def static_analysis_test():
'7b0a23bffc80bac05739ea1af898daad']
else:
scan_md5s = ['02e7989c457ab67eb514a8328779f256',
'3a552566097a8de588b8184b059b0158',
'82ab8b2193b3cfb1c737e3a786be363a',
'52c50ae824e329ba8b5b7a0f523efffe',
'57bb5be0ea44a755ada4a93885c3825e',
'8179b557433835827a70510584f3143e',
@@ -242,7 +256,7 @@ def api_test():
if platform.system() in ['Darwin', 'Linux']:
pdfs = [
{'hash': '02e7989c457ab67eb514a8328779f256'},
{'hash': '3a552566097a8de588b8184b059b0158'},
{'hash': '82ab8b2193b3cfb1c737e3a786be363a'},
{'hash': '6c23c2970551be15f32bbab0b5db0c71'},
{'hash': '52c50ae824e329ba8b5b7a0f523efffe'},
{'hash': '57bb5be0ea44a755ada4a93885c3825e'},
@@ -252,7 +266,7 @@ def api_test():
else:
pdfs = [
{'hash': '02e7989c457ab67eb514a8328779f256'},
{'hash': '3a552566097a8de588b8184b059b0158'},
{'hash': '82ab8b2193b3cfb1c737e3a786be363a'},
{'hash': '52c50ae824e329ba8b5b7a0f523efffe'},
{'hash': '57bb5be0ea44a755ada4a93885c3825e'},
{'hash': '8179b557433835827a70510584f3143e'},
@@ -314,9 +328,9 @@ def api_test():
logger.info('[OK] Scorecard API test completed')
logger.info('Running View Source API test')
# View Source tests
files = [{'file': 'opensecurity/helloworld/MainActivity.java',
files = [{'file': 'jakhar/aseem/diva/MainActivity.java',
'type': 'apk',
'hash': '3a552566097a8de588b8184b059b0158'},
'hash': '82ab8b2193b3cfb1c737e3a786be363a'},
{'file': 'opensecurity/webviewignoressl/MainActivity.java',
'type': 'studio',
'hash': '52c50ae824e329ba8b5b7a0f523efffe'},
@@ -351,7 +365,7 @@ def api_test():
resp = http_client.post(
'/api/v1/compare',
{
'hash1': '3a552566097a8de588b8184b059b0158',
'hash1': '82ab8b2193b3cfb1c737e3a786be363a',
'hash2': '52c50ae824e329ba8b5b7a0f523efffe',
},
HTTP_AUTHORIZATION=auth)
@@ -359,7 +373,7 @@ def api_test():
resp_custom = http_client.post(
'/api/v1/compare',
{
'hash1': '3a552566097a8de588b8184b059b0158',
'hash1': '82ab8b2193b3cfb1c737e3a786be363a',
'hash2': '52c50ae824e329ba8b5b7a0f523efffe',
},
HTTP_X_MOBSF_API_KEY=auth)
@@ -373,7 +387,7 @@ def api_test():
logger.info('Running Delete Scan Results test')
# Suppression tests
# Android Manifest by rule
and_hash = '3a552566097a8de588b8184b059b0158'
and_hash = '82ab8b2193b3cfb1c737e3a786be363a'
rule = 'app_is_debuggable'
typ = 'manifest'
logger.info('Running Suppression disable by rule for APK manifest')
@@ -489,7 +503,7 @@ def api_test():
# Deleting Scan Results
if platform.system() in ['Darwin', 'Linux']:
scan_md5s = ['02e7989c457ab67eb514a8328779f256',
'3a552566097a8de588b8184b059b0158',
'82ab8b2193b3cfb1c737e3a786be363a',
'6c23c2970551be15f32bbab0b5db0c71',
'52c50ae824e329ba8b5b7a0f523efffe',
'57bb5be0ea44a755ada4a93885c3825e',
@@ -498,7 +512,7 @@ def api_test():
]
else:
scan_md5s = ['02e7989c457ab67eb514a8328779f256',
'3a552566097a8de588b8184b059b0158',
'82ab8b2193b3cfb1c737e3a786be363a',
'52c50ae824e329ba8b5b7a0f523efffe',
'57bb5be0ea44a755ada4a93885c3825e',
'8179b557433835827a70510584f3143e',
@@ -42,15 +42,28 @@ MANIFEST_DESC = {
'[android:networkSecurityConfig=%s]'),
},
'vulnerable_os_version': {
'title': ('App can be installed on a vulnerable Android version'
'<br>[minSdk=%s]'),
'level': 'warning',
'title': ('App can be installed on a vulnerable '
'upatched Android version<br>Android %s, [minSdk=%s]'),
'level': 'high',
'description': ('This application can be installed on an older version'
' of android that has multiple unfixed '
'vulnerabilities. Support an Android version > 8, '
'API 26 to receive reasonable security updates.'),
'vulnerabilities. These devices won\'t receive '
'reasonable security updates from Google. '
'Support an Android version => 10, API 29 '
'to receive reasonable security updates.'),
'name': ('App can be installed on a vulnerable '
'upatched Android version %s, [minSdk=%s]'),
},
'vulnerable_os_version2': {
'title': ('App can be installed on a vulnerable Android version'
'<br>Android %s, minSdk=%s]'),
'level': 'warning',
'description': ('This application can be installed on an older version'
' of android that has multiple vulnerabilities. '
'Support an Android version => 10, API 29 '
'to receive reasonable security updates.'),
'name': ('App can be installed on a vulnerable Android version'
'[minSdk=%s]'),
' %s, [minSdk=%s]'),
},
'app_is_debuggable': {
'title': 'Debug Enabled For App<br>[android:debuggable=true]',
@@ -104,7 +117,7 @@ MANIFEST_DESC = {
},
'non_standard_launchmode': {
'title': 'Launch Mode of activity (%s) is not standard.',
'level': 'high',
'level': 'warning',
'description': ('An Activity should not be having the launch mode'
' attribute set to "singleTask/singleInstance" as '
'it becomes root Activity and it is possible for'
@@ -114,9 +127,45 @@ MANIFEST_DESC = {
' information is included in an Intent.'),
'name': 'Launch Mode of activity (%s) is not standard.',
},
'task_hijacking': {
'title': ('Activity (%s) is vulnerable to Android '
'Task Hijacking/StrandHogg.'),
'level': 'high',
'description': ('An Activity should not be having the launch mode '
'attribute set to "singleTask". It is then '
'possible for other applications to place a '
'malicious activity on top of the activity stack '
'resulting in Task Hijacking/StrandHogg 1.0'
'vulnerability. This makes the application an easy '
'target for phishing attacks. The vulnerability can '
'be remediated by setting the launch mode attribute '
'to "singleInstance" or by setting an empty '
'taskAffinity (taskAffinity="") attribute. You can '
'also update the target SDK version of the app to '
'28 or higher to fix this issue at platform level.'),
'name': ('Activity (%s) is vulnerable to Android '
'Task Hijacking/StrandHogg.'),
},
'task_hijacking2': {
'title': 'Activity (%s) is vulnerable to StrandHogg 2.0',
'level': 'high',
'description': ('Activity is found to be vulnerable to '
'StrandHogg 2.0 task hijacking vulnerability. '
'When vulnerable, it is possible for other '
'applications to place a malicious activity '
'on top of the activity stack of the vulnerable '
'application. This makes the application an easy '
'target for phishing attacks. The vulnerability can '
'be remediated by setting the launch mode attribute '
'to "singleInstance" and by setting an empty '
'taskAffinity (taskAffinity=""). You can also update '
'the target SDK version of the app to 29 or higher '
'to fix this issue at platform level.'),
'name': 'Activity (%s) is vulnerable to StrandHogg 2.0',
},
'improper_provider_permission': {
'title': 'Improper Content Provider Permissions<br>[%s]',
'level': 'high',
'level': 'warning',
'description': ('A content provider permission was set to allows'
' access from any other app on the device. '
'Content providers may contain sensitive '
@@ -343,7 +392,7 @@ MANIFEST_DESC = {
'explicitly_exported': {
'title': ('<strong>%s</strong> (%s) is not Protected.'
' <br>[android:exported=true]'),
'level': 'high',
'level': 'warning',
'description': ('A%s %s is found to be shared with other apps on the'
' device therefore leaving it accessible to any other'
' application on the device.'),
@@ -50,10 +50,11 @@ def get_hardcoded_cert_keystore(files):
for file_name in files:
if '.' not in file_name:
continue
ext = file_name.split('.')[-1]
if re.search('cer|pem|cert|crt|pub|key|pfx|p12|der', ext):
ext = Path(file_name).suffix
if ext in ('.cer', '.pem', '.cert', '.crt',
'.pub', '.key', '.pfx', '.p12', '.der'):
certz.append(escape(file_name))
if re.search('jks|bks', ext):
if ext in ('.jks', '.bks'):
key_store.append(escape(file_name))
if certz:
desc = 'Certificate/Key files hardcoded inside the app.'
@@ -14,8 +14,42 @@ logger = logging.getLogger(__name__)
ANDROID_4_2_LEVEL = 17
ANDROID_5_0_LEVEL = 21
ANDROID_8_0_LEVEL = 26
ANDROID_9_0_LEVEL = 28
ANDROID_10_0_LEVEL = 29
ANDROID_MANIFEST_FILE = 'AndroidManifest.xml'
ANDROID_API_LEVEL_MAP = {
'1': '1.0',
'2': '1.1',
'3': '1.5',
'4': '1.6',
'5': '2.0-2.1',
'8': '2.2-2.2.3',
'9': '2.3-2.3.2',
'10': '2.3.3-2.3.7',
'11': '3.0',
'12': '3.1',
'13': '3.2-3.2.6',
'14': '4.0-4.0.2',
'15': '4.0.3-4.0.4',
'16': '4.1-4.1.2',
'17': '4.2-4.2.2',
'18': '4.3-4.3.1',
'19': '4.4-4.4.4',
'20': '4.4W-4.4W.2',
'21': '5.0-5.0.2',
'22': '5.1-5.1.1',
'23': '6.0-6.0.1',
'24': '7.0',
'25': '7.1-7.1.2',
'26': '8.0',
'27': '8.1',
'28': '9',
'29': '10',
'30': '11',
'31': '12',
'32': '12L',
'33': '13',
}
def get_browsable_activities(node, ns):
"""Get Browsable Activities."""
@@ -110,7 +144,12 @@ def manifest_analysis(mfxml, ns, man_data_dic, src_type, app_dir):
# GENERAL
if man_data_dic['min_sdk'] and int(man_data_dic['min_sdk']) < ANDROID_8_0_LEVEL:
minsdk = man_data_dic.get('min_sdk')
ret_list.append(('vulnerable_os_version', (minsdk,), ()))
android_version = ANDROID_API_LEVEL_MAP.get(minsdk, 'XX')
ret_list.append(('vulnerable_os_version', (android_version, minsdk,), ()))
elif man_data_dic['min_sdk'] and int(man_data_dic['min_sdk']) < ANDROID_10_0_LEVEL:
minsdk = man_data_dic.get('min_sdk')
android_version = ANDROID_API_LEVEL_MAP.get(minsdk, 'XX')
ret_list.append(('vulnerable_os_version2', (android_version, minsdk,), ()))
# APPLICATIONS
# Handle multiple application tags in AAR
backupDisabled = False
@@ -174,30 +213,44 @@ def manifest_analysis(mfxml, ns, man_data_dic, src_type, app_dir):
else:
itemname = 'NIL'
item = ''
if itemname in ['Activity', 'Activity-Alias']:
# Task Affinity
task_affinity = node.getAttribute(f'{ns}:taskAffinity')
if (task_affinity):
item = node.getAttribute(f'{ns}:name')
ret_list.append(('task_affinity_set', (item,), ()))
# Task Affinity
if (
itemname in ['Activity', 'Activity-Alias'] and
node.getAttribute(f'{ns}:taskAffinity')
):
# LaunchMode
try:
affected_sdk = int(
man_data_dic['min_sdk']) < ANDROID_5_0_LEVEL
except Exception:
# in case min_sdk is not defined we assume vulnerability
affected_sdk = True
launchmode = node.getAttribute(f'{ns}:launchMode')
item = node.getAttribute(f'{ns}:name')
ret_list.append(('task_affinity_set', (item,), ()))
modes = ('singleTask', 'singleInstance')
if (affected_sdk
and launchmode in modes):
ret_list.append(('non_standard_launchmode', (item,), ()))
# LaunchMode
try:
affected_sdk = int(
man_data_dic['min_sdk']) < ANDROID_5_0_LEVEL
except Exception:
# in case min_sdk is not defined we assume vulnerability
affected_sdk = True
# Android Task Hijacking or StrandHogg 1.0
try:
target_sdk = int(man_data_dic['target_sdk'])
except Exception:
target_sdk = ANDROID_8_0_LEVEL
if (target_sdk < ANDROID_9_0_LEVEL
and launchmode == 'singleTask'):
ret_list.append(('task_hijacking', (item,), ()))
# Android StrandHogg 2.0
exported_act = node.getAttribute(f'{ns}:exported')
if (target_sdk < ANDROID_10_0_LEVEL
and itemname in ['Activity', 'Activity-Alias']
and exported_act == 'true'
and (launchmode != 'singleInstance' or task_affinity != '')):
ret_list.append(('task_hijacking2', (item,), ()))
if (
affected_sdk and
itemname in ['Activity', 'Activity-Alias'] and
(node.getAttribute(f'{ns}:launchMode') == 'singleInstance'
or node.getAttribute(f'{ns}:launchMode') == 'singleTask')):
item = node.getAttribute(f'{ns}:name')
ret_list.append(('non_standard_launchmode', (item,), ()))
# Exported Check
item = ''
is_inf = False
@@ -4,6 +4,10 @@ import logging
from xml.dom import minidom
from pathlib import Path
from mobsf.MobSF.utils import (
is_path_traversal,
)
logger = logging.getLogger(__name__)
HIGH = 'high'
WARNING = 'warning'
@@ -13,7 +17,7 @@ SECURE = 'secure'
def read_netsec_config(app_dir, config, src_type):
"""Read the manifest file."""
msg = 'Reading Network Security Config'
msg = 'Reading Network Security config'
try:
config_file = None
config = config.replace('@xml/', '', 1)
@@ -24,14 +28,20 @@ def read_netsec_config(app_dir, config, src_type):
else:
# APK
xml_dir = base / 'apktool_out' / 'res' / 'xml'
if not is_path_traversal(config):
netsec_file = xml_dir / f'{config}.xml'
if netsec_file.exists():
logger.info('%s from %s.xml', msg, config)
return netsec_file.read_text('utf8', 'ignore')
# Couldn't find the file defined in manifest
xmls = Path(xml_dir).glob('*.xml')
for xml in xmls:
if xml.stem in [config, 'network_security_config']:
if 'network_security' in xml.stem:
config_file = xml
break
if not config_file:
return None
logger.info(msg)
logger.info('%s from %s', msg, config_file.name)
return config_file.read_text('utf8', 'ignore')
except Exception:
logger.exception(msg)
@@ -50,7 +60,7 @@ def analysis(app_dir, config, is_debuggable, src_type):
netsec_conf = read_netsec_config(app_dir, config, src_type)
if not netsec_conf:
return netsec
logger.info('Parsing Network Security Config')
logger.info('Parsing Network Security config')
parsed = minidom.parseString(netsec_conf)
finds = []
summary = {HIGH: 0, WARNING: 0, INFO: 0, SECURE: 0}
@@ -2,6 +2,7 @@
# coding=utf-8
import shutil
import subprocess
from pathlib import Path
import lief
@@ -75,7 +76,12 @@ class MachOChecksec:
'to execute reliably.')
else:
severity = 'high'
if self.macho_name.endswith('.dylib'):
ext = Path(self.macho_name).suffix
# PIE check not applicable for static and dynamic libraries
# https://github.com/MobSF/Mobile-Security-Framework-MobSF/
# issues/2290#issuecomment-1837272113
if (ext == '.dylib'
or (not ext and '.framework' in self.macho_name)):
severity = 'info'
desc = (
'The binary is built without Position '
@@ -86,7 +92,7 @@ class MachOChecksec:
'the address space positions of key data areas of a '
'process, including the base of the executable and the '
'positions of the stack,heap and libraries. Use compiler '
'option -fPIC to enable Position Independent Code.'
'option -fPIC to enable Position Independent Code. '
'Not applicable for dylibs and static libraries.')
macho_dict['pie'] = {
'has_pie': has_pie,
@@ -13,7 +13,7 @@ logger = logging.getLogger(__name__)
def get_desc(desc_str, match):
"""Generate formatted detailed description with matches."""
return desc_str.format(
b', '.join(list(set(match))).decode('utf-8', 'ignore'))
b', '.join(sorted(set(match))).decode('utf-8', 'ignore'))
def _add_bfindings(findings, desc, detailed_desc, rule):
@@ -22,6 +22,19 @@ class _SourceType(Enum):
nocode = 'No Code'
def merge_findings(swift, objc):
code_analysis = {}
# Add all unique keys
for k in swift:
if k in objc:
swift[k]['files'].update(objc[k]['files'])
code_analysis[k] = swift[k]
for k in objc:
if k not in code_analysis:
code_analysis[k] = objc[k]
return code_analysis
def ios_source_analysis(src):
"""IOS Objective-C and Swift Code Analysis."""
try:
@@ -40,20 +53,22 @@ def ios_source_analysis(src):
source_types = set()
# Code and API Analysis
code_findings = scan(
objc_findings = scan(
objective_c_rules.as_posix(),
{'.m'},
[src],
settings.SKIP_CLASS_PATH)
if code_findings:
if objc_findings:
source_types.add(_SourceType.objc)
code_findings.update(scan(
swift_findings = scan(
swift_rules.as_posix(),
{'.swift'},
[src],
settings.SKIP_CLASS_PATH))
if code_findings:
settings.SKIP_CLASS_PATH)
if swift_findings:
source_types.add(_SourceType.swift)
code_findings = merge_findings(swift_findings, objc_findings)
# API Analysis
api_findings = scan(
api_rules.as_posix(),
{'.m', '.swift'},
@@ -2,9 +2,9 @@
"""iOS File Analysis."""
import os
import re
import shutil
import logging
from pathlib import Path
from django.utils.html import escape
@@ -39,15 +39,15 @@ def ios_list_files(src, md5_hash, binary_form, mode):
fileparam = file_path.replace(src, '')
filez.append(fileparam)
full_paths.append(file_path)
ext = jfile.split('.')[-1]
if re.search(r'cer|pem|cert|crt|pub|key|pfx|p12|der', ext):
ext = Path(jfile).suffix
if ext in ('.cer', '.pem', '.cert', '.crt',
'.pub', '.key', '.pfx', '.p12', '.der'):
certz.append({
'file_path': escape(file_path.replace(src, '')),
'type': None,
'hash': None,
})
if re.search(r'^db$|^sqlitedb$|^sqlite$', ext):
if ext in ('.db', '.sqlitedb', '.sqlite', '.sqlite3'):
database.append({
'file_path': escape(fileparam),
'type': mode,
@@ -117,7 +117,7 @@
type: Regex
metadata:
cvss: 7.5
cwe: CWE-532
cwe: cwe-532
masvs: storage-3
owasp-mobile: ''
ref: https://github.com/MobSF/owasp-mstg/blob/master/Document/0x06i-Testing-Code-Quality-and-Build-Settings.md#finding-debugging-code-and-verbose-error-logging-mstg-code-4
@@ -131,7 +131,7 @@
type: RegexOr
metadata:
cvss: 5.9
cwe: CWE-327
cwe: cwe-327
masvs: crypto-4
owasp-mobile: m5
ref: https://github.com/MobSF/owasp-mstg/blob/master/Document/0x04g-Testing-Cryptography.md#identifying-insecure-andor-deprecated-cryptographic-algorithms-mstg-crypto-4
@@ -144,7 +144,7 @@
type: RegexOr
metadata:
cvss: 5.9
cwe: CWE-327
cwe: cwe-327
masvs: crypto-4
owasp-mobile: m5
ref: https://github.com/MobSF/owasp-mstg/blob/master/Document/0x04g-Testing-Cryptography.md#identifying-insecure-andor-deprecated-cryptographic-algorithms-mstg-crypto-4
@@ -157,7 +157,7 @@
type: RegexOr
metadata:
cvss: 5.9
cwe: CWE-327
cwe: cwe-327
masvs: crypto-4
owasp-mobile: m5
ref: https://github.com/MobSF/owasp-mstg/blob/master/Document/0x04g-Testing-Cryptography.md#identifying-insecure-andor-deprecated-cryptographic-algorithms-mstg-crypto-4
@@ -171,7 +171,7 @@
type: RegexOr
metadata:
cvss: 5.9
cwe: CWE-327
cwe: cwe-327
masvs: crypto-4
owasp-mobile: m5
ref: https://github.com/MobSF/owasp-mstg/blob/master/Document/0x04g-Testing-Cryptography.md#identifying-insecure-andor-deprecated-cryptographic-algorithms-mstg-crypto-4
@@ -185,7 +185,7 @@
type: RegexOr
metadata:
cvss: 5.9
cwe: CWE-327
cwe: cwe-327
masvs: crypto-4
owasp-mobile: m5
ref: https://github.com/MobSF/owasp-mstg/blob/master/Document/0x04g-Testing-Cryptography.md#identifying-insecure-andor-deprecated-cryptographic-algorithms-mstg-crypto-4
@@ -344,7 +344,7 @@
type: Regex
metadata:
cvss: 4.3
cwe: CWE-311
cwe: cwe-311
masvs: storage-1
owasp-mobile: m2
ref: https://github.com/MobSF/owasp-mstg/blob/master/Document/0x06d-Testing-Data-Storage.md#ios-data-storage
@@ -410,7 +410,7 @@
type: RegexOr
metadata:
cvss: 0
cwe: CWE-295
cwe: cwe-295
masvs: network-4
owasp-mobile: m3
ref: https://github.com/MobSF/owasp-mstg/blob/master/Document/0x05g-Testing-Network-Communication.md#testing-custom-certificate-stores-and-certificate-pinning-mstg-network-4
@@ -422,7 +422,7 @@
type: Regex
metadata:
cvss: 0
cwe: CWE-311
cwe: cwe-311
masvs: storage-14
owasp-mobile: m2
ref: https://github.com/MobSF/owasp-mstg/blob/master/Document/0x06d-Testing-Data-Storage.md#realm-databases
@@ -436,7 +436,7 @@
type: RegexAnd
metadata:
cvss: 0
cwe: CWE-311
cwe: cwe-311
masvs: storage-14
owasp-mobile: m2
ref: https://github.com/MobSF/owasp-mstg/blob/master/Document/0x06d-Testing-Data-Storage.md#coredata
@@ -450,7 +450,7 @@
type: RegexAnd
metadata:
cvss: 0
cwe: CWE-311
cwe: cwe-311
masvs: storage-14
owasp-mobile: m2
ref: https://github.com/MobSF/owasp-mstg/blob/master/Document/0x06d-Testing-Data-Storage.md#realm-databases
@@ -475,7 +475,7 @@
type: Regex
metadata:
cvss: 0
cwe: CWE-939
cwe: cwe-939
masvs: platform-3
owasp-mobile: m1
- id: ios_sensitive_backup
@@ -517,7 +517,7 @@
type: RegexAndOr
metadata:
cvss: 7.5
cwe: CWE-757
cwe: cwe-757
masvs: network-2
owasp-mobile: m3
ref: https://github.com/MobSF/owasp-mstg/blob/master/Document/0x04f-Testing-Network-Communication.md#verifying-data-encryption-on-the-network-mstg-network-1-and-mstg-network-2
+1 -1
View File
@@ -41,7 +41,7 @@
<li class="nav-item d-none d-sm-inline-block"><a href="{% url 'recent' %}" class="nav-link">RECENT SCANS</a></li>
<li class="nav-item d-none d-sm-inline-block"><a href="{% url 'home' %}" class="nav-link">STATIC ANALYZER</a></li>
<li class="nav-item d-none d-sm-inline-block"><a href="{% url 'dynamic' %}" class="nav-link">DYNAMIC ANALYZER</a></li>
<li class="nav-item d-none d-sm-inline-block"><a href="{% url 'api_docs' %}" class="nav-link">REST API</a></li>
<li class="nav-item d-none d-sm-inline-block"><a href="{% url 'api_docs' %}" class="nav-link">API</a></li>
<li class="nav-item d-none d-sm-inline-block"><a href="{% url 'donate' %}" class="nav-link">DONATE ♥</a></li>
<li class="nav-item d-none d-sm-inline-block"><a target="_blank" href="https://mobsf.github.io/docs/#/" class="nav-link">DOCS</a></li>
<li class="nav-item d-none d-sm-inline-block"><a href="{% url 'about' %}" class="nav-link">ABOUT</a></li>
+1 -1
View File
@@ -14,7 +14,7 @@
<h1>About Mobile Security Framework</h1>
<p class="lead">
Mobile Security Framework (MobSF) is an automated, all-in-one mobile application (Android/iOS/Windows) pen-testing, malware analysis and security assessment framework capable of performing static and dynamic analysis. MobSF support mobile app binaries (APK, XAPK, IPA & APPX) along with zipped source code and provides REST APIs for seamless integration with your CI/CD or DevSecOps pipeline. The Dynamic Analyzer helps you to perform runtime security assessment and interactive instrumented testing.
Mobile Security Framework (MobSF) is an automated, all-in-one mobile application (Android/iOS/Windows) pen-testing, malware analysis and security assessment framework capable of performing static and dynamic analysis. MobSF support mobile app binaries (APK, XAPK, IPA & APPX) along with zipped source code and provides APIs for seamless integration with your CI/CD or DevSecOps pipeline. The Dynamic Analyzer helps you to perform runtime security assessment and interactive instrumented testing.
</p>
<p> <strong>Author:</strong> <a href="//twitter.com/ajinabraham">Ajin Abraham</a> </p>
<h2>Active Collaborators</h2>
+2 -2
View File
@@ -19,9 +19,9 @@
<div class="col-lg-12">
<div class="card">
<div class="card-body">
<h1><strong>REST API Docs</strong></h1>
<h1><strong>API Docs</strong></h1>
<p class="lead">
REST API Key: <strong><code>{{ api_key}}</code></strong>
API Key: <strong><code>{{ api_key}}</code></strong>
</p>
<!--API Docs -->
+2 -2
View File
@@ -35,7 +35,7 @@
<a class="nav-link" href="{% url 'dynamic' %}">DYNAMIC ANALYZER</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'api_docs' %}">REST API</a>
<a class="nav-link" href="{% url 'api_docs' %}">API</a>
</li>
</ul>
<ul class="navbar-nav ml-auto">
@@ -88,7 +88,7 @@
<div class="inner">
<h6> <a href="{% url 'recent' %}">RECENT SCANS</a> | <a href="{% url 'dynamic' %}">DYNAMIC ANALYZER</a> | <a href="{% url 'api_docs' %}">REST API</a> | <a href="{% url 'donate' %}">DONATE ♥</a> | <a target="_blank"
<h6> <a href="{% url 'recent' %}">RECENT SCANS</a> | <a href="{% url 'dynamic' %}">DYNAMIC ANALYZER</a> | <a href="{% url 'api_docs' %}">API</a> | <a href="{% url 'donate' %}">DONATE ♥</a> | <a target="_blank"
href="https://mobsf.github.io/docs/#/">DOCS</a> | <a href="{% url 'about' %}">ABOUT</a></h6>
</br>
<p>&copy; {% now "Y" %} Mobile Security Framework - MobSF {{ version }}</p>
@@ -812,10 +812,17 @@
{{ details.metadata.description }}
</td>
<td>
{% for file_path, lines in details.files.items %}
<a href="{% url "view_source" %}?file={{ file_path }}&amp;md5={{ md5 }}&amp;type={{app_type}}&amp;lines={{ lines }}"> {{ file_path }}</a>
<br/>
{% endfor %}
<a class="btn btn-primary btn-xs" data-toggle="collapse" href="#collapseapi{{forloop.counter}}" role="button" aria-expanded="false" aria-controls="collapseapi{{forloop.counter}}">
Show Files
</a>
<div class="collapse" id="collapseapi{{forloop.counter}}">
{% for file_path, lines in details.files.items %}
<small>
<a href="{% url "view_source" %}?file={{ file_path }}&amp;md5={{ md5 }}&amp;type={{app_type}}&amp;lines={{ lines }}"> {{ file_path }}</a>
</small>
</br>
{% endfor %}
</div>
</td>
</tr>
{% endfor %}
@@ -1301,10 +1308,26 @@
{% if details.metadata.masvs %}</br> <strong>OWASP MASVS: </strong>{{ details.metadata.masvs }}{% endif %}
</td>
<td>
{% for file_path, lines in details.files.items %}
<a href="{% url "view_source" %}?file={{ file_path }}&amp;md5={{ md5 }}&amp;type={{app_type}}&amp;lines={{ lines}}"> {{ file_path }}</a>
<br/>
{% endfor %}
{% if details.files|length < 4 %}
{% for file_path, lines in details.files.items %}
<small>
<a href="{% url "view_source" %}?file={{ file_path }}&amp;md5={{ md5 }}&amp;type={{app_type}}&amp;lines={{ lines}}"> {{ file_path }}</a>
</small>
</br>
{% endfor %}
{% else %}
<a class="btn btn-primary btn-xs" data-toggle="collapse" href="#collapsecode{{forloop.counter}}" role="button" aria-expanded="false" aria-controls="collapsecode{{forloop.counter}}">
Show Files
</a>
<div class="collapse" id="collapsecode{{forloop.counter}}">
{% for file_path, lines in details.files.items %}
<small>
<a href="{% url "view_source" %}?file={{ file_path }}&amp;md5={{ md5 }}&amp;type={{app_type}}&amp;lines={{ lines}}"> {{ file_path }}</a>
</small>
</br>
{% endfor %}
</div>
{% endif %}
</td>
<td>
@@ -628,10 +628,17 @@
{{ details.metadata.description }}
</td>
<td>
{% for file_path, lines in details.files.items %}
<a href="{% url "view_source" %}?file={{ file_path }}&amp;md5={{ md5 }}&amp;type={{app_type}}&amp;lines={{ lines }}"> {{ file_path }}</a>
<br/>
{% endfor %}
<a class="btn btn-primary btn-xs" data-toggle="collapse" href="#collapseapi{{forloop.counter}}" role="button" aria-expanded="false" aria-controls="collapseapi{{forloop.counter}}">
Show Files
</a>
<div class="collapse" id="collapseapi{{forloop.counter}}">
{% for file_path, lines in details.files.items %}
<small>
<a href="{% url "view_source" %}?file={{ file_path }}&amp;md5={{ md5 }}&amp;type={{app_type}}&amp;lines={{ lines }}"> {{ file_path }}</a>
</small>
</br>
{% endfor %}
</div>
</td>
</tr>
{% endfor %}
@@ -1038,10 +1045,27 @@
{% if details.metadata.masvs %}</br> <strong>OWASP MASVS: </strong>{{ details.metadata.masvs }}{% endif %}
</td>
<td>
{% for file_path, lines in details.files.items %}
<a href="{% url "view_source" %}?file={{ file_path }}&amp;md5={{ md5 }}&amp;type={{app_type}}&amp;lines={{ lines }}"> {{ file_path }}</a>
<br/>
{% endfor %}
{% if details.files|length < 4 %}
{% for file_path, lines in details.files.items %}
<small>
<a href="{% url "view_source" %}?file={{ file_path }}&amp;md5={{ md5 }}&amp;type={{app_type}}&amp;lines={{ lines }}"> {{ file_path }}</a>
</small>
</br>
{% endfor %}
{% else %}
<a class="btn btn-primary btn-xs" data-toggle="collapse" href="#collapsecode{{forloop.counter}}" role="button" aria-expanded="false" aria-controls="collapsecode{{forloop.counter}}">
Show Files
</a>
<div class="collapse" id="collapsecode{{forloop.counter}}">
{% for file_path, lines in details.files.items %}
<small>
<a href="{% url "view_source" %}?file={{ file_path }}&amp;md5={{ md5 }}&amp;type={{app_type}}&amp;lines={{ lines }}"> {{ file_path }}</a>
</small>
</br>
{% endfor %}
</div>
{% endif %}
</td>
<td>
@@ -112,6 +112,7 @@ sidebar-collapse
// @Version: 0.0.2 (2015-02-18)
*/
</style>
<link rel="stylesheet" href="{% static "others/css/spinner.css" %}">
{% endblock %}
{% block content %}
<!-- Content Wrapper. Contains page content -->
@@ -490,13 +491,31 @@ sidebar-collapse
<!-- /.content -->
</div>
<!-- /.content-wrapper -->
<!--Loader-->
<div class="hidden loading">
<div class='uil-ring-css' style='transform:scale(0.79);'>
<div></div>
</div>
</div>
{% endblock %}
{% block extra_scripts %}
<script src="{% static "chartjs/Chart.bundle.js" %}"></script>
<script src="{% static "chartjs/chartjs-gauge.js" %}"></script>
<script src="{% static "jqueryknob/jquery.knob.min.js" %}"></script>
<script>
function dynamic_loader(){
var loadingOverlay = document.querySelector('.loading');
loadingOverlay.classList.remove('hidden');
}
function stop_loader(){
var loadingOverlay = document.querySelector('.loading');
loadingOverlay.classList.add('hidden');
}
dynamic_loader();
document.onreadystatechange = function(){
if(document.readyState=='loaded' || document.readyState=='complete')
stop_loader();
}
// Severity
const high = {{ high | length }};
@@ -521,10 +521,17 @@
{{ details.metadata.description }}
</td>
<td>
{% for file_path, lines in details.files.items %}
<a href="{% url 'view_file_ios' %}?file={{ file_path }}&amp;md5={{ md5 }}&amp;type=ios&amp;lines={{ lines }}"> {{ file_path }}</a>
</br>
{% endfor %}
<a class="btn btn-primary btn-xs" data-toggle="collapse" href="#collapseapi{{forloop.counter}}" role="button" aria-expanded="false" aria-controls="collapseapi{{forloop.counter}}">
Show Files
</a>
<div class="collapse" id="collapseapi{{forloop.counter}}">
{% for file_path, lines in details.files.items %}
<small>
<a href="{% url 'view_file_ios' %}?file={{ file_path }}&amp;md5={{ md5 }}&amp;type=ios&amp;lines={{ lines }}"> {{ file_path }}</a>
</small>
</br>
{% endfor %}
</div>
</td>
</tr>
{% endfor %}
@@ -745,10 +752,26 @@
{% if details.metadata.masvs %}</br> <strong>OWASP MASVS: </strong>{{ details.metadata.masvs }}{% endif %}
</td>
<td>
{% for file_path, lines in details.files.items %}
<a href="{% url 'view_file_ios' %}?file={{ file_path }}&amp;md5={{ md5 }}&amp;type=ios&amp;lines={{ lines }}"> {{ file_path }}</a>
</br>
{% endfor %}
{% if details.files|length < 4 %}
{% for file_path, lines in details.files.items %}
<small>
<a href="{% url 'view_file_ios' %}?file={{ file_path }}&amp;md5={{ md5 }}&amp;type=ios&amp;lines={{ lines }}"> {{ file_path }}</a>
</small>
</br>
{% endfor %}
{% else %}
<a class="btn btn-primary btn-xs" data-toggle="collapse" href="#collapsecode{{forloop.counter}}" role="button" aria-expanded="false" aria-controls="collapsecode{{forloop.counter}}">
Show Files
</a>
<div class="collapse" id="collapsecode{{forloop.counter}}">
{% for file_path, lines in details.files.items %}
<small>
<a href="{% url 'view_file_ios' %}?file={{ file_path }}&amp;md5={{ md5 }}&amp;type=ios&amp;lines={{ lines }}"> {{ file_path }}</a>
</small>
</br>
{% endfor %}
</div>
{% endif %}
</td>
<td>
+1 -1
View File
@@ -1,6 +1,6 @@
[tool.poetry]
name = "mobsf"
version = "3.8.7"
version = "3.8.8"
description = "Mobile Security Framework (MobSF) is an automated, all-in-one mobile application (Android/iOS/Windows) pen-testing, malware analysis and security assessment framework capable of performing static and dynamic analysis."
keywords = ["mobsf", "mobile security framework", "mobile security", "security tool", "static analysis", "dynamic analysis", "malware analysis"]
authors = ["Ajin Abraham <[email protected]>"]
+2 -2
View File
@@ -73,7 +73,7 @@ if __name__ == '__main__':
'of a running MobSF Server. '
'(ex: 127.0.0.1:8000)')
parser.add_argument(
'-k', '--apikey', help='MobSF REST API Key')
'-k', '--apikey', help='MobSF API Key')
parser.add_argument(
'-r', '--rescan', help='Run a fresh scan. '
'Value can be 1 or 0 (Default: 0)')
@@ -86,7 +86,7 @@ if __name__ == '__main__':
apikey = args.apikey
rescan = args.rescan
if not is_server_up(server_url):
print('MobSF REST API Server is not running at ' + server_url)
print('MobSF API Server is not running at ' + server_url)
print('Exiting!')
exit(0)
# MobSF is running, start scan