Files
Mobile-Security-Framework-M…/mobsf/templates/dynamic_analysis/ios/device/dynamic_analysis.html
T
Ajin AbrahamandCursor a23ff75ec0 Fix CSRF in dynamic analysis actions (#2679)
* Harden path traversal checks for Windows root-relative escapes.

Reject POSIX/Windows absolute paths in is_path_traversal and require post-join containment at icon, network-config, and archive extraction sinks.

Co-authored-by: Cursor <[email protected]>

* Restrict network security config names to a basename.

CodeQL flagged the manifest-derived join; reduce the resource name first so path construction cannot escape xml_dir.

Co-authored-by: Cursor <[email protected]>

* Use os.path.basename for CodeQL-recognized path sanitization.

Path.name did not clear py/path-injection taint; basename plus existing containment checks keep the network-config read inside xml_dir.

Co-authored-by: Cursor <[email protected]>

* Drop CodeQL-appeasement basename sanitization from network config reads.

is_safe_path after join already rejects traversal, absolute, and Windows root-relative names; CodeQL py/path-injection is a false positive.

Co-authored-by: Cursor <[email protected]>

* Bound androguard ZIP member decompression

Use the configured per-file ZIP limit for apkinspector reads and cap
actual raw-DEFLATE output. Keep decompression-limit failures out of the
tampered-entry fallback so malicious compressed data cannot be treated
as stored bytes.

Co-authored-by: Cursor <[email protected]>

* Reject inactive SAML users before ACS group updates.

Existing accounts mapped from a valid IdP assertion should not have groups replaced or be passed to login() when is_active is False.

Co-authored-by: Cursor <[email protected]>

* Return the ACS error page for inactive users instead of raising Exception.

Co-authored-by: Cursor <[email protected]>

* Fix iOS plist-derived path traversal

Select and validate one contained IPA app bundle, reject unsafe plist
executable values, and guard icon and Mach-O inputs before access.
Harden equivalent source icon, plist, library, and dynamic icon paths.

Co-authored-by: Cursor <[email protected]>

* correct version

* fix CSRF in dynamic analysis actions

Co-authored-by: Ajin Abraham <[email protected]>

* document HTTPTools host header SSRF advisory

Co-authored-by: Ajin Abraham <[email protected]>

---------

Co-authored-by: Cursor <[email protected]>
2026-09-20 16:36:10 -07:00

342 lines
12 KiB
HTML

{% extends "base/base_layout.html" %}
{% load static %}
{% block sidebar_option %}
sidebar-collapse
{% endblock %}
{% block extra_css %}
<!-- DataTables -->
<link rel="stylesheet" href="{% static "adminlte/plugins/datatables-bs4/dataTables.bootstrap4.min.css" %}">
<link rel="stylesheet" href="{% static "others/css/spinner.css" %}">
<link href="{% static "adminlte/plugins/sweetalert2/sweetalert2.min.css" %}" rel="stylesheet">
<style>
#app_icon{
width: 64px;
height: 64px;
}
</style>
{% endblock %}
{% block content %}
<div class="content-wrapper">
<div class="content-header">
</div>
<div class="container-fluid">
<div class="row">
<div class="col-md-12">
<div class="card bg-gradient-primary">
<!-- /.card-header -->
<div class="card-body">
<div class="row">
<div class="col-md-12">
<h4>MobSF iOS Dynamic Analyzer</h4>
<data id="choosen_device" value="{{ selected_device }}"></data>
<div class="card-body">
<div class="table-responsive">
<p>
<h6><strong> Choose a device for Dynamic Analysis: </strong></h6>
<select class="form-control" id="ios_dynamic"></select>
</p>
</div>
</div>
</div>
</div>
</div>
<!-- /.card-body -->
</div>
<!-- /.card -->
</div>
<!-- /.col -->
<div class="col-md-12">
<div class="card card-default">
<div class="card-header">
<h3 class="card-title"><i class="fa fa-rocket"></i> MobSF Dynamic Analysis</h3>
</div>
<div class="card-body">
<div class="table-responsive">
<h4> Apps in Device</h4>
<table id="in_device" class="table table-bordered table-hover table-striped">
<tbody>
</tbody>
</table>
</br>
<h4> Apps Available</h4>
<table class="dattbl table table-bordered table-hover table-striped">
<thead>
<tr>
<th>APP</th>
<th>FILE NAME</th>
<th>BUNDLE ID</th>
<th>ACTION</th>
</tr>
</thead>
<tbody>
{% if apps %}
{% for e in apps %}
<tr>
<td align="center">
<img id="app_icon" src="/download/{{ e.MD5 }}-icon.png"/>
<br/><strong>{{ e.APP_NAME }} - {{ e.APP_VERSION }}</strong>
</td>
<td>
{{ e.FILE_NAME }}
</td>
<td>
{{ e.BUNDLE_ID }}
</td>
<td align="center">
{% if e.ENCRYPTED %}
<span class="badge badge-danger">ENCRYPTED IPA</span></br>
<small>You need decrypted IPA for dynamic analysis.</small>
{% else %}
<p>
<a class="btn btn-success upload-install-btn disabled" onclick="upload_and_install('{{ e.MD5 }}')" data-checksum="{{ e.MD5 }}"><i class="fab fa-apple"></i> Upload &amp; Install</a>
</p>
<p>
<a class="btn btn-info {% if not e.DYNAMIC_REPORT_EXISTS %}disabled{% endif %}" href="{% url 'view_report_device' bundle_id=e.BUNDLE_ID %}" onclick="dynamic_loader()"><i class="fa fa-mobile"></i> View Report </a>
</p>
{% endif %}
</td>
</tr>
{% endfor %}
{% endif %}
</tbody>
</table>
</div>
</div>
<!-- /.card-body -->
</div>
<!-- /.card -->
</div>
<!-- /.col -->
</div>
</div>
</div>
</div>
</div>
</div>
<!--Loader-->
<div class="hidden loading">
<div class='uil-ring-css' style='transform:scale(0.79);'>
<div></div>
</div>
</div>
{% endblock %}
{% block extra_scripts %}
<!-- DataTables -->
<script src="{% static "adminlte/plugins/datatables/jquery.dataTables.min.js" %} "></script>
<script src="{% static "adminlte/plugins/datatables-bs4/dataTables.bootstrap4.min.js" %}"></script>
<script src="{% static "adminlte/plugins/sweetalert2/sweetalert2.min.js" %}"></script>
<script>
// Escape HTML
function escapeHtml(unsafe){
return unsafe
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
}
function dynamic_loader(){
var loadingOverlay = document.querySelector('.loading');
loadingOverlay.classList.remove('hidden');
}
function stop_loader(){
var loadingOverlay = document.querySelector('.loading');
loadingOverlay.classList.add('hidden');
}
// Datatables
$(function () {
// Datatable
$('.dattbl').DataTable({
"paging": true,
"lengthChange": false,
"searching": true,
"ordering": false,
"info": true,
"autoWidth": true,
"responsive": true,
"language": {
"zeroRecords": " "
},
});
});
// Populate Available Dynamic Analyzer instances.
{% for i in wifi_devices %}
$('#ios_dynamic').append($('<option>',{
value: '{{ i.0 }}:{{ i.1 }}',
text: '{{ i.0 }}:{{ i.1 }} (WiFi)',
}));
{% endfor %}
{% for i in usb_devices %}
$('#ios_dynamic').append($('<option>',{
value: '{{ i.id}}',
text: '{{ i.model }} - iOS {{ i.version}} - {{ i.serial}}',
}));
{% endfor %}
var choosen_device = document.querySelector('#choosen_device').value;
if (choosen_device){
$('#ios_dynamic option').each(function(){
if ($(this).val() === choosen_device){
$(this).prop('selected', true);
}
});
} else {
// Add text select a device
$('#ios_dynamic').append($('<option>',{
value: '',
text: 'Select a Jailbroken iOS Device',
selected: true,
}));
}
// List apps onload
if ($('#ios_dynamic').val()){
list_apps();
}
// List apps on device change
$('#ios_dynamic').on('change', function() {
location.href = '{% url 'dynamic_ios_device' %}?device_id=' + $(this).val();
});
// List installed apps
function list_apps(){
$('#in_device tbody tr').remove();
$('#in_device thead').remove();
dynamic_loader();
$.ajax({
url: '{% url 'get_ios_device' %}',
type : 'POST',
data : {
csrfmiddlewaretoken: '{{ csrf_token }}',
device_id: $('#ios_dynamic').val(),
},
dataType: 'json',
success : function(json) {
if(!json)
stop_loader();
if(!json.status){
stop_loader();
Swal.fire(
'Listing apps failed',
'Device is not ready',
'error'
)
}
if (json.status==='ok'){
$('#in_device').append('<thead><tr> <th>APP</th> <th>BUNDLE ID</th> <th>APP TYPE</th> <th>ACTION</th> </tr></thead><tbody></tbody>');
for(var i=0; i < json.apps.length; i++) {
let name = json.apps[i].app_name || 'Unknown App';
let bundle = json.apps[i].bundle_id || 'Unknown Bundle';
let type = json.apps[i].app_type || 'Unknown';
let reportExists = true;
let iconb64;
if (json.apps[i].app_icon)
iconb64 = 'data:image/png;base64,' + json.apps[i].app_icon;
else
iconb64 = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==';
var buttonState = 'disabled';
if (reportExists)
buttonState = '';
var order;
if (type === 'User')
order = 'first';
else
order = 'last';
var url = `{% url 'dynamic_analyzer_device' %}`;
var deviceId = escapeHtml($('#ios_dynamic').val());
$('#in_device > tbody:' + order + '-child').append(
`<tr><td align="center">
<img id="app_icon" src="${escapeHtml(iconb64)}"/><br/>
<strong>${escapeHtml(name)}</strong></td>
<td>${escapeHtml(bundle)}</td>
<td>${escapeHtml(type)}</td>
<td><div>
<form method="post" action="${url}" onsubmit="dynamic_loader()" class="d-inline">
<input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}">
<input type="hidden" name="bundle_id" value="${escapeHtml(bundle)}">
<input type="hidden" name="device_id" value="${deviceId}">
<button type="submit" class="btn btn-success disable"><i class="fab fa-apple"></i> Start Dynamic Analysis</button>
</form>
<a class="btn btn-info ${buttonState}" onclick="dynamic_loader()" href="../../ios/view_report_device/${escapeHtml(bundle)}"><i class="fa fa-mobile"></i> View Report </a>
</div>
</td></tr>`);
}
$('.upload-install-btn').removeClass('disabled');
stop_loader();
}
else {
stop_loader();
Swal.fire(
'Listing apps failed',
json.message,
'error'
)
}
},
error : function(xhr,errmsg,err) {
stop_loader();
console.log(errmsg)
}
});
}
// Upload and Install IPA to device
function upload_and_install(checksum){
dynamic_loader();
$.ajax({
url: '{% url 'install_ipa_device' %}',
type : 'POST',
dataType: 'json',
data : {
csrfmiddlewaretoken: '{{ csrf_token }}',
device_id: $('#ios_dynamic').val(),
checksum: checksum,
},
success : function(json) {
if (json.status !== 'ok'){
stop_loader();
Swal.fire(
'IPA Install Failed',
'Failed to Install IPA: ' + json.message,
'error'
)
} else {
stop_loader();
Swal.fire(
'IPA Installed',
'The IPA is successfully installed',
'success'
);
list_apps();
}
},
error : function(xhr,errmsg,err) {
stop_loader();
Swal.fire(
'IPA Install Errored',
errmsg,
'error'
)
}
});
}
</script>
{% endblock %}