Skip to content

Commit 05206e7

Browse files
authored
[SECURITY] Security update to fix vulnerabilities reported by Positive Technologies researchers (#2488)
* Fix Stored XSS in iOS Dynamic Analysis, GHSA-cxqq-w3x5-7ph3 * Fix DOS by loose re_path check and strict check inside function, GHSA-jrm8-xgf3-fwqr * Fix API Key leakage, replace REST API with authenticated endpoint, GHSA-79f6-p65j-3m2m * Update SECURITY.md
1 parent d1d3b7a commit 05206e7

File tree

11 files changed

+120
-73
lines changed

11 files changed

+120
-73
lines changed

.github/SECURITY.md

+3
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ Please report all security issues [here](https://github.com/MobSF/Mobile-Securit
1010

1111
| Vulnerability | Affected Versions |
1212
| ------- | ------------------ |
13+
| [Partial Denial of Service due to strict regex check in iOS report view URL](https://github.com/MobSF/Mobile-Security-Framework-MobSF/security/advisories/GHSA-jrm8-xgf3-fwqr) | `<=4.3.0` |
14+
| [Local Privilege escalation due to leaked REST API key in web UI](https://github.com/MobSF/Mobile-Security-Framework-MobSF/security/advisories/GHSA-79f6-p65j-3m2m) | `<=4.3.0` |
15+
| [Stored Cross-Site Scripting in iOS dynamic_analysis view via `bundle` id](https://github.com/MobSF/Mobile-Security-Framework-MobSF/security/advisories/GHSA-cxqq-w3x5-7ph3) | `<=4.3.0` |
1316
| [Stored Cross-Site Scripting Vulnerability in Recent Scans "Diff or Compare"](https://github.com/MobSF/Mobile-Security-Framework-MobSF/security/advisories/GHSA-5jc6-h9w7-jm3p) | `<=4.2.8` |
1417
| [Zip Slip Vulnerability in .a extraction](https://github.com/MobSF/Mobile-Security-Framework-MobSF/security/advisories/GHSA-4hh3-vj32-gr6j) | `<=4.0.6` |
1518
| [Open Redirect in Login redirect](https://github.com/MobSF/Mobile-Security-Framework-MobSF/security/advisories/GHSA-8m9j-2f32-2vx4) | `<=4.0.4` |

mobsf/DynamicAnalyzer/views/ios/corellium_instance.py

+2
Original file line numberDiff line numberDiff line change
@@ -763,6 +763,8 @@ def download_data(request, bundle_id, api=False):
763763
if failed:
764764
return send_response(failed, api)
765765
if not strict_package_check(bundle_id):
766+
# Check bundle_id during call, as the check
767+
# is not done in REST API/URL repath.
766768
data['message'] = 'Invalid iOS Bundle id'
767769
return send_response(data, api)
768770
ci = CorelliumInstanceAPI(instance_id)

mobsf/DynamicAnalyzer/views/ios/report.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,9 @@ def ios_view_report(request, bundle_id, api=False):
4949
else:
5050
dev = ''
5151
if not strict_package_check(bundle_id):
52-
# We need this check since bundleid
53-
# is not validated in REST API
52+
# bundle_id is not validated in REST API.
53+
# Also bundleid is not strictly validated
54+
# in URL path.
5455
return print_n_send_error_response(
5556
request,
5657
'Invalid iOS Bundle id',

mobsf/MobSF/init.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
logger = logging.getLogger(__name__)
2020

21-
VERSION = '4.3.0'
21+
VERSION = '4.3.1'
2222
BANNER = r"""
2323
__ __ _ ____ _____ _ _ _____
2424
| \/ | ___ | |__/ ___|| ___|_ _| || | |___ /

mobsf/MobSF/urls.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252

5353
from . import settings
5454

55-
bundle_id_regex = r'(?P<bundle_id>([a-zA-Z0-9]{1}[\w.-]{1,255}))$'
55+
bundle_id_regex = r'(?P<bundle_id>.+)$'
5656
checksum_regex = r'(?P<checksum>[0-9a-f]{32})'
5757
paginate = r'(?P<page_size>[0-9]{1,10})/(?P<page_number>[0-9]{1,10})'
5858

mobsf/StaticAnalyzer/views/android/views/source_tree.py

-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
render,
1111
)
1212

13-
from mobsf.MobSF.init import api_key
1413
from mobsf.MobSF.utils import (
1514
is_md5,
1615
print_n_send_error_response,
@@ -71,7 +70,6 @@ def run(request):
7170
'hash': md5,
7271
'source_type': typ,
7372
'version': settings.MOBSF_VER,
74-
'api_key': api_key(settings.MOBSF_HOME),
7573
}
7674
template = 'static_analysis/source_tree.html'
7775
return render(request, template, context)

mobsf/StaticAnalyzer/views/android/views/view_source.py

+25-7
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
# -*- coding: utf_8 -*-
22
"""View Source of a file."""
3-
43
import logging
54
import ntpath
65
from pathlib import Path
76

87
from django.conf import settings
98
from django.shortcuts import render
109
from django.utils.html import escape
10+
from django.http import JsonResponse
1111

1212
from mobsf.MobSF.forms import FormUtil
1313
from mobsf.MobSF.utils import (
@@ -28,9 +28,26 @@
2828
logger = logging.getLogger(__name__)
2929

3030

31+
def send_json(data):
32+
return JsonResponse(data, safe=False)
33+
34+
35+
def send_error(request, err, api_mode, json_resp, exp=None):
36+
"""Send error message as dict or JSON."""
37+
if exp:
38+
res = print_n_send_error_response(request, err, api_mode, exp)
39+
else:
40+
res = print_n_send_error_response(request, err, api_mode)
41+
if json_resp:
42+
return send_json(res)
43+
return res
44+
45+
3146
@login_required
3247
def run(request, api=False):
3348
"""View the source of a file."""
49+
json_resp = request.GET.get('json', '0') == '1'
50+
api_mode = api or json_resp
3451
try:
3552
logger.info('View Java Source File')
3653
exp = 'Error Description'
@@ -46,8 +63,7 @@ def run(request, api=False):
4663
viewsource_form = ViewSourceAndroidForm(request.GET)
4764
if not viewsource_form.is_valid():
4865
err = FormUtil.errors_message(viewsource_form)
49-
return print_n_send_error_response(request, err, api, exp)
50-
66+
return send_error(request, err, api_mode, json_resp, exp)
5167
base = Path(settings.UPLD_DIR) / md5
5268
if typ == 'smali':
5369
src = base / 'smali_source'
@@ -57,12 +73,12 @@ def run(request, api=False):
5773
src, syntax, _ = find_java_source_folder(base)
5874
except StopIteration:
5975
msg = 'Invalid directory or file extension'
60-
return print_n_send_error_response(request, msg, api)
76+
return send_error(request, msg, api_mode, json_resp)
6177

6278
sfile = src / fil
6379
if not is_safe_path(src, sfile.as_posix()):
6480
msg = 'Path Traversal Detected!'
65-
return print_n_send_error_response(request, msg, api)
81+
return send_error(request, msg, api_mode, json_resp)
6682
context = {
6783
'title': escape(ntpath.basename(fil)),
6884
'file': escape(ntpath.basename(fil)),
@@ -72,11 +88,13 @@ def run(request, api=False):
7288
'version': settings.MOBSF_VER,
7389
}
7490
template = 'general/view.html'
75-
if api:
91+
if json_resp:
92+
return send_json(context)
93+
if api_mode:
7694
return context
7795
return render(request, template, context)
7896
except Exception as exp:
7997
logger.exception('Error Viewing Source')
8098
msg = str(exp)
8199
exp = exp.__doc__
82-
return print_n_send_error_response(request, msg, api, exp)
100+
return send_error(request, msg, api_mode, json_resp, exp)

mobsf/templates/dynamic_analysis/ios/dynamic_analysis.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@ <h4 class="modal-title">Create a Corellium iOS VM</h4>
403403
<td><p>
404404
<a class="btn btn-success disable" onclick="dynamic_loader()" href="${url}"><i class="fab fa-apple"></i> Start Dynamic Analysis</a>
405405
<a class="btn btn-info ${buttonState}" href="../../ios/view_report/${escapeHtml(bundle)}"><i class="fa fa-mobile"></i> View Report </a>
406-
<a class="btn btn-warning" id="${$('#ios_dynamic').val()}" onclick="remove_app(this, '${bundle}')"><i class="fas fa-trash-alt"></i> Uninstall</a>
406+
<a class="btn btn-warning" id="${$('#ios_dynamic').val()}" onclick="remove_app(this, '${escapeHtml(bundle)}')"><i class="fas fa-trash-alt"></i> Uninstall</a>
407407
</p>
408408
</td></tr>`);
409409
}

mobsf/templates/static_analysis/source_tree.html

+2-10
Original file line numberDiff line numberDiff line change
@@ -275,17 +275,9 @@ <h2>
275275

276276
function show_file(strPath) {
277277
$.ajax({
278-
type: "POST",
279-
url: "{% url "api_view_source" %}",
278+
type: "GET",
279+
url: "{% url "view_source" %}?json=1&md5={{ hash }}&type={{ source_type }}&file=" + strPath,
280280
dataType: 'json',
281-
headers: {
282-
"Authorization": "{{ api_key }}"
283-
},
284-
data: {
285-
type: "{{ source_type }}",
286-
hash: "{{ hash }}",
287-
file: strPath
288-
},
289281
success: function(strFileData) {
290282
var code_block = $("pre#fileoutput")
291283
code_block.text(strFileData.data);

0 commit comments

Comments
 (0)