diff --git a/Log Manager/Database Schema/shellm_sessions_answers.sql b/Log Manager/Database Schema/shellm_sessions_answers.sql
new file mode 100644
index 0000000..d69846b
--- /dev/null
+++ b/Log Manager/Database Schema/shellm_sessions_answers.sql
@@ -0,0 +1,44 @@
+-- MySQL dump 10.13 Distrib 8.0.40, for Win64 (x86_64)
+--
+-- Host: localhost Database: shellm_sessions
+-- ------------------------------------------------------
+-- Server version 8.0.40
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!50503 SET NAMES utf8 */;
+/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
+/*!40103 SET TIME_ZONE='+00:00' */;
+/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
+/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
+/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
+/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
+
+--
+-- Table structure for table `answers`
+--
+
+DROP TABLE IF EXISTS `answers`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!50503 SET character_set_client = utf8mb4 */;
+CREATE TABLE `answers` (
+ `answer_id` int NOT NULL AUTO_INCREMENT,
+ `command_id` int DEFAULT NULL,
+ `answer` text NOT NULL,
+ PRIMARY KEY (`answer_id`),
+ KEY `command_id` (`command_id`),
+ CONSTRAINT `answers_ibfk_1` FOREIGN KEY (`command_id`) REFERENCES `commands` (`command_id`)
+) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
+/*!40101 SET character_set_client = @saved_cs_client */;
+/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
+
+/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
+/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
+/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
+/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
+/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
+/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
+/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
+
+-- Dump completed on 2024-12-06 9:42:51
diff --git a/Log Manager/Database Schema/shellm_sessions_attacker_session.sql b/Log Manager/Database Schema/shellm_sessions_attacker_session.sql
new file mode 100644
index 0000000..b9b6746
--- /dev/null
+++ b/Log Manager/Database Schema/shellm_sessions_attacker_session.sql
@@ -0,0 +1,30 @@
+-- MySQL dump 10.13 Distrib 8.0.40, for Win64 (x86_64)
+--
+-- Host: localhost Database: shellm_sessions
+-- ------------------------------------------------------
+-- Server version 8.0.40
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!50503 SET NAMES utf8 */;
+/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
+/*!40103 SET TIME_ZONE='+00:00' */;
+/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
+/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
+/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
+/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
+
+--
+-- Table structure for table `attacker_session`
+--
+
+DROP TABLE IF EXISTS `attacker_session`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!50503 SET character_set_client = utf8mb4 */;
+CREATE TABLE `attacker_session` (
+ `attacker_session_id` int NOT NULL AUTO_INCREMENT,
+ `src_ip` varchar(45) NOT NULL,
+ PRIMARY KEY (`attacker_session_id`)
+) ENGINE=InnoDB AUTO_INCREMENT=224 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
+/*!40101 SET character_set_client = @saved_cs_client */;
diff --git a/Log Manager/Database Schema/shellm_sessions_commands.sql b/Log Manager/Database Schema/shellm_sessions_commands.sql
new file mode 100644
index 0000000..e1b698a
--- /dev/null
+++ b/Log Manager/Database Schema/shellm_sessions_commands.sql
@@ -0,0 +1,44 @@
+-- MySQL dump 10.13 Distrib 8.0.40, for Win64 (x86_64)
+--
+-- Host: localhost Database: shellm_sessions
+-- ------------------------------------------------------
+-- Server version 8.0.40
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!50503 SET NAMES utf8 */;
+/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
+/*!40103 SET TIME_ZONE='+00:00' */;
+/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
+/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
+/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
+/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
+
+--
+-- Table structure for table `commands`
+--
+
+DROP TABLE IF EXISTS `commands`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!50503 SET character_set_client = utf8mb4 */;
+CREATE TABLE `commands` (
+ `command_id` int NOT NULL AUTO_INCREMENT,
+ `shellm_session_id` int DEFAULT NULL,
+ `command` text NOT NULL,
+ PRIMARY KEY (`command_id`),
+ KEY `shellm_session_id` (`shellm_session_id`),
+ CONSTRAINT `commands_ibfk_1` FOREIGN KEY (`shellm_session_id`) REFERENCES `shellm_session` (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=153 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
+/*!40101 SET character_set_client = @saved_cs_client */;
+/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
+
+/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
+/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
+/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
+/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
+/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
+/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
+/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
+
+-- Dump completed on 2024-12-06 9:42:50
diff --git a/Log Manager/Database Schema/shellm_sessions_shellm_session.sql b/Log Manager/Database Schema/shellm_sessions_shellm_session.sql
new file mode 100644
index 0000000..c2b4ea0
--- /dev/null
+++ b/Log Manager/Database Schema/shellm_sessions_shellm_session.sql
@@ -0,0 +1,49 @@
+-- MySQL dump 10.13 Distrib 8.0.40, for Win64 (x86_64)
+--
+-- Host: localhost Database: shellm_sessions
+-- ------------------------------------------------------
+-- Server version 8.0.40
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!50503 SET NAMES utf8 */;
+/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
+/*!40103 SET TIME_ZONE='+00:00' */;
+/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
+/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
+/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
+/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
+
+--
+-- Table structure for table `shellm_session`
+--
+
+DROP TABLE IF EXISTS `shellm_session`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!50503 SET character_set_client = utf8mb4 */;
+CREATE TABLE `shellm_session` (
+ `id` int NOT NULL AUTO_INCREMENT,
+ `ssh_session_id` int DEFAULT NULL,
+ `model` varchar(255) NOT NULL,
+ `start_time` datetime NOT NULL,
+ `end_time` datetime NOT NULL,
+ `attacker_id` int DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ KEY `ssh_session_id` (`ssh_session_id`),
+ KEY `fk_attacker` (`attacker_id`),
+ CONSTRAINT `fk_attacker` FOREIGN KEY (`attacker_id`) REFERENCES `attacker_session` (`attacker_session_id`),
+ CONSTRAINT `shellm_session_ibfk_1` FOREIGN KEY (`ssh_session_id`) REFERENCES `ssh_session` (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=42 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
+/*!40101 SET character_set_client = @saved_cs_client */;
+/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
+
+/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
+/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
+/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
+/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
+/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
+/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
+/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
+
+-- Dump completed on 2024-12-06 9:42:51
diff --git a/Log Manager/Database Schema/shellm_sessions_ssh_session.sql b/Log Manager/Database Schema/shellm_sessions_ssh_session.sql
new file mode 100644
index 0000000..fb6063f
--- /dev/null
+++ b/Log Manager/Database Schema/shellm_sessions_ssh_session.sql
@@ -0,0 +1,46 @@
+-- MySQL dump 10.13 Distrib 8.0.40, for Win64 (x86_64)
+--
+-- Host: localhost Database: shellm_sessions
+-- ------------------------------------------------------
+-- Server version 8.0.40
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!50503 SET NAMES utf8 */;
+/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
+/*!40103 SET TIME_ZONE='+00:00' */;
+/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
+/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
+/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
+/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
+
+--
+-- Table structure for table `ssh_session`
+--
+
+DROP TABLE IF EXISTS `ssh_session`;
+/*!40101 SET @saved_cs_client = @@character_set_client */;
+/*!50503 SET character_set_client = utf8mb4 */;
+CREATE TABLE `ssh_session` (
+ `id` int NOT NULL AUTO_INCREMENT,
+ `username` varchar(255) NOT NULL,
+ `time_date` datetime NOT NULL,
+ `src_ip` varchar(45) NOT NULL,
+ `dst_ip` varchar(45) NOT NULL,
+ `src_port` int DEFAULT NULL,
+ `dst_port` int DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=227 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
+/*!40101 SET character_set_client = @saved_cs_client */;
+/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
+
+/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
+/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
+/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
+/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
+/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
+/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
+/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
+
+-- Dump completed on 2024-12-06 9:42:50
diff --git a/Log Manager/dashboard.html b/Log Manager/dashboard.html
new file mode 100644
index 0000000..52f04a0
--- /dev/null
+++ b/Log Manager/dashboard.html
@@ -0,0 +1,104 @@
+
+
+
+
+
+ Log Manager Dashboard
+
+
+
+ Log Manager Dashboard
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ID |
+ Username |
+ Time & Date |
+ Source IP |
+ Destination IP |
+ Destination Port |
+
+
+
+
+
+
+
+
+
+
+
+ ID |
+ ssh_session_id |
+ model |
+ start_time |
+ end_time |
+ attacker_id |
+
+
+
+
+
+
+
+
+
+
+
+ command_id |
+ Command |
+ answer_id |
+ Answer |
+
+
+
+
+
+
+
+
+
+
+
+ command_id |
+ shellm_session_id |
+ Command |
+
+
+
+
+
+
+
+
+
+
+
+ answer_id |
+ command_id |
+ answer |
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Log Manager/db_credentials.env b/Log Manager/db_credentials.env
new file mode 100644
index 0000000..ac1a475
--- /dev/null
+++ b/Log Manager/db_credentials.env
@@ -0,0 +1,3 @@
+MYSQL_USER=
+MYSQL_PASSWORD=
+MYSQL_HOST=
diff --git a/Log Manager/log_manager.py b/Log Manager/log_manager.py
new file mode 100644
index 0000000..b2c0eed
--- /dev/null
+++ b/Log Manager/log_manager.py
@@ -0,0 +1,112 @@
+from flask import Flask, jsonify, render_template
+from flask_cors import CORS # Import Flask-CORS
+import ssh_module
+import mysql.connector
+from datetime import datetime, timedelta
+from dotenv import load_dotenv
+import os
+
+# Load environment variables from .env file
+load_dotenv('db_credentials.env')
+
+MYSQL_USER = os.getenv('MYSQL_USER')
+MYSQL_PASSWORD = os.getenv('MYSQL_PASSWORD')
+MYSQL_HOST = os.getenv('MYSQL_HOST')
+
+def connect_to_db():
+ # Connect to the MySQL server
+ conn = mysql.connector.connect(
+ host=MYSQL_HOST,
+ user=MYSQL_USER,
+ password=MYSQL_PASSWORD,
+ database='shellm_sessions'
+ )
+ cursor = conn.cursor()
+
+ return conn, cursor
+
+app = Flask(__name__)
+
+CORS(app)
+
+# Route to fetch SSH sessions from the database
+@app.route('/ssh_sessions', methods=['GET'])
+def get_ssh_sessions():
+ conn, cursor = connect_to_db()
+ if conn is None:
+ return jsonify({"error": "Database connection failed"}), 500
+
+ try:
+ cursor.execute("SELECT * FROM ssh_session ORDER BY id DESC;")
+ sessions = cursor.fetchall() # Fetch data as a list of dictionaries
+ return jsonify(sessions)
+ except Exception as e:
+ return jsonify({"error": str(e)}), 500
+ finally:
+ cursor.close()
+ conn.close()
+
+@app.route('/shellm_sessions', methods=['GET'])
+def get_shellm_sessions():
+ conn, cursor = connect_to_db()
+ cursor.execute("SELECT * FROM shellm_session ORDER BY id DESC;")
+ sessions = cursor.fetchall()
+ cursor.close()
+ conn.close()
+
+ return jsonify(sessions)
+
+@app.route('/commands', methods=['GET'])
+def get_commands():
+ conn, cursor = connect_to_db()
+ cursor.execute("SELECT * FROM commands ORDER BY command_id DESC;")
+ commands = cursor.fetchall()
+ cursor.close()
+ conn.close()
+
+ return jsonify(commands)
+
+@app.route('/answers', methods=['GET'])
+def get_answers():
+ conn, cursor = connect_to_db()
+ cursor.execute("SELECT * FROM answers ORDER BY answer_id DESC;")
+ answers = cursor.fetchall()
+ cursor.close()
+ conn.close()
+
+ return jsonify(answers)
+
+# Route to render the dashboard
+@app.route('/', methods=['GET'])
+def dashboard():
+ return render_template('dashboard.html')
+
+@app.route('/commands_answers/', methods=['GET'])
+def get_commands_answers(shellm_session_id):
+ conn, cursor = connect_to_db()
+
+ # Fetch commands and their associated answers
+ cursor.execute("""
+ SELECT c.command_id, c.command, a.answer_id, COALESCE(a.answer, 'No answer') AS answer
+ FROM commands c
+ LEFT JOIN answers a ON c.command_id = a.command_id
+ WHERE c.shellm_session_id = %s
+ """, (shellm_session_id,))
+
+ results = cursor.fetchall()
+ conn.close()
+
+ # Return as a JSON response
+ # Return as a JSON response
+ return jsonify([
+ {
+ "command_id": row[0],
+ "command": row[1],
+ "answer_id": row[2],
+ "answer": row[3]
+ }
+ for row in results
+ ])
+
+if __name__ == "__main__":
+ app.run(debug=True)
\ No newline at end of file
diff --git a/Log Manager/script.js b/Log Manager/script.js
new file mode 100644
index 0000000..cb74775
--- /dev/null
+++ b/Log Manager/script.js
@@ -0,0 +1,388 @@
+// Function to fetch SSH session data from the Flask server
+function fetchSSH_Sessions() {
+ fetch('http://127.0.0.1:5000/ssh_sessions')
+ .then(response => response.json())
+ .then(data => {
+ displaySSHSessions(data);
+ })
+ .catch(error => {
+ console.error('Error fetching SSH sessions:', error);
+ });
+}
+
+// Function to fetch shelLM sessions data from the Flask server
+function fetchShelLM_Sessions() {
+ fetch('http://127.0.0.1:5000/shellm_sessions')
+ .then(response => response.json())
+ .then(data => {
+ displayshelLMSessions(data);
+ })
+ .catch(error => {
+ console.error('Error fetching shelLM sessions:', error);
+ });
+}
+
+// Function to fetch Commands data from the Flask server
+function fetchCommands() {
+ fetch('http://127.0.0.1:5000/commands')
+ .then(response => response.json())
+ .then(data => {
+ displayCommands(data);
+ })
+ .catch(error => {
+ console.error('Error fetching Commands:', error);
+ });
+}
+
+// Function to fetch Answers data from the Flask server
+function fetchAnswers() {
+ fetch('http://127.0.0.1:5000/answers')
+ .then(response => response.json())
+ .then(data => {
+ displayAnswers(data);
+ })
+ .catch(error => {
+ console.error('Error fetching Answers:', error);
+ });
+}
+
+// Function to display SSH sessions in the table
+function displaySSHSessions(sessions) {
+ console.log("Sessions data received:", sessions);
+
+ const table = document.getElementById("ssh-sessions-table"); // Reference to the table
+ const tableBody = document.getElementById("ssh-sessions-table-body");
+
+ if (!table || !tableBody) {
+ console.error("Table or table body with ID 'ssh-sessions-table' or 'ssh-sessions-table-body' not found.");
+ return;
+ }
+
+ // Make sure the table is visible
+ table.style.display = "table"; // Unhide the table
+
+ // Clear previous entries
+ tableBody.innerHTML = "";
+
+ // Check if 'sessions' is an array and contains valid data
+ if (Array.isArray(sessions) && sessions.length > 0) {
+ sessions.forEach((session, index) => {
+ console.log(`Processing session ${index}:`, session);
+
+ if (!Array.isArray(session) || session.length < 7) {
+ console.error("Invalid session data:", session);
+ return;
+ }
+
+ const row = document.createElement("tr");
+
+ const idCell = document.createElement("td");
+ idCell.textContent = session[0];
+
+ const usernameCell = document.createElement("td");
+ usernameCell.textContent = session[1];
+
+ const timeDateCell = document.createElement("td");
+ timeDateCell.textContent = session[2];
+
+ const srcIPCell = document.createElement("td");
+ srcIPCell.textContent = session[3];
+
+ const dstIPCell = document.createElement("td");
+ dstIPCell.textContent = session[4];
+
+ const dstPortCell = document.createElement("td");
+ dstPortCell.textContent = session[6];
+
+ row.appendChild(idCell);
+ row.appendChild(usernameCell);
+ row.appendChild(timeDateCell);
+ row.appendChild(srcIPCell);
+ row.appendChild(dstIPCell);
+ row.appendChild(dstPortCell);
+
+ tableBody.appendChild(row);
+ });
+
+ console.log("Table populated successfully.");
+ } else {
+ console.error("Invalid data structure received:", sessions);
+ }
+}
+
+
+// Function to display SSH sessions in the table
+function displayshelLMSessions(sessions) {
+ console.log("Sessions data received:", sessions);
+
+ const table = document.getElementById("shellm-sessions-table"); // Reference to the table
+ const tableBody = document.getElementById("shellm-sessions-table-body");
+
+ if (!table || !tableBody) {
+ console.error("Table or table body with ID 'shellm-sessions-table' or 'shellm-sessions-table-body' not found.");
+ return;
+ }
+
+ // Make sure the table is visible
+ table.style.display = "table"; // Unhide the table
+
+ // Clear previous entries
+ tableBody.innerHTML = "";
+
+ // Check if 'sessions' is an array and contains valid data
+ if (Array.isArray(sessions) && sessions.length > 0) {
+ sessions.forEach((session, index) => {
+ console.log(`Processing session ${index}:`, session);
+
+ if (!Array.isArray(session) || session.length < 6) {
+ console.error("Invalid session data:", session);
+ return;
+ }
+
+ const row = document.createElement("tr");
+
+ const idCell = document.createElement("td");
+ idCell.textContent = session[0];
+ idCell.style.cursor = "pointer";
+ idCell.addEventListener("click", () => fetchAndDisplayCommandsAnswers(session[0]));
+
+ const ssh_session_idCell = document.createElement("td");
+ ssh_session_idCell.textContent = session[1];
+
+ const modelCell = document.createElement("td");
+ modelCell.textContent = session[2];
+
+ const start_timeCell = document.createElement("td");
+ start_timeCell.textContent = session[3];
+
+ const end_timeCell = document.createElement("td");
+ end_timeCell.textContent = session[4];
+
+ const attacker_idCell = document.createElement("td");
+ attacker_idCell.textContent = session[5];
+
+ row.appendChild(idCell);
+ row.appendChild(ssh_session_idCell);
+ row.appendChild(modelCell);
+ row.appendChild(start_timeCell);
+ row.appendChild(end_timeCell);
+ row.appendChild(attacker_idCell);
+
+ tableBody.appendChild(row);
+ });
+
+ console.log("Table populated successfully.");
+ } else {
+ console.error("Invalid data structure received:", sessions);
+ }
+}
+
+// Function to display SSH sessions in the table
+function displayCommands(sessions) {
+ console.log("Commands data received:", sessions);
+
+ const table = document.getElementById("commands-table"); // Reference to the table
+ const tableBody = document.getElementById("commands-table-body");
+
+ if (!table || !tableBody) {
+ console.error("Table or table body with ID 'commands-table' or 'commands-table-body' not found.");
+ return;
+ }
+
+ // Make sure the table is visible
+ table.style.display = "table"; // Unhide the table
+
+ // Clear previous entries
+ tableBody.innerHTML = "";
+
+ // Check if 'sessions' is an array and contains valid data
+ if (Array.isArray(sessions) && sessions.length > 0) {
+ sessions.forEach((session, index) => {
+ console.log(`Processing command ${index}:`, session);
+
+ if (!Array.isArray(session) || session.length < 3) {
+ console.error("Invalid commands data:", session);
+ return;
+ }
+
+ const row = document.createElement("tr");
+
+ const idCell = document.createElement("td");
+ idCell.textContent = session[0];
+
+ const shellm_session_idCell = document.createElement("td");
+ shellm_session_idCell.textContent = session[1];
+
+ const commandCell = document.createElement("td");
+ commandCell.textContent = session[2];
+
+ row.appendChild(idCell);
+ row.appendChild(shellm_session_idCell);
+ row.appendChild(commandCell);
+
+ tableBody.appendChild(row);
+ });
+
+ console.log("Table populated successfully.");
+ } else {
+ console.error("Invalid data structure received:", sessions);
+ }
+}
+
+// Function to display SSH sessions in the table
+function displayAnswers(sessions) {
+ console.log("Answers data received:", sessions);
+
+ const table = document.getElementById("answers-table"); // Reference to the table
+ const tableBody = document.getElementById("answers-table-body");
+
+ if (!table || !tableBody) {
+ console.error("Table or table body with ID 'answers-table' or 'answers-table-body' not found.");
+ return;
+ }
+
+ // Make sure the table is visible
+ table.style.display = "table"; // Unhide the table
+
+ // Clear previous entries
+ tableBody.innerHTML = "";
+
+ // Check if 'sessions' is an array and contains valid data
+ if (Array.isArray(sessions) && sessions.length > 0) {
+ sessions.forEach((session, index) => {
+ console.log(`Processing answer ${index}:`, session);
+
+ if (!Array.isArray(session) || session.length < 3) {
+ console.error("Invalid answer data:", session);
+ return;
+ }
+
+ const row = document.createElement("tr");
+
+ const idCell = document.createElement("td");
+ idCell.textContent = session[0];
+
+ const command_idCell = document.createElement("td");
+ command_idCell.textContent = session[1];
+
+ const answerCell = document.createElement("td");
+ answerCell.textContent = session[2];
+
+ row.appendChild(idCell);
+ row.appendChild(command_idCell);
+ row.appendChild(answerCell);
+
+ tableBody.appendChild(row);
+ });
+
+ console.log("Table populated successfully.");
+ } else {
+ console.error("Invalid data structure received:", sessions);
+ }
+}
+
+// Function to fetch and display commands and answers for a shellm session
+function fetchAndDisplayCommandsAnswers(shellmSessionID) {
+ console.log("Fetching commands and answers for ShellM Session ID:", shellmSessionID);
+
+ fetch(`http://127.0.0.1:5000/commands_answers/${shellmSessionID}`)
+ .then((response) => {
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+ return response.json();
+ })
+ .then((data) => {
+ const tableBody = document.getElementById("commands-answers-table-body");
+ const commandsAnswersTable = document.getElementById("commands-answers-table");
+
+ if (!tableBody || !commandsAnswersTable) {
+ console.error("Commands and Answers table elements not found in the DOM.");
+ return;
+ }
+
+ // Clear previous entries
+ tableBody.innerHTML = "";
+
+ // Show the table
+ commandsAnswersTable.style.display = "table";
+
+ // Populate the table with the received data
+ if (Array.isArray(data) && data.length > 0) {
+ data.forEach((entry) => {
+ const row = document.createElement("tr");
+
+ // Create and populate cells
+ const commandIDCell = document.createElement("td");
+ commandIDCell.textContent = entry.command_id || "N/A";
+
+ const commandCell = document.createElement("td");
+ commandCell.textContent = entry.command || "N/A";
+
+ const answerIDCell = document.createElement("td");
+ answerIDCell.textContent = entry.answer_id || "N/A";
+
+ const answerCell = document.createElement("td");
+ answerCell.textContent = entry.answer || "N/A";
+
+ // Append cells to the row
+ row.appendChild(commandIDCell);
+ row.appendChild(commandCell);
+ row.appendChild(answerIDCell);
+ row.appendChild(answerCell);
+
+ // Append the row to the table body
+ tableBody.appendChild(row);
+ });
+ } else {
+ // If no data is found, show a "No data available" message
+ const row = document.createElement("tr");
+ const noDataCell = document.createElement("td");
+ noDataCell.textContent = "No commands or answers found for this session.";
+ noDataCell.colSpan = 4;
+ row.appendChild(noDataCell);
+ tableBody.appendChild(row);
+ }
+ })
+ .catch((error) => console.error("Error fetching commands and answers:", error));
+}
+
+// Function to hide all tables
+function hideAllTables() {
+ const tables = document.querySelectorAll('table');
+ tables.forEach(table => table.style.display = 'none');
+}
+
+// Add event listeners to the buttons
+document.getElementById('sshSessionsBtn').addEventListener('click', () => {
+ hideAllTables();
+ fetchSSH_Sessions();
+});
+document.getElementById('shelLM_SessionsBtn').addEventListener('click', () => {
+ hideAllTables();
+ fetchShelLM_Sessions();
+});
+document.getElementById('commandsBtn').addEventListener('click', () => {
+ hideAllTables();
+ fetchCommands();
+});
+document.getElementById('answersBtn').addEventListener('click', () => {
+ hideAllTables();
+ fetchAnswers();
+});
+
+// Function to handle ID click
+function handleIDClick(shellmSessionID) {
+ console.log("ShellM Session ID clicked:", shellmSessionID);
+
+ const commandsAnswersSection = document.getElementById("commands-answers-section");
+ commandsAnswersSection.style.display = "block"; // Show the new button
+
+ const commandsAnswersBtn = document.getElementById("commandsAnswersBtn");
+ commandsAnswersBtn.onclick = () => fetchAndDisplayCommandsAnswers(shellmSessionID); // Attach handler
+}
+
+// Ensure the page is ready for actions
+document.addEventListener("DOMContentLoaded", () => {
+ console.log("Log Manager Dashboard ready.");
+});
diff --git a/Log Manager/ssh_module.py b/Log Manager/ssh_module.py
new file mode 100644
index 0000000..6fa1bff
--- /dev/null
+++ b/Log Manager/ssh_module.py
@@ -0,0 +1,419 @@
+import paramiko
+import mysql.connector
+from datetime import datetime, timedelta
+from dotenv import load_dotenv
+import os
+
+
+# Load environment variables from .env file
+load_dotenv('db_credentials.env')
+
+MYSQL_USER = os.getenv('MYSQL_USER')
+MYSQL_PASSWORD = os.getenv('MYSQL_PASSWORD')
+MYSQL_HOST = os.getenv('MYSQL_HOST')
+
+
+def parse_last_output(last_output):
+ sessions = []
+
+ # Process the output line by line
+ for line in last_output.splitlines():
+ # Skip empty lines or irrelevant lines
+ if not line.strip() or line.startswith("wtmp") or "reboot" in line:
+ continue
+
+ parts = line.split() # Split the line into words
+
+ # Extract details based on fixed column positions
+ username = parts[0]
+ terminal = parts[1]
+ src_ip = parts[2] if parts[2] != ":0" else "127.0.0.1" # Default to localhost for local logins
+ time_date_start = " ".join(parts[3:8]) # Combine the time and date parts
+
+ # Convert time strings to MySQL-compatible format
+ time_date_start = datetime.strptime(time_date_start, "%a %b %d %H:%M:%S %Y").strftime("%Y-%m-%d %H:%M:%S")
+
+ # Destination IP (your server IP or localhost for testing)
+ dst_ip = "olympus.felk.cvut.cz"
+ dst_port = 1337
+
+ # Append parsed data as a tuple
+ sessions.append((username, time_date_start, src_ip, dst_ip, dst_port))
+
+ return sessions
+
+
+def connect_to_db():
+ # Connect to the MySQL server
+ conn = mysql.connector.connect(
+ host=MYSQL_HOST,
+ user=MYSQL_USER,
+ password=MYSQL_PASSWORD,
+ database='shellm_sessions'
+ )
+ cursor = conn.cursor()
+
+ return conn, cursor
+
+
+# Function to insert data into MySQL
+def insert_into_ssh_session(data):
+ conn, cursor = connect_to_db()
+
+ # Insert data into ssh_session table
+ for session in data:
+ cursor.execute("""
+ INSERT INTO ssh_session (username, time_date, src_ip, dst_ip, dst_port)
+ VALUES (%s, %s, %s, %s, %s)
+ """, session)
+
+ # Commit and close
+ conn.commit()
+ cursor.close()
+ conn.close()
+
+
+# Function to insert data into MySQL
+def insert_into_attacker_session(data):
+ conn, cursor = connect_to_db()
+
+ # Insert data into ssh_session table
+ for session in data:
+ src_ip = session[2]
+ cursor.execute("""
+ INSERT INTO attacker_session (src_ip)
+ VALUES (%s)
+ """, (src_ip,))
+
+ # Commit and close
+ conn.commit()
+ cursor.close()
+ conn.close()
+
+
+# Function to count how many new connections were to ssh since last database entry
+def count_newest(data):
+ conn, cursor = connect_to_db()
+
+ cursor.execute("""
+ SELECT time_date FROM ssh_session ORDER BY id DESC LIMIT 1;
+ """)
+
+ latest_entry = cursor.fetchone()
+
+ if latest_entry:
+ time_date = latest_entry[0]
+
+ # Check if it's a datetime object or a string
+ if isinstance(time_date, datetime):
+ # If it's a datetime object, format it as a string
+ time_date_str = time_date.strftime(f"%Y-%m-%d %H:%M:%S")
+ else:
+ # If it's already a string, use it directly
+ time_date_str = str(time_date)
+
+ counter = 0
+
+ # Go through ssh logs and stop when old entries are reached
+ for session in data:
+ if session[1] <= time_date_str: # time_date_str - the specific date is only for testing
+ break
+ else:
+ counter += 1
+
+ # Commit and close
+ conn.commit()
+ cursor.close()
+ conn.close()
+
+ return counter
+
+
+def create_filenames(data):
+ filenames = []
+
+ for session in data:
+ # Extract the time_date value from the session tuple
+ time_date = session[1] # Assuming time_date is the second element in the tuple
+
+ # Convert the time_date to a string if it's not already
+ if isinstance(time_date, datetime):
+ time_date = time_date + timedelta(seconds=1)
+ time_date_str = time_date.strftime(f"%Y-%m-%d_%H-%M-%S")
+ else:
+ time_date_str = str(time_date).replace(" ", "_").replace(":", "-")
+
+ # Create the filename using the formatted time_date
+ filename = f"historySSH_{time_date_str}.txt"
+ filenames.append(filename)
+
+ return filenames
+
+
+def get_latest_sessions_ids(counter):
+ ids = []
+
+ conn, cursor = connect_to_db()
+ cursor.execute("""
+ SELECT id FROM ssh_session ORDER BY id DESC LIMIT %s;
+ """,(counter,))
+ ids = [row[0] for row in cursor.fetchall()]
+
+ return ids
+
+
+def get_latest_attackers_ids(counter):
+ ids = []
+
+ conn, cursor = connect_to_db()
+ cursor.execute("""
+ SELECT attacker_session_id FROM attacker_session ORDER BY attacker_session_id DESC LIMIT %s;
+ """,(counter,))
+ ids = [row[0] for row in cursor.fetchall()]
+
+ return ids
+
+
+def parse_historylog(filename, ssh):
+ stdin, stdout, stderr = ssh.exec_command(f"cat /path/to/the/specific/historylog/{filename}")
+ conversation = stdout.read().decode('utf-8')
+ conversation_error = stderr.read().decode('utf-8')
+
+ commands = []
+ answers = []
+ timestamps = []
+ start = ""
+
+ lines = conversation.splitlines()
+
+ previous_line = None
+ output = None
+
+ for line in lines:
+
+ if "For the last login date use" in line:
+ line_parts = line.split()
+ start = line_parts[-2] + " " + line_parts[-1]
+
+ # Check if the line contains a command
+ if line.strip().endswith('>'): # Command line ends with '>'
+
+ # First make sure if there is a multiline output to put it to answers
+ if output is not None:
+ answers.append(output)
+ output = None
+
+ split_line = line.split()
+
+ command = split_line[1:-2]
+ command = ' '.join(command)
+
+ if previous_line is not None and ":~" in previous_line:
+ output = split_line[0]
+ answers.append(output)
+ output = None
+
+ # print(line)
+ # print(command)
+
+ # For the exit command just put ""
+ if command == "exit":
+ answers.append("")
+
+ # Extract timestamp from the command line
+ try:
+ timestamp = split_line[-2] + split_line[-1]
+ timestamps.append(timestamp)
+ except (IndexError, ValueError):
+ pass # Ignore lines without valid timestamps
+
+ commands.append(command)
+
+ previous_line = line
+
+ else:
+ # Collect lines of output for the current command
+ if previous_line is not None:
+ if ":~" in previous_line:
+ output = line.strip()
+ previous_line = line
+ else:
+ output = output + "\n" + line.strip()
+ previous_line = line
+
+ # Determine start and end times
+ timestamps = [timestamps[0], timestamps[-1]]
+ start_time = start if start else timestamps[0] if timestamps else None
+ end_time = timestamps[1] if timestamps else None
+
+ # print(timestamps)
+ # print(commands)
+ # print(answers)
+
+ return commands, answers, start_time, end_time
+
+
+def insert_into_commands_and_answers(commands, shellm_session_id, answers):
+ conn, cursor = connect_to_db()
+
+ try:
+ # Ensure we have a matching number of commands and answers
+ if len(commands) != len(answers):
+ raise ValueError("The number of commands and answers must be equal.")
+
+ answer_counter = 0
+
+ # Insert each command and its corresponding answer
+ for command in commands:
+ # Insert command into 'commands' table
+ cursor.execute("""
+ INSERT INTO commands (shellm_session_id, command)
+ VALUES (%s, %s)
+ """, (shellm_session_id, command))
+
+ # Fetch the last inserted 'command_id'
+ cursor.execute("""
+ SELECT LAST_INSERT_ID();
+ """)
+ command_id = cursor.fetchone()[0] # Extract the value from the tuple
+
+ # Insert answer into 'answers' table
+ cursor.execute("""
+ INSERT INTO answers (command_id, answer)
+ VALUES (%s, %s)
+ """, (command_id, answers[answer_counter]))
+
+ answer_counter += 1
+
+ # Commit the transaction
+ conn.commit()
+
+ except Exception as e:
+ print(f"An error occurred: {e}")
+ conn.rollback() # Rollback in case of error
+
+ finally:
+ # Clean up resources
+ cursor.close()
+ conn.close()
+
+
+def insert_into_shellm_session(start_time, end_time, latest_session_ids, latest_attacker_ids):
+ conn, cursor = connect_to_db()
+
+ ssh_session_id = latest_session_ids[0]
+ latest_attacker_id = latest_attacker_ids[0]
+
+ cursor.execute("""
+ INSERT INTO shellm_session (ssh_session_id, model, start_time, end_time, attacker_id)
+ VALUES (%s, %s, %s, %s, %s)
+ """, (ssh_session_id, "FT GPT-3.5-16k", start_time, end_time, latest_attacker_id))
+
+ conn.commit()
+ cursor.close()
+ conn.close()
+
+
+def get_latest_shellm_session():
+
+ conn, cursor = connect_to_db()
+
+ cursor.execute("""
+ SELECT id FROM shellm_session ORDER BY id DESC LIMIT 1;
+ """)
+
+ shellm_session_id = cursor.fetchone()
+
+ # Commit and close
+ conn.commit()
+ cursor.close()
+ conn.close()
+
+ return shellm_session_id
+
+
+def format_datetime_for_db(raw_time):
+ # Step 1: Remove angle brackets
+ cleaned_time = raw_time.strip('<>')
+
+ # Step 2: Insert a space between the date and time
+ formatted_time = cleaned_time[:10] + ' ' + cleaned_time[10:]
+
+ # Step 3: Convert to datetime object (validates the format)
+ datetime_obj = datetime.strptime(formatted_time, f"%Y-%m-%d %H:%M:%S.%f")
+
+ # Step 4: Format to MySQL-compatible DATETIME string
+ return datetime_obj.strftime(f"%Y-%m-%d %H:%M:%S")
+
+
+def get_logs_from_server():
+ ssh = paramiko.SSHClient()
+ ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
+
+ # Load your private key to log in to remote server with logs
+ private_key = paramiko.RSAKey.from_private_key_file('C:\\pathtoprivatekey\\id_rsa')
+
+ # Connect to the SSH server using key-based authentication
+ ssh.connect(hostname="hostname", port="", username="user", pkey=private_key)
+
+ # Execute commands as before
+ stdin, stdout, stderr = ssh.exec_command("docker exec containerid last -F")
+ error_output = stderr.read().decode('utf-8')
+ docker_history = stdout.read().decode('utf-8')
+
+ ssh_data = parse_last_output(docker_history)
+ counter = count_newest(ssh_data)
+ ssh_data = ssh_data[:counter][::-1]
+
+ stdin, stdout, stderr = ssh.exec_command(f"ls /path/to/history/logs")
+ shellm_histories = stdout.read().decode('utf-8')
+ error_getting_histories = stderr.read().decode('utf-8')
+
+ # Get just the last created histories. Ignore earlier. This is to know exact file names of history logs.
+ shellm_histories = shellm_histories.split()
+ shellm_histories = shellm_histories[-counter:][::1]
+ # print(shellm_histories)
+
+ if counter > 0:
+ if docker_history:
+ insert_into_ssh_session(ssh_data)
+ insert_into_attacker_session(ssh_data)
+ else:
+ print(error_output)
+
+ # filenames = create_filenames(ssh_data)
+ # print(filenames)
+
+ # Get ids of the latest created session. They are FKs in shellm_session table. Invert them to get them in right order.
+ latest_sessions_ids = get_latest_sessions_ids(counter)
+ latest_sessions_ids = latest_sessions_ids[:][::-1]
+ latest_attacker_ids = get_latest_attackers_ids(counter)
+ latest_attacker_ids = latest_attacker_ids[:][::-1]
+ # print(latest_sessions_ids)
+
+ for filename in shellm_histories:
+ commands, answers, start_time, end_time = parse_historylog(filename, ssh)
+
+ start_time = format_datetime_for_db(start_time)
+ end_time = format_datetime_for_db(end_time)
+
+ insert_into_shellm_session(start_time, end_time, latest_sessions_ids, latest_attacker_ids)
+
+ shellm_session_id = get_latest_shellm_session()
+ # print(shellm_session_id)
+
+ insert_into_commands_and_answers(commands, shellm_session_id[0], answers)
+
+ # Pop the processed ssh_session
+ latest_sessions_ids = latest_sessions_ids[1:]
+ latest_attacker_ids = latest_attacker_ids[1:]
+
+
+ # log_file_content = stdout.read().decode()
+
+ ssh.close()
+
+ return docker_history#, log_file_content
+
+if __name__ == "__main__":
+ get_logs_from_server()
\ No newline at end of file
diff --git a/Log Manager/style.css b/Log Manager/style.css
new file mode 100644
index 0000000..0ce352e
--- /dev/null
+++ b/Log Manager/style.css
@@ -0,0 +1,93 @@
+body {
+ font-family: Arial, sans-serif;
+ margin: 0;
+ padding: 0;
+ background-color: #f9f9f9;
+ color: #333;
+}
+
+h1 {
+ text-align: center;
+ padding: 20px;
+ background-color: #4CAF50;
+ color: white;
+ margin: 0;
+}
+
+.container {
+ max-width: 1200px;
+ margin: 20px auto;
+ padding: 20px;
+ background: white;
+ border-radius: 8px;
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
+}
+
+.button-container {
+ display: flex;
+ justify-content: center;
+ margin-bottom: 20px;
+}
+
+.button-container button {
+ background-color: #4CAF50;
+ color: white;
+ border: none;
+ padding: 10px 20px;
+ margin: 0 10px;
+ border-radius: 5px;
+ font-size: 16px;
+ cursor: pointer;
+ transition: background-color 0.3s ease;
+}
+
+.button-container button:hover {
+ background-color: #45a049;
+}
+
+table {
+ border-collapse: collapse;
+ width: 100%;
+ margin-top: 20px;
+}
+
+th, td {
+ border: 1px solid #ddd;
+ padding: 12px;
+ text-align: left;
+}
+
+th {
+ background-color: #4CAF50;
+ color: white;
+}
+
+tr:nth-child(even) {
+ background-color: #f2f2f2;
+}
+
+tr:hover {
+ background-color: #ddd;
+}
+
+#commands-answers-table {
+ display: none;
+}
+
+.table-header {
+ margin-top: 30px;
+ text-align: center;
+ font-size: 18px;
+ color: #555;
+}
+
+footer {
+ text-align: center;
+ margin-top: 40px;
+ padding: 10px 0;
+ background-color: #4CAF50;
+ color: white;
+ position: relative;
+ bottom: 0;
+ width: 100%;
+}