mirror of
https://github.com/MobSF/Mobile-Security-Framework-MobSF.git
synced 2026-10-12 02:06:59 +00:00
331 lines
14 KiB
Python
Executable File
331 lines
14 KiB
Python
Executable File
#!/usr/bin/env python
|
|
import json
|
|
import logging
|
|
import os
|
|
import platform
|
|
|
|
from django.conf import settings
|
|
from django.http import HttpResponse
|
|
from django.test import Client, TestCase
|
|
|
|
from MobSF.utils import api_key, log_exception
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
RESCAN = False
|
|
# Set RESCAN to True if Static Analyzer Code is modified
|
|
|
|
|
|
def static_analysis_test():
|
|
"""Test Static Analyzer."""
|
|
logger.info('Running Static Analyzer Unit test')
|
|
try:
|
|
uploaded = []
|
|
logger.info('Running Upload Test')
|
|
http_client = Client()
|
|
apk_dir = os.path.join(settings.BASE_DIR, 'StaticAnalyzer/test_files/')
|
|
for filename in os.listdir(apk_dir):
|
|
fpath = os.path.join(apk_dir, filename)
|
|
with open(fpath, 'rb') as filp:
|
|
response = http_client.post('/upload/', {'file': filp})
|
|
obj = json.loads(response.content.decode('utf-8'))
|
|
if response.status_code == 200 and obj['status'] == 'success':
|
|
logger.info('[OK] Upload OK: %s', filename)
|
|
uploaded.append(obj['url'])
|
|
else:
|
|
logger.error('Performing Upload: %s', filename)
|
|
return True
|
|
break
|
|
logger.info('[OK] Completed Upload test')
|
|
logger.info('Running Static Analysis Test')
|
|
for upl in uploaded:
|
|
if RESCAN:
|
|
upl = '/' + upl + '&rescan=1'
|
|
else:
|
|
upl = '/' + upl
|
|
resp = http_client.get(upl, follow=True)
|
|
if resp.status_code == 200:
|
|
logger.info('[OK] Static Analysis Complete: %s', upl)
|
|
else:
|
|
logger.error('Performing Static Analysis: %s', upl)
|
|
return True
|
|
break
|
|
logger.info('[OK] Static Analysis test completed')
|
|
logger.info('Running PDF Generation Test')
|
|
if platform.system() in ['Darwin', 'Linux']:
|
|
pdfs = [
|
|
'/PDF/?md5=3a552566097a8de588b8184b059b0158&type=APK',
|
|
'/PDF/?md5=6c23c2970551be15f32bbab0b5db0c71&type=IPA',
|
|
'/PDF/?md5=52c50ae824e329ba8b5b7a0f523efffe&type=ANDZIP',
|
|
'/PDF/?md5=57bb5be0ea44a755ada4a93885c3825e&type=IOSZIP',
|
|
'/PDF/?md5=8179b557433835827a70510584f3143e&type=APPX',
|
|
]
|
|
else:
|
|
pdfs = [
|
|
'/PDF/?md5=3a552566097a8de588b8184b059b0158&type=APK',
|
|
'/PDF/?md5=52c50ae824e329ba8b5b7a0f523efffe&type=ANDZIP',
|
|
'/PDF/?md5=57bb5be0ea44a755ada4a93885c3825e&type=IOSZIP',
|
|
'/PDF/?md5=8179b557433835827a70510584f3143e&type=APPX',
|
|
]
|
|
|
|
for pdf in pdfs:
|
|
resp = http_client.get(pdf)
|
|
if (resp.status_code == 200
|
|
and resp._headers['content-type'][1] == 'application/pdf'):
|
|
logger.info('[OK] PDF Report Generated: %s', pdf)
|
|
else:
|
|
logger.error('Generating PDF: %s', pdf)
|
|
logger.info(resp.content)
|
|
return True
|
|
break
|
|
logger.info('[OK] PDF Generation test completed')
|
|
|
|
# Compare apps test
|
|
logger.info('Running App Compare tests')
|
|
first_app = '3a552566097a8de588b8184b059b0158'
|
|
second_app = '52c50ae824e329ba8b5b7a0f523efffe'
|
|
url = '/compare/{}/{}/'.format(first_app, second_app)
|
|
resp = http_client.get(url, follow=True)
|
|
assert (resp.status_code == 200)
|
|
if resp.status_code == 200:
|
|
logger.info('[OK] App compare tests passed successfully')
|
|
else:
|
|
logger.error('App compare tests failed')
|
|
logger.info(resp.content)
|
|
return True
|
|
logger.info('Running Delete Scan Results test')
|
|
# Deleting Scan Results
|
|
if platform.system() in ['Darwin', 'Linux']:
|
|
scan_md5s = ['3a552566097a8de588b8184b059b0158',
|
|
'6c23c2970551be15f32bbab0b5db0c71',
|
|
'52c50ae824e329ba8b5b7a0f523efffe',
|
|
'57bb5be0ea44a755ada4a93885c3825e',
|
|
'8179b557433835827a70510584f3143e']
|
|
else:
|
|
scan_md5s = ['3a552566097a8de588b8184b059b0158',
|
|
'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.decode('utf-8'))
|
|
if dat['deleted'] == 'yes':
|
|
logger.info('[OK] Deleted Scan: %s', md5)
|
|
else:
|
|
logger.error('Deleting Scan: %s', md5)
|
|
return True
|
|
else:
|
|
logger.error('Deleting Scan: %s', md5)
|
|
return True
|
|
logger.info('Delete Scan Results test completed')
|
|
except Exception:
|
|
log_exception('Completing Static Analyzer Test')
|
|
return False
|
|
|
|
|
|
def api_test():
|
|
"""View for Handling REST API Test."""
|
|
logger.info('\nRunning REST API Unit test')
|
|
auth = api_key()
|
|
try:
|
|
uploaded = []
|
|
logger.info('Running Test on Upload API')
|
|
http_client = Client()
|
|
apk_dir = os.path.join(settings.BASE_DIR, 'StaticAnalyzer/test_files/')
|
|
for filename in os.listdir(apk_dir):
|
|
fpath = os.path.join(apk_dir, filename)
|
|
if (platform.system() not in ['Darwin', 'Linux']
|
|
and fpath.endswith('.ipa')):
|
|
continue
|
|
with open(fpath, 'rb') as filp:
|
|
response = http_client.post(
|
|
'/api/v1/upload', {'file': filp}, HTTP_AUTHORIZATION=auth)
|
|
obj = json.loads(response.content.decode('utf-8'))
|
|
if response.status_code == 200 and 'hash' in obj:
|
|
logger.info('[OK] Upload OK: %s', filename)
|
|
uploaded.append(obj)
|
|
else:
|
|
logger.error('Performing Upload %s', filename)
|
|
return True
|
|
logger.info('[OK] Completed Upload API test')
|
|
logger.info('Running Static Analysis API Test')
|
|
for upl in uploaded:
|
|
resp = http_client.post(
|
|
'/api/v1/scan', upl, HTTP_AUTHORIZATION=auth)
|
|
if resp.status_code == 200:
|
|
logger.info('[OK] Static Analysis Complete: %s',
|
|
upl['file_name'])
|
|
else:
|
|
logger.error('Performing Static Analysis: %s',
|
|
upl['file_name'])
|
|
return True
|
|
logger.info('[OK] Static Analysis API test completed')
|
|
# Scan List API test
|
|
logger.info('Running Scan List API tests')
|
|
resp = http_client.get('/api/v1/scans', HTTP_AUTHORIZATION=auth)
|
|
if resp.status_code == 200:
|
|
logger.info('Scan List API Test 1 success')
|
|
else:
|
|
logger.error('Scan List API Test 1')
|
|
return True
|
|
resp = http_client.get(
|
|
'/api/v1/scans?page=1&page_size=10', HTTP_AUTHORIZATION=auth)
|
|
if resp.status_code == 200:
|
|
logger.info('Scan List API Test 2 success')
|
|
else:
|
|
logger.error('Scan List API Test 2')
|
|
return True
|
|
logger.info('[OK] Scan List API tests completed')
|
|
# PDF Tests
|
|
logger.info('Running PDF Generation API Test')
|
|
if platform.system() in ['Darwin', 'Linux']:
|
|
pdfs = [
|
|
{'hash': '3a552566097a8de588b8184b059b0158',
|
|
'scan_type': 'apk'},
|
|
{'hash': '6c23c2970551be15f32bbab0b5db0c71',
|
|
'scan_type': 'ipa'},
|
|
{'hash': '52c50ae824e329ba8b5b7a0f523efffe',
|
|
'scan_type': 'andzip'},
|
|
{'hash': '57bb5be0ea44a755ada4a93885c3825e',
|
|
'scan_type': 'ioszip'},
|
|
{'hash': '8179b557433835827a70510584f3143e',
|
|
'scan_type': 'appx'},
|
|
]
|
|
else:
|
|
pdfs = [
|
|
{'hash': '3a552566097a8de588b8184b059b0158',
|
|
'scan_type': 'apk'},
|
|
{'hash': '52c50ae824e329ba8b5b7a0f523efffe',
|
|
'scan_type': 'andzip'},
|
|
{'hash': '57bb5be0ea44a755ada4a93885c3825e',
|
|
'scan_type': 'ioszip'},
|
|
{'hash': '8179b557433835827a70510584f3143e',
|
|
'scan_type': 'appx'},
|
|
]
|
|
for pdf in pdfs:
|
|
resp = http_client.post(
|
|
'/api/v1/download_pdf', pdf, HTTP_AUTHORIZATION=auth)
|
|
if (resp.status_code == 200
|
|
and resp._headers['content-type'][1] == 'application/pdf'):
|
|
logger.info('[OK] PDF Report Generated: %s', pdf['hash'])
|
|
else:
|
|
logger.error('Generating PDF: %s', pdf['hash'])
|
|
logger.info(resp.content)
|
|
return True
|
|
logger.info('[OK] PDF Generation API test completed')
|
|
logger.info('Running JSON Report API test')
|
|
# JSON Report
|
|
ctype = 'application/json; charset=utf-8'
|
|
for jsn in pdfs:
|
|
resp = http_client.post(
|
|
'/api/v1/report_json', jsn, HTTP_AUTHORIZATION=auth)
|
|
if (resp.status_code == 200
|
|
and resp._headers['content-type'][1] == ctype):
|
|
logger.info('[OK] JSON Report Generated: %s', jsn['hash'])
|
|
else:
|
|
logger.error('Generating JSON Response: %s', jsn['hash'])
|
|
return True
|
|
logger.info('[OK] JSON Report API test completed')
|
|
logger.info('Running View Source API test')
|
|
# View Source tests
|
|
files = [{'file': 'opensecurity/helloworld/MainActivity.java',
|
|
'type': 'apk',
|
|
'hash': '3a552566097a8de588b8184b059b0158'},
|
|
{'file': 'helloworld.app/Info.plist',
|
|
'type': 'ipa',
|
|
'hash': '6c23c2970551be15f32bbab0b5db0c71'},
|
|
{'file': 'opensecurity/webviewignoressl/MainActivity.java',
|
|
'type': 'studio',
|
|
'hash': '52c50ae824e329ba8b5b7a0f523efffe'},
|
|
{'file': 'DamnVulnerableIOSApp/AppDelegate.m',
|
|
'type': 'ios',
|
|
'hash': '57bb5be0ea44a755ada4a93885c3825e'}]
|
|
for sfile in files:
|
|
resp = http_client.post(
|
|
'/api/v1/view_source', sfile, HTTP_AUTHORIZATION=auth)
|
|
if resp.status_code == 200:
|
|
dat = json.loads(resp.content.decode('utf-8'))
|
|
if dat['title']:
|
|
logger.info('[OK] Reading - %s', sfile['file'])
|
|
else:
|
|
logger.error('Reading - %s', sfile['file'])
|
|
return True
|
|
else:
|
|
logger.error('Reading - %s', sfile['file'])
|
|
return True
|
|
logger.info('[OK] View Source API test completed')
|
|
logger.info('Running Delete Scan API Results test')
|
|
# Deleting Scan Results
|
|
if platform.system() in ['Darwin', 'Linux']:
|
|
scan_md5s = ['3a552566097a8de588b8184b059b0158',
|
|
'6c23c2970551be15f32bbab0b5db0c71',
|
|
'52c50ae824e329ba8b5b7a0f523efffe',
|
|
'57bb5be0ea44a755ada4a93885c3825e',
|
|
'8179b557433835827a70510584f3143e',
|
|
]
|
|
else:
|
|
scan_md5s = ['3a552566097a8de588b8184b059b0158',
|
|
'52c50ae824e329ba8b5b7a0f523efffe',
|
|
'57bb5be0ea44a755ada4a93885c3825e',
|
|
'8179b557433835827a70510584f3143e',
|
|
]
|
|
for md5 in scan_md5s:
|
|
resp = http_client.post(
|
|
'/api/v1/delete_scan', {'hash': md5}, HTTP_AUTHORIZATION=auth)
|
|
if resp.status_code == 200:
|
|
dat = json.loads(resp.content.decode('utf-8'))
|
|
if dat['deleted'] == 'yes':
|
|
logger.info('[OK] Deleted Scan: %s', md5)
|
|
else:
|
|
logger.error('Deleting Scan: %s', md5)
|
|
return True
|
|
else:
|
|
logger.error('Deleting Scan: %s', md5)
|
|
return True
|
|
logger.info('Delete Scan Results API test completed')
|
|
except Exception:
|
|
log_exception('Completing REST API Unit Test')
|
|
return False
|
|
|
|
|
|
def start_test(request):
|
|
"""Static Analyzer Unit test."""
|
|
item = request.GET.get('module', 'static')
|
|
if item == 'static':
|
|
comp = 'static_analyzer'
|
|
failed_stat = static_analysis_test()
|
|
else:
|
|
comp = 'static_analyzer_api'
|
|
failed_stat = api_test()
|
|
try:
|
|
if failed_stat:
|
|
message = 'some tests failed'
|
|
resp_code = 403
|
|
else:
|
|
message = 'all tests completed'
|
|
resp_code = 200
|
|
except Exception:
|
|
resp_code = 403
|
|
message = 'error'
|
|
logger.info('\n\nALL TESTS COMPLETED!')
|
|
logger.info('Test Status: %s', message)
|
|
return HttpResponse(json.dumps({comp: message}),
|
|
content_type='application/json; charset=utf-8',
|
|
status=resp_code)
|
|
|
|
|
|
class StaticAnalyzerAndAPI(TestCase):
|
|
"""Unit Tests."""
|
|
|
|
def setUp(self):
|
|
self.http_client = Client()
|
|
|
|
def test_static_analyzer(self):
|
|
resp = self.http_client.post('/tests/?module=static')
|
|
self.assertEqual(resp.status_code, 200)
|
|
|
|
def test_rest_api(self):
|
|
resp = self.http_client.post('/tests/?module=api')
|
|
self.assertEqual(resp.status_code, 200)
|