diff --git a/app/routes.py b/app/routes.py index f3d9dac..d336044 100644 --- a/app/routes.py +++ b/app/routes.py @@ -412,44 +412,87 @@ def register_routes(app): @app.route('/file//', methods=['GET']) def get_analysis_results(target, analysis_type): try: - # Find result folder for the given hash result_path = find_file_by_hash(target, app.config['upload']['result_folder']) if not result_path: - return jsonify({'error': 'Results not found'}), 404 + return render_template('error.html', error='Results not found'), 404 + + # Load file info + file_info_path = os.path.join(result_path, 'file_info.json') + if not os.path.exists(file_info_path): + return render_template('error.html', error='File info not found'), 404 + + with open(file_info_path, 'r') as f: + file_info = json.load(f) - # Handle different types of requests if analysis_type == 'info': - # Read and return the file info - file_info_path = os.path.join(result_path, 'file_info.json') - if not os.path.exists(file_info_path): - return jsonify({'error': 'File info not found'}), 404 - - with open(file_info_path, 'r') as f: - results = json.load(f) - + return render_template('file_info.html', file_info=file_info) + elif analysis_type in ['static', 'dynamic']: - # Read and return the analysis results results_file = f'{analysis_type}_analysis_results.json' results_path = os.path.join(result_path, results_file) if not os.path.exists(results_path): - return jsonify({'error': 'Analysis results not found'}), 404 - + return render_template('error.html', error=f'No {analysis_type} analysis results found'), 404 + with open(results_path, 'r') as f: - results = json.load(f) + analysis_results = json.load(f) - else: - return jsonify({'error': 'Invalid analysis type'}), 400 + if analysis_type == 'static': + # Calculate detection counts for static analysis with safe defaults + try: + yara_matches = analysis_results.get('yara', {}).get('matches', []) + yara_detections = len(yara_matches) if yara_matches is not None else 0 + except: + yara_detections = 0 - return jsonify({ - 'status': 'success', - 'results': results - }) + try: + checkplz_findings = analysis_results.get('checkplz', {}).get('findings', {}) + checkplz_detections = 1 if checkplz_findings and checkplz_findings.get('initial_threat') else 0 + except: + checkplz_detections = 0 + + # Format scan duration as MM:SS.mmm + try: + scan_duration = analysis_results.get('checkplz', {}).get('findings', {}).get('scan_results', {}).get('scan_duration', 0) + if scan_duration is None: + scan_duration = 0 + minutes = int(scan_duration // 60) + seconds = int(scan_duration % 60) + milliseconds = int((scan_duration % 1) * 1000) + formatted_duration = f"{minutes:02d}:{seconds:02d}.{milliseconds:03d}" + except: + formatted_duration = "00:00.000" + + return render_template('static_analysis.html', + file_info=file_info, + analysis_results=analysis_results, + yara_detections=yara_detections, + checkplz_detections=checkplz_detections, + scan_duration=formatted_duration) + + elif analysis_type == 'dynamic': + # Calculate detection counts for dynamic analysis + yara_detections = len(analysis_results.get('yara', {}).get('matches', [])) if analysis_results.get('yara') else 0 + pesieve_detections = analysis_results.get('pe_sieve', {}).get('findings', {}).get('total_suspicious', 0) + moneta_detections = ( + analysis_results.get('moneta', {}).get('findings', {}).get('total_private_rwx', 0) + + analysis_results.get('moneta', {}).get('findings', {}).get('total_abnormal_private_exec', 0) + ) + patriot_detections = len(analysis_results.get('patriot', {}).get('findings', {}).get('findings', [])) + hsb_detections = analysis_results.get('hsb', {}).get('findings', {}).get('summary', {}).get('total_findings', 0) + + return render_template('dynamic_analysis.html', + file_info=file_info, + analysis_results=analysis_results, + yara_detections=yara_detections, + pesieve_detections=pesieve_detections, + moneta_detections=moneta_detections, + patriot_detections=patriot_detections, + hsb_detections=hsb_detections) + + return render_template('error.html', error='Invalid analysis type'), 400 except Exception as e: - return jsonify({ - 'status': 'error', - 'error': str(e) - }), 500 + return render_template('error.html', error=str(e)), 500 @app.route('/cleanup', methods=['POST']) def cleanup(): diff --git a/app/static/images/summary.jpg b/app/static/images/summary.jpg deleted file mode 100644 index 51a98d8..0000000 Binary files a/app/static/images/summary.jpg and /dev/null differ diff --git a/app/templates/dynamic_analysis.html b/app/templates/dynamic_analysis.html new file mode 100644 index 0000000..71621cf --- /dev/null +++ b/app/templates/dynamic_analysis.html @@ -0,0 +1,139 @@ +{% extends "base.html" %} + +{% block content %} +
+ +
+
+

Analysis Summary

+

Comprehensive overview of all scan results.

+
+ +
+ + +
+
+

Target Process

+ {% if analysis_results.moneta and analysis_results.moneta.findings.process_info %} + {% set info = analysis_results.moneta.findings.process_info %} +

+ Name: {{ info.name }}
+ PID: {{ info.pid }}
+ Path: {{ info.path }} +

+ {% endif %} +
+
+ + +
+
+
Overall Status
+
+ {{ 'Threats Detected' if yara_detections + pesieve_detections + moneta_detections + patriot_detections + hsb_detections > 0 else 'Clean' }} +
+
+
+
Total Detections
+
{{ yara_detections + pesieve_detections + moneta_detections + patriot_detections + hsb_detections }}
+
+
+
Scan Duration
+
+ {{ "%.2f"|format(analysis_results.moneta.findings.scan_duration if analysis_results.moneta else 0) }}s +
+
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ScannerStatusDetectionsDetails
YARA + + {{ 'Suspicious' if yara_detections else 'Clean' }} + + {{ yara_detections }} + {{ yara_detections|string + ' rule matches found' if yara_detections else 'No threats detected' }} +
PE-sieve + + {{ 'Suspicious' if pesieve_detections else 'Clean' }} + + {{ pesieve_detections }} + {{ pesieve_detections|string + ' suspicious modifications found' if pesieve_detections else 'No modifications detected' }} +
Moneta + + {{ 'Suspicious' if moneta_detections else 'Clean' }} + + {{ moneta_detections }} + {{ 'Memory anomalies found' if moneta_detections else 'No anomalies detected' }} +
Patriot + + {{ 'Suspicious' if patriot_detections else 'Clean' }} + + {{ patriot_detections }} + {{ patriot_detections|string + ' suspicious activities found' if patriot_detections else 'No suspicious activities' }} +
Hunt-Sleeping-Beacons + + {{ 'Suspicious' if hsb_detections else 'Clean' }} + + {{ hsb_detections }} + {{ 'Suspicious behavior detected' if hsb_detections else 'No suspicious behavior' }} +
+
+ + +
+{% endblock %} \ No newline at end of file diff --git a/app/templates/error.html b/app/templates/error.html new file mode 100644 index 0000000..2ea72b3 --- /dev/null +++ b/app/templates/error.html @@ -0,0 +1,38 @@ +{% extends "base.html" %} + +{% block content %} +
+
+ +
+ + + +
+ + +

Something went wrong

+

{{ error }}

+ + +
+ + + +
+
+
+{% endblock %} \ No newline at end of file diff --git a/app/templates/file_info.html b/app/templates/file_info.html new file mode 100644 index 0000000..3fe1183 --- /dev/null +++ b/app/templates/file_info.html @@ -0,0 +1,166 @@ +{% extends "base.html" %} + +{% block content %} +
+ +
+
+

{{ file_info.original_name }}

+

MD5: {{ file_info.md5 }}

+
+ + {{ file_info.entropy_analysis.detection_risk }} Risk + +
+ +
+ + +
+ +
+

Basic Information

+
+
+

File Size

+

{{ file_info.size|filesizeformat }}

+
+
+

File Type

+

{{ file_info.mime_type }}

+
+
+

Upload Time

+

{{ file_info.upload_time }}

+
+
+

SHA256

+

{{ file_info.sha256 }}

+
+
+

Entropy

+

{{ "%.2f"|format(file_info.entropy) }}

+
+
+
+ + {% if file_info.pe_info %} + +
+

PE Information

+
+
+

File Type

+

{{ file_info.pe_info.file_type }}

+
+
+

Machine Type

+

{{ file_info.pe_info.machine_type }}

+
+
+

Subsystem

+

{{ file_info.pe_info.subsystem }}

+
+
+

Compile Time

+

{{ file_info.pe_info.compile_time }}

+
+
+

Entry Point

+

{{ file_info.pe_info.entry_point }}

+
+
+
+ + +
+

Detection Notes

+
    + {% for note in file_info.pe_info.detection_notes %} +
  • + + + + {{ note }} +
  • + {% endfor %} +
+
+ + +
+

PE Sections

+
+ + + + + + + + + + + {% for section in file_info.pe_info.sections %} + + + + + + + {% endfor %} + +
NameSizeEntropyNotes
+ + {{ section.name }} + + {{ section.size|filesizeformat }} + + {{ "%.2f"|format(section.entropy) }} + + +
+ {% for note in section.detection_notes %} +
{{ note }}
+ {% endfor %} +
+
+
+
+ + + {% if file_info.pe_info.suspicious_imports %} +
+

Suspicious Imports

+
+ {% for import in file_info.pe_info.suspicious_imports %} +
+

{{ import.dll }}!{{ import.function }}

+

{{ import.note }}

+
+ {% endfor %} +
+
+ {% endif %} + {% endif %} +
+{% endblock %} \ No newline at end of file diff --git a/app/templates/static_analysis.html b/app/templates/static_analysis.html new file mode 100644 index 0000000..39fac6e --- /dev/null +++ b/app/templates/static_analysis.html @@ -0,0 +1,92 @@ +{% extends "base.html" %} + +{% block content %} +
+ +
+
+

Analysis Summary

+

Comprehensive overview of all scan results.

+
+ +
+ + +
+
+

Target File

+

+ File Path: + {{ analysis_results.checkplz.findings.scan_results.file_path if analysis_results.checkplz else file_info.original_name }} +

+
+
+ + +
+
+
Overall Status
+
+ {{ 'Threats Detected' if yara_detections or checkplz_detections else 'Clean' }} +
+
+
+
Total Detections
+
{{ yara_detections + checkplz_detections }}
+
+
+
Scan Duration
+
+ {{ scan_duration }} +
+
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
ScannerStatusDetectionsDetails
YARA + + {{ 'Suspicious' if yara_detections else 'Clean' }} + + {{ yara_detections }} + {{ yara_detections|string + ' rule matches found' if yara_detections else 'No threats detected' }} +
CheckPlz + + {{ 'Suspicious' if checkplz_detections else 'Clean' }} + + {{ checkplz_detections }} + {{ analysis_results.checkplz.findings.initial_threat if checkplz_detections else 'No threats detected' }} +
+
+ + +
+{% endblock %} \ No newline at end of file