427 lines
25 KiB
HTML
427 lines
25 KiB
HTML
<!-- app/templates/dynamic_results.html -->
|
|
|
|
{% extends "base.html" %}
|
|
|
|
{% block content %}
|
|
<div class="max-w-6xl mx-auto px-4 py-6">
|
|
<!-- Header -->
|
|
<div class="flex items-center justify-between mb-6">
|
|
<div>
|
|
<h1 class="text-xl font-medium text-gray-100">Analysis Summary</h1>
|
|
<p class="text-base text-gray-500 mb-6">Comprehensive overview of all scan results.</p>
|
|
</div>
|
|
{% if file_info %}
|
|
<button onclick="window.location.href='/results/{{ file_info.md5 }}/info'"
|
|
class="px-4 py-2 bg-blue-500/10 text-blue-500 border border-blue-500 rounded-lg hover:bg-blue-500/20 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50 transition-colors"
|
|
aria-label="Navigate back to file information">
|
|
Back to File Info
|
|
</button>
|
|
{% else %}
|
|
<button onclick="window.location.href='/summary'"
|
|
class="px-4 py-2 bg-blue-500/10 text-blue-500 border border-blue-500 rounded-lg hover:bg-blue-500/20 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50 transition-colors"
|
|
aria-label="Navigate back to summary">
|
|
Back to Summary
|
|
</button>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<!-- Target Details -->
|
|
<div id="targetDetails" class="mb-6">
|
|
<div class="bg-gray-900/30 rounded-lg border border-gray-800 p-4 mb-4">
|
|
<h4 class="text-base font-medium text-gray-100 mb-2">Target Process</h4>
|
|
{% if analysis_results.moneta and analysis_results.moneta.findings.process_info %}
|
|
{% set info = analysis_results.moneta.findings.process_info %}
|
|
<p class="text-gray-300">
|
|
<span class="font-semibold">Name:</span> {{ info.name }}<br>
|
|
<span class="font-semibold">PID:</span> {{ info.pid }}<br>
|
|
<span class="font-semibold">Path:</span> <span class="text-gray-400">{{ info.path }}</span>
|
|
</p>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Overall Status Grid -->
|
|
<div class="grid grid-cols-3 gap-4 mb-6">
|
|
<div class="bg-gray-900/30 rounded-lg border border-gray-800 p-4">
|
|
<div class="text-sm text-gray-500">Overall Status</div>
|
|
<div id="overallStatus" class="text-2xl font-semibold {{ 'text-red-500' if yara_detections + pesieve_detections + moneta_detections + patriot_detections + hsb_detections > 0 else 'text-green-500' }}">
|
|
{{ 'Threats Detected' if yara_detections + pesieve_detections + moneta_detections + patriot_detections + hsb_detections > 0 else 'Clean' }}
|
|
</div>
|
|
</div>
|
|
<div class="bg-gray-900/30 rounded-lg border border-gray-800 p-4">
|
|
<div class="text-sm text-gray-500">Total Detections</div>
|
|
<div id="totalDetections" class="text-2xl font-semibold text-gray-300">{{ yara_detections + pesieve_detections + moneta_detections + patriot_detections + hsb_detections }}</div>
|
|
</div>
|
|
<div class="bg-gray-900/30 rounded-lg border border-gray-800 p-4">
|
|
<div class="text-sm text-gray-500">Total Analysis Duration</div>
|
|
<div id="scanDuration" class="text-2xl font-semibold text-gray-300">
|
|
{{ "%.2f"|format(analysis_results.analysis_metadata.total_duration if analysis_results.analysis_metadata else 0) }}s
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Scanner Results Table -->
|
|
<div class="bg-gray-900/30 rounded-lg border border-gray-800 overflow-hidden">
|
|
<table class="w-full">
|
|
<thead>
|
|
<tr class="border-b border-gray-800">
|
|
<th class="px-6 py-3 text-left text-base font-medium text-gray-300">Scanner</th>
|
|
<th class="px-6 py-3 text-left text-base font-medium text-gray-300">Status</th>
|
|
<th class="px-6 py-3 text-left text-base font-medium text-gray-300">Detections</th>
|
|
<th class="px-6 py-3 text-left text-base font-medium text-gray-300">Details</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="scannerResultsBody" class="divide-y divide-gray-800">
|
|
<!-- YARA Results Row -->
|
|
<tr>
|
|
<td class="px-6 py-4 text-base text-gray-300">YARA</td>
|
|
<td class="px-6 py-4">
|
|
<span class="px-2 py-1 text-base rounded {{ 'bg-red-500/10 text-red-500' if yara_detections else 'bg-green-500/10 text-green-500' }}">
|
|
{{ 'Suspicious' if yara_detections else 'Clean' }}
|
|
</span>
|
|
</td>
|
|
<td class="px-6 py-4 text-base {{ 'text-red-500' if yara_detections else 'text-gray-400' }}">{{ yara_detections }}</td>
|
|
<td class="px-6 py-4">
|
|
{% if yara_detections %}
|
|
<div class="text-base text-gray-400">
|
|
{% for match in analysis_results.yara.matches %}
|
|
<div class="mb-1">
|
|
Rule: <span class="text-red-400">{{ match.rule }}</span>
|
|
{% if match.metadata %}
|
|
(Severity: {{ match.metadata.severity }})
|
|
{% endif %}
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% else %}
|
|
<span class="text-base text-gray-400">No threats detected</span>
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
|
|
<!-- PE-sieve Results Row -->
|
|
<tr>
|
|
<td class="px-6 py-4 text-base text-gray-300">PE-sieve</td>
|
|
<td class="px-6 py-4">
|
|
<span class="px-2 py-1 text-base rounded {{ 'bg-red-500/10 text-red-500' if pesieve_detections else 'bg-green-500/10 text-green-500' }}">
|
|
{{ 'Suspicious' if pesieve_detections else 'Clean' }}
|
|
</span>
|
|
</td>
|
|
<td class="px-6 py-4 text-base {{ 'text-red-500' if pesieve_detections else 'text-gray-400' }}">{{ pesieve_detections }}</td>
|
|
<td class="px-6 py-4">
|
|
{% if pesieve_detections %}
|
|
{% set findings = analysis_results.pe_sieve.findings %}
|
|
<div class="text-base text-gray-400">
|
|
{% if findings.total_scanned > 0 %}
|
|
<div>Total Scanned: {{ findings.total_scanned }}</div>
|
|
{% endif %}
|
|
{% if findings.skipped > 0 %}
|
|
<div>Skipped: {{ findings.skipped }}</div>
|
|
{% endif %}
|
|
{% if findings.hooked > 0 %}
|
|
<div>Hooked: {{ findings.hooked }}</div>
|
|
{% endif %}
|
|
{% if findings.replaced > 0 %}
|
|
<div>Replaced: {{ findings.replaced }}</div>
|
|
{% endif %}
|
|
{% if findings.hdrs_modified > 0 %}
|
|
<div>Headers Modified: {{ findings.hdrs_modified }}</div>
|
|
{% endif %}
|
|
{% if findings.iat_hooks > 0 %}
|
|
<div>IAT Hooks: {{ findings.iat_hooks }}</div>
|
|
{% endif %}
|
|
{% if findings.implanted > 0 %}
|
|
<div>Implanted: {{ findings.implanted }}</div>
|
|
{% endif %}
|
|
{% if findings.implanted_pe > 0 %}
|
|
<div>Implanted PE: {{ findings.implanted_pe }}</div>
|
|
{% endif %}
|
|
{% if findings.implanted_shc > 0 %}
|
|
<div>Implanted Shellcode: {{ findings.implanted_shc }}</div>
|
|
{% endif %}
|
|
{% if findings.unreachable > 0 %}
|
|
<div>Unreachable Files: {{ findings.unreachable }}</div>
|
|
{% endif %}
|
|
{% if findings.other > 0 %}
|
|
<div>Other: {{ findings.other }}</div>
|
|
{% endif %}
|
|
{% if findings.total_suspicious > 0 %}
|
|
<div>Total Suspicious: {{ findings.total_suspicious }}</div>
|
|
{% endif %}
|
|
</div>
|
|
{% else %}
|
|
<span class="text-base text-gray-400">No modifications detected</span>
|
|
{% endif %}
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
<!-- Moneta Results Row -->
|
|
<tr>
|
|
<td class="px-6 py-4 text-base text-gray-300">Moneta</td>
|
|
<td class="px-6 py-4">
|
|
<span class="px-2 py-1 text-base rounded {{ 'bg-red-500/10 text-red-500' if moneta_detections else 'bg-green-500/10 text-green-500' }}">
|
|
{{ 'Suspicious' if moneta_detections else 'Clean' }}
|
|
</span>
|
|
</td>
|
|
<td class="px-6 py-4 text-base {{ 'text-red-500' if moneta_detections else 'text-gray-400' }}">{{ moneta_detections }}</td>
|
|
<td class="px-6 py-4">
|
|
{% if moneta_detections %}
|
|
<div class="text-base text-gray-400">
|
|
{% for key, value in analysis_results.moneta.findings.items() %}
|
|
{% if value is number and value > 0 and key != 'scan_duration' %}
|
|
<div class="mb-1">
|
|
{% if key == 'total_regions' %}
|
|
Total Regions: {{ value }}
|
|
{% elif key == 'total_private_rx' %}
|
|
Private RX: {{ value }}
|
|
{% elif key == 'total_private_rwx' %}
|
|
Private RWX: {{ value }}
|
|
{% elif key == 'total_abnormal_private_exec' %}
|
|
Abnormal Private Executable: {{ value }}
|
|
{% elif key == 'total_heap_executable' %}
|
|
Heap Executable: {{ value }}
|
|
{% elif key == 'total_modified_code' %}
|
|
Modified Code: {{ value }}
|
|
{% elif key == 'total_modified_pe_header' %}
|
|
Modified PE Headers: {{ value }}
|
|
{% elif key == 'total_inconsistent_x' %}
|
|
Inconsistent Execute Flags: {{ value }}
|
|
{% elif key == 'total_missing_peb' %}
|
|
Missing PEB: {{ value }}
|
|
{% elif key == 'total_mismatching_peb' %}
|
|
Mismatching PEB: {{ value }}
|
|
{% elif key == 'total_threads_non_image' %}
|
|
Threads in Non-Image Memory: {{ value }}
|
|
{% endif %}
|
|
</div>
|
|
{% endif %}
|
|
{% endfor %}
|
|
</div>
|
|
{% else %}
|
|
<span class="text-base text-gray-400">No anomalies detected</span>
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
<!-- Patriot Results Row -->
|
|
<tr>
|
|
<td class="px-6 py-4 text-base text-gray-300">Patriot</td>
|
|
<td class="px-6 py-4">
|
|
<span class="px-2 py-1 text-base rounded {{ 'bg-red-500/10 text-red-500' if patriot_detections else 'bg-green-500/10 text-green-500' }}">
|
|
{{ 'Suspicious' if patriot_detections else 'Clean' }}
|
|
</span>
|
|
</td>
|
|
<td class="px-6 py-4 text-base {{ 'text-red-500' if patriot_detections else 'text-gray-400' }}">{{ patriot_detections }}</td>
|
|
<td class="px-6 py-4">
|
|
{% if patriot_detections %}
|
|
<div class="text-base text-gray-400">
|
|
{% for finding in analysis_results.patriot.findings.findings %}
|
|
<div class="mb-1">
|
|
{{ finding.type }} ({{ finding.level }})
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% else %}
|
|
<span class="text-base text-gray-400">No suspicious activities</span>
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
|
|
<!-- HSB Results Row -->
|
|
<tr>
|
|
<td class="px-6 py-4 text-base text-gray-300">Hunt-Sleeping-Beacons</td>
|
|
<td class="px-6 py-4">
|
|
<span class="px-2 py-1 text-base rounded {{ 'bg-red-500/10 text-red-500' if hsb_detections else 'bg-green-500/10 text-green-500' }}">
|
|
{{ 'Suspicious' if hsb_detections else 'Clean' }}
|
|
</span>
|
|
</td>
|
|
<td class="px-6 py-4 text-base {{ 'text-red-500' if hsb_detections else 'text-gray-400' }}">{{ hsb_detections }}</td>
|
|
<td class="px-6 py-4">
|
|
{% if hsb_detections %}
|
|
<div class="text-base text-gray-400">
|
|
{% for detection in analysis_results.hsb.findings.detections %}
|
|
{% for finding in detection.findings %}
|
|
<div class="mb-1">{{ finding.type }} ({{ finding.severity }})</div>
|
|
{% endfor %}
|
|
{% endfor %}
|
|
</div>
|
|
{% else %}
|
|
<span class="text-base text-gray-400">No suspicious behavior</span>
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<!-- RedEdr Summary Section - Add this after the scanner results table -->
|
|
<div class="mt-8">
|
|
<h2 class="text-xl font-medium text-gray-100 mb-4">Process Telemetry Summary</h2>
|
|
|
|
<!-- Event Statistics Grid -->
|
|
<div class="grid grid-cols-3 gap-4 mb-6">
|
|
{% if analysis_results.rededr and analysis_results.rededr.findings %}
|
|
{% set findings = analysis_results.rededr.findings %}
|
|
{% set summary = findings.summary %}
|
|
|
|
<!-- Basic Stats -->
|
|
<div class="bg-gray-900/30 rounded-lg border border-gray-800 p-4">
|
|
<div class="flex items-center space-x-2 mb-4">
|
|
<svg class="w-5 h-5 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
|
|
</svg>
|
|
<h3 class="text-lg font-medium text-gray-200">Activity Stats</h3>
|
|
</div>
|
|
<div class="space-y-2">
|
|
<div class="flex justify-between">
|
|
<span class="text-gray-400">Total Events:</span>
|
|
<span class="text-gray-200">{{ summary.total_events }}</span>
|
|
</div>
|
|
<div class="flex justify-between">
|
|
<span class="text-gray-400">DLLs Loaded:</span>
|
|
<span class="text-gray-200">{{ summary.total_dlls }}</span>
|
|
</div>
|
|
<div class="flex justify-between">
|
|
<span class="text-gray-400">Images Loaded:</span>
|
|
<span class="text-gray-200">{{ summary.total_image_loads }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Process Information -->
|
|
<div class="bg-gray-900/30 rounded-lg border border-gray-800 p-4">
|
|
<div class="flex items-center space-x-2 mb-4">
|
|
<svg class="w-5 h-5 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
|
|
</svg>
|
|
<h3 class="text-lg font-medium text-gray-200">Process Info</h3>
|
|
</div>
|
|
<div class="space-y-2">
|
|
<div class="flex justify-between">
|
|
<span class="text-gray-400">Child Processes:</span>
|
|
<span class="text-gray-200">{{ summary.total_child_processes }}</span>
|
|
</div>
|
|
<div class="flex justify-between">
|
|
<span class="text-gray-400">Active Threads:</span>
|
|
<span class="text-gray-200">{{ summary.total_threads }}</span>
|
|
</div>
|
|
<div class="flex justify-between">
|
|
<span class="text-gray-400">Image Unloads:</span>
|
|
<span class="text-gray-200">{{ summary.total_image_unloads }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Process Details -->
|
|
<div class="bg-gray-900/30 rounded-lg border border-gray-800 p-4">
|
|
<div class="flex items-center space-x-2 mb-4">
|
|
<svg class="w-5 h-5 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
|
</svg>
|
|
<h3 class="text-lg font-medium text-gray-200">Process Details</h3>
|
|
</div>
|
|
<div class="space-y-2 text-sm">
|
|
<div class="flex flex-col">
|
|
<span class="text-gray-400">PID:</span>
|
|
<span class="text-gray-200">{{ findings.process_info.pid }}</span>
|
|
</div>
|
|
<div class="flex flex-col">
|
|
<span class="text-gray-400">Parent PID:</span>
|
|
<span class="text-gray-200">{{ findings.process_info.parent_pid }}</span>
|
|
</div>
|
|
<div class="flex flex-col">
|
|
<span class="text-gray-400">Status:</span>
|
|
<span class="text-gray-200">{{ 'Protected' if findings.process_info.is_protected_process else 'Standard' }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% else %}
|
|
<div class="col-span-3 bg-gray-900/30 rounded-lg border border-gray-800 p-4">
|
|
<p class="text-gray-400">No RedEdr telemetry data available.</p>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<!-- Payload Output Section -->
|
|
<div class="mt-8">
|
|
<h2 class="text-xl font-medium text-gray-100 mb-4">Process Output</h2>
|
|
|
|
<div class="bg-gray-900/30 rounded-lg border border-gray-800 overflow-hidden">
|
|
<div class="p-4">
|
|
<button id="togglePayloadOutput"
|
|
class="w-full flex items-center justify-between text-left">
|
|
<div class="flex items-center space-x-2">
|
|
<svg id="payloadChevron"
|
|
class="w-5 h-5 text-gray-400 transform transition-transform duration-200"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
viewBox="0 0 24 24">
|
|
<path stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
stroke-width="2"
|
|
d="M9 5l7 7-7 7" />
|
|
</svg>
|
|
<span class="text-base font-medium text-gray-300">Captured Output</span>
|
|
</div>
|
|
<span class="text-sm px-2 py-1 rounded-full {{ 'bg-green-500/10 text-green-500' if analysis_results.get('process_output', {}).get('stdout') or analysis_results.get('process_output', {}).get('stderr') else 'bg-gray-800 text-gray-400' }}">
|
|
{{ 'Output Available' if analysis_results.get('process_output', {}).get('stdout') or analysis_results.get('process_output', {}).get('stderr') else 'No Output' }}
|
|
</span>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Collapsible Content -->
|
|
<div id="payloadOutputContent"
|
|
class="hidden border-t border-gray-800">
|
|
<div class="p-4 space-y-4">
|
|
<!-- STDOUT Section -->
|
|
{% if analysis_results.get('process_output', {}).get('stdout') %}
|
|
<div class="space-y-2">
|
|
<h5 class="text-sm font-medium text-gray-400">Standard Output</h5>
|
|
<div class="bg-black/30 rounded p-4 font-mono text-sm">
|
|
<pre class="text-gray-300 whitespace-pre-wrap">{{ analysis_results.get('process_output', {}).get('stdout') }}</pre>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- STDERR Section -->
|
|
{% if analysis_results.get('process_output', {}).get('stderr') %}
|
|
<div class="space-y-2">
|
|
<h5 class="text-sm font-medium text-gray-400">Standard Error</h5>
|
|
<div class="bg-black/30 rounded p-4 font-mono text-sm">
|
|
<pre class="text-red-300 whitespace-pre-wrap">{{ analysis_results.get('process_output', {}).get('stderr') }}</pre>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Additional Info -->
|
|
{% if analysis_results.get('process_output', {}) %}
|
|
<div class="text-sm text-gray-500 italic">
|
|
{% if analysis_results.get('process_output', {}).get('output_truncated') %}
|
|
Output was truncated due to size limitations
|
|
{% if analysis_results.get('process_output', {}).get('exit_code') is not none %} • {% endif %}
|
|
{% endif %}
|
|
{% if analysis_results.get('process_output', {}).get('exit_code') is not none %}
|
|
Process exit code: {{ analysis_results.get('process_output', {}).get('exit_code') }}
|
|
{% endif %}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const toggleBtn = document.getElementById('togglePayloadOutput');
|
|
const content = document.getElementById('payloadOutputContent');
|
|
const chevron = document.getElementById('payloadChevron');
|
|
|
|
if (toggleBtn && content && chevron) {
|
|
toggleBtn.addEventListener('click', function() {
|
|
content.classList.toggle('hidden');
|
|
chevron.classList.toggle('rotate-90');
|
|
});
|
|
}
|
|
});
|
|
</script>
|
|
{% endblock %}
|