Skip to content

Commit

Permalink
Bug Fixes + Improvements (#2307)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
ajinabraham authored Dec 17, 2023
1 parent 78e9563 commit c6f0371
Show file tree
Hide file tree
Showing 24 changed files with 353 additions and 115 deletions.
2 changes: 1 addition & 1 deletion mobsf/MobSF/init.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

logger = logging.getLogger(__name__)

VERSION = '3.8.7'
VERSION = '3.8.8'
BANNER = """
__ __ _ ____ _____ _____ ___
| \/ | ___ | |__/ ___|| ___|_ _|___ / ( _ )
Expand Down
3 changes: 2 additions & 1 deletion mobsf/MobSF/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion mobsf/MobSF/views/home.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ def upload(self):
def api_docs(request):
"""Api Docs Route."""
context = {
'title': 'REST API Docs',
'title': 'API Docs',
'api_key': api_key(),
'version': settings.MOBSF_VER,
}
Expand Down
2 changes: 1 addition & 1 deletion mobsf/StaticAnalyzer/test_files
Submodule test_files updated 1 files
+ android.apk
42 changes: 28 additions & 14 deletions mobsf/StaticAnalyzer/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -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/',
Expand All @@ -81,7 +81,7 @@ def static_analysis_test():
else:
pdfs = [
'/pdf/02e7989c457ab67eb514a8328779f256/',
'/pdf/3a552566097a8de588b8184b059b0158/',
'/pdf/82ab8b2193b3cfb1c737e3a786be363a/',
'/pdf/52c50ae824e329ba8b5b7a0f523efffe/',
'/pdf/57bb5be0ea44a755ada4a93885c3825e/',
'/pdf/8179b557433835827a70510584f3143e/',
Expand All @@ -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)
Expand All @@ -113,18 +113,32 @@ 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',
'8179b557433835827a70510584f3143e',
'7b0a23bffc80bac05739ea1af898daad']
else:
scan_md5s = ['02e7989c457ab67eb514a8328779f256',
'3a552566097a8de588b8184b059b0158',
'82ab8b2193b3cfb1c737e3a786be363a',
'52c50ae824e329ba8b5b7a0f523efffe',
'57bb5be0ea44a755ada4a93885c3825e',
'8179b557433835827a70510584f3143e',
Expand Down Expand Up @@ -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'},
Expand All @@ -252,7 +266,7 @@ def api_test():
else:
pdfs = [
{'hash': '02e7989c457ab67eb514a8328779f256'},
{'hash': '3a552566097a8de588b8184b059b0158'},
{'hash': '82ab8b2193b3cfb1c737e3a786be363a'},
{'hash': '52c50ae824e329ba8b5b7a0f523efffe'},
{'hash': '57bb5be0ea44a755ada4a93885c3825e'},
{'hash': '8179b557433835827a70510584f3143e'},
Expand Down Expand Up @@ -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'},
Expand Down Expand Up @@ -351,15 +365,15 @@ def api_test():
resp = http_client.post(
'/api/v1/compare',
{
'hash1': '3a552566097a8de588b8184b059b0158',
'hash1': '82ab8b2193b3cfb1c737e3a786be363a',
'hash2': '52c50ae824e329ba8b5b7a0f523efffe',
},
HTTP_AUTHORIZATION=auth)
assert (resp.status_code == 200)
resp_custom = http_client.post(
'/api/v1/compare',
{
'hash1': '3a552566097a8de588b8184b059b0158',
'hash1': '82ab8b2193b3cfb1c737e3a786be363a',
'hash2': '52c50ae824e329ba8b5b7a0f523efffe',
},
HTTP_X_MOBSF_API_KEY=auth)
Expand All @@ -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')
Expand Down Expand Up @@ -489,7 +503,7 @@ def api_test():
# Deleting Scan Results
if platform.system() in ['Darwin', 'Linux']:
scan_md5s = ['02e7989c457ab67eb514a8328779f256',
'3a552566097a8de588b8184b059b0158',
'82ab8b2193b3cfb1c737e3a786be363a',
'6c23c2970551be15f32bbab0b5db0c71',
'52c50ae824e329ba8b5b7a0f523efffe',
'57bb5be0ea44a755ada4a93885c3825e',
Expand All @@ -498,7 +512,7 @@ def api_test():
]
else:
scan_md5s = ['02e7989c457ab67eb514a8328779f256',
'3a552566097a8de588b8184b059b0158',
'82ab8b2193b3cfb1c737e3a786be363a',
'52c50ae824e329ba8b5b7a0f523efffe',
'57bb5be0ea44a755ada4a93885c3825e',
'8179b557433835827a70510584f3143e',
Expand Down
65 changes: 57 additions & 8 deletions mobsf/StaticAnalyzer/views/android/android_manifest_desc.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,28 @@
'[android:networkSecurityConfig=%s]'),
},
'vulnerable_os_version': {
'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. 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>[minSdk=%s]'),
'<br>Android %s, minSdk=%s]'),
'level': 'warning',
'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.'),
' 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]',
Expand Down Expand Up @@ -104,7 +117,7 @@
},
'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'
Expand All @@ -114,9 +127,45 @@
' 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 '
Expand Down Expand Up @@ -343,7 +392,7 @@
'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.'),
Expand Down
7 changes: 4 additions & 3 deletions mobsf/StaticAnalyzer/views/android/cert_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.'
Expand Down
Loading

0 comments on commit c6f0371

Please sign in to comment.