From f40bd4e2ca59687fe0066636ef609afbd4f78354 Mon Sep 17 00:00:00 2001 From: Kevin Munoz Date: Sat, 7 Sep 2024 13:18:02 -0500 Subject: [PATCH] yo a este lo conozco --- .env.example | 6 + .gitignore | 1 + app.py | 146 +++++++++-- requirements.txt | 45 ++-- templates/index.html | 574 ++++++++++++++++++++++++------------------- 5 files changed, 477 insertions(+), 295 deletions(-) create mode 100644 .env.example diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..fce1179 --- /dev/null +++ b/.env.example @@ -0,0 +1,6 @@ +DB_HOST= +DB_USER= +DB_PASSWD= +DB_NAME= +DB_CHARSET=utf8mb4 +DB_COALLITION=utf8mb4_general_ci diff --git a/.gitignore b/.gitignore index 4e02557..5306746 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ /templates/upload.html app.py~ app2.py +.env diff --git a/app.py b/app.py index b966cc0..7123945 100644 --- a/app.py +++ b/app.py @@ -1,13 +1,81 @@ from flask import Flask, render_template, request, jsonify from flask_socketio import SocketIO, emit +from dotenv import load_dotenv import subprocess import uuid import os import requests +import hashlib +import mysql.connector +import filetype app = Flask(__name__) socketio = SocketIO(app) +def get_file_hashes(file_path): + hash_md5 = hashlib.md5() + hash_sha1 = hashlib.sha1() + hash_sha256 = hashlib.sha256() + + with open(file_path, "rb") as f: + for chunk in iter(lambda: f.read(4096), b""): + hash_md5.update(chunk) + hash_sha1.update(chunk) + hash_sha256.update(chunk) + + return { + "md5": hash_md5.hexdigest(), + "sha1": hash_sha1.hexdigest(), + "sha256": hash_sha256.hexdigest() + } + +def get_file_type(file_path): + kind = filetype.guess(file_path) + if kind is None: + return "Unknown" + return kind.mime + +def check_file_in_db(hashes): + connection = mysql.connector.connect( + host=os.getenv('DB_HOST'), + user=os.getenv('DB_USER'), + password=os.getenv('DB_PASSWD'), + database=os.getenv('DB_NAME'), + charset=os.getenv('DB_CHARSET'), + collation=os.getenv('DB_COALLITION') + ) + cursor = connection.cursor() + + query = "SELECT scan_result FROM file_scans WHERE md5_hash = %s OR sha1_hash = %s OR sha256_hash = %s" + cursor.execute(query, (hashes["md5"], hashes["sha1"], hashes["sha256"])) + result = cursor.fetchone() + + cursor.close() + connection.close() + + return result + +def store_file_in_db(filename, hashes, file_type, scan_result): + connection = mysql.connector.connect( + host=os.getenv('DB_HOST'), + user=os.getenv('DB_USER'), + password=os.getenv('DB_PASSWD'), + database=os.getenv('DB_NAME'), + charset=os.getenv('DB_CHARSET'), + collation=os.getenv('DB_COALLITION') + ) + cursor = connection.cursor() + + query = """ + INSERT INTO file_scans (filename, md5_hash, sha1_hash, sha256_hash, file_type, scan_result) + VALUES (%s, %s, %s, %s, %s, %s) + """ + cursor.execute(query, (filename, hashes["md5"], hashes["sha1"], hashes["sha256"], file_type, scan_result)) + connection.commit() + + cursor.close() + connection.close() + @app.route('/', methods=['GET', 'POST']) def index(): return render_template('index.html') @@ -18,12 +86,27 @@ def upload_file(): if file: file_path = os.path.join('/tmp', f"{uuid.uuid4()}_{file.filename}") file.save(file_path) - + + # Obtener los hashes y el tipo de archivo + hashes = get_file_hashes(file_path) + file_type = get_file_type(file_path) + + # Verificar si el archivo ya fue escaneado + existing_result = check_file_in_db(hashes) + if existing_result: + os.remove(file_path) + # Formatear el resultado del escaneo para que sea más legible + scan_result = format_scan_result(existing_result[0]) + return jsonify({ + 'message': 'Este archivo ya lo he visto antes.', + 'scan_result': scan_result + }) + # Ejecuta el escaneo en un hilo separado para no bloquear la aplicación - socketio.start_background_task(target=scan_file, file_path=file_path) - - return 'Archivo subido exitosamente: ' + file.filename - return 'No se recibió ningún archivo', 400 + socketio.start_background_task(target=scan_file, file_path=file_path, hashes=hashes, file_type=file_type, filename=file.filename) + + return jsonify({'message': 'Archivo subido exitosamente: ' + file.filename}) + return jsonify({'error': 'No se recibió ningún archivo'}), 400 @app.route('/scan_url', methods=['POST']) def scan_url(): @@ -40,37 +123,68 @@ def scan_url(): response = requests.get(url) if response.status_code != 200: return jsonify({'error': f'Error al descargar la URL: {response.status_code}'}), 400 - + file_path = os.path.join('/tmp', f"{uuid.uuid4()}_downloaded_content") with open(file_path, 'wb') as temp_file: temp_file.write(response.content) - # Ejecutar el escaneo en un hilo separado para no bloquear la aplicación - socketio.start_background_task(target=scan_file, file_path=file_path) + # Obtener los hashes y el tipo de archivo + hashes = get_file_hashes(file_path) + file_type = get_file_type(file_path) - return jsonify({'message': f'Archivo descargado y guardado como {file_path}'}), 200 + # Verificar si el archivo ya fue escaneado + existing_result = check_file_in_db(hashes) + if existing_result: + os.remove(file_path) + # Formatear el resultado del escaneo para que sea más legible + scan_result = format_scan_result(existing_result[0]) + return jsonify({ + 'message': 'Este archivo ya lo he visto antes.', + 'scan_result': scan_result + }) + + # Ejecutar el escaneo en un hilo separado para no bloquear la aplicación + socketio.start_background_task(target=scan_file, file_path=file_path, hashes=hashes, file_type=file_type, filename=filename) + + return jsonify({'message': f'Archivo descargado y guardado como {file_path}. El escaneo está en progreso.'}), 200 except Exception as e: return jsonify({'error': str(e)}), 500 -def scan_file(file_path): +def scan_file(file_path, hashes, file_type, filename): try: + # Ejecuta el comando de escaneo scan_command = ["clamscan", "-r", file_path] process = subprocess.Popen(scan_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) - for line in iter(process.stdout.readline, ''): - if line.strip(): - socketio.emit('scan_output', {'data': line.strip()}) + # Lee la salida y los errores usando communicate() + scan_output, error_output = process.communicate() + # Verificar el código de retorno del proceso + if process.returncode != 0: + socketio.emit('scan_output', {'data': f'Error en el escaneo: {error_output}'}) + return + + # Si no hubo errores, emitir la salida del escaneo + socketio.emit('scan_output', {'data': scan_output}) + + # Emitir mensaje de escaneo completo socketio.emit('scan_output', {'data': '--- Escaneo completado ---'}) - process.stdout.close() - process.stderr.close() - process.wait() + # Almacenar los hashes, el tipo de archivo y el resultado del escaneo en la base de datos + store_file_in_db(filename, hashes, file_type, scan_output) + except Exception as e: socketio.emit('scan_output', {'data': f'Error: {str(e)}'}) finally: + # Asegúrate de eliminar el archivo temporal después del escaneo if os.path.exists(file_path): os.remove(file_path) +def format_scan_result(scan_result): + # Formatear el resultado del escaneo para mejor legibilidad + formatted_result = scan_result.replace("\n", "
") + return formatted_result + if __name__ == '__main__': socketio.run(app, debug=True) + diff --git a/requirements.txt b/requirements.txt index fbcf11d..2ecc7ec 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,21 +1,24 @@ -bidict -blinker -certifi -charset-normalizer -clamd -click -Flask -Flask-SocketIO -h11 -idna -itsdangerous -Jinja2 -MarkupSafe -pyClamd -python-engineio -python-socketio -requests -simple-websocket -urllib3 -Werkzeug -wsproto +bidict==0.23.1 +blinker==1.8.2 +certifi==2024.7.4 +charset-normalizer==3.3.2 +clamd==1.0.2 +click==8.1.7 +filetype==1.2.0 +Flask==3.0.3 +Flask-SocketIO==5.3.6 +h11==0.14.0 +idna==3.7 +itsdangerous==2.2.0 +Jinja2==3.1.4 +MarkupSafe==2.1.5 +mysql-connector-python==9.0.0 +pyClamd==0.4.0 +python-dotenv==1.0.1 +python-engineio==4.9.1 +python-socketio==5.11.3 +requests==2.32.3 +simple-websocket==1.0.0 +urllib3==2.2.2 +Werkzeug==3.0.3 +wsproto==1.2.0 diff --git a/templates/index.html b/templates/index.html index 9e07283..bc27a7e 100644 --- a/templates/index.html +++ b/templates/index.html @@ -1,313 +1,371 @@ - + Condor Business Solutions SecureScan - - + +
-

Condor Business Solutions CyberScan|Terminal Web de Escaneo

- - - - - -
- +

Condor Business Solutions CyberScan|Terminal Web de Escaneo

+ + + + + +
+
- +