298 lines
7.7 KiB
Python
298 lines
7.7 KiB
Python
import argparse
|
|
import sys
|
|
import os
|
|
from flask import Flask, render_template, request, redirect, url_for, abort
|
|
|
|
from Modules.windows import get_windows_content
|
|
|
|
from Modules.linux import get_linux_content
|
|
from Modules.tips import get_random_tip_or_joke
|
|
from Modules.methodology import get_methodology_content
|
|
from Modules.investigate import get_investigate_content
|
|
|
|
from Modules.Investigate.threat import *
|
|
from Modules.Investigate.ip import *
|
|
from Modules.Investigate.domain import *
|
|
from Modules.Investigate.filehash import *
|
|
from Modules.Investigate.malware import *
|
|
|
|
|
|
from Static.ascii_text_prompts import full_ascii_art_stripped, infinitei_stripped
|
|
from Config.config import VERSION
|
|
|
|
|
|
|
|
app = Flask(__name__)
|
|
|
|
# In-memory data store for the notebook page
|
|
notebook = {
|
|
"notes": [],
|
|
"ips": [],
|
|
"domains": [],
|
|
"services": [],
|
|
"tasks": []
|
|
}
|
|
|
|
@app.context_processor
|
|
def inject_tip():
|
|
"""
|
|
Add a random tip or joke to every page's context.
|
|
"""
|
|
return {"random_tip": get_random_tip_or_joke()}
|
|
|
|
README_PATH = os.path.join(os.getcwd(), "README.md")
|
|
|
|
|
|
def get_readme_description():
|
|
"""
|
|
Extract the description starting with "HUNT-AI" and stopping at the next blank line from the README.md file.
|
|
"""
|
|
if not os.path.exists(README_PATH):
|
|
return "No description available."
|
|
|
|
description = []
|
|
capture = False
|
|
|
|
try:
|
|
with open(README_PATH, "r", encoding="utf-8") as readme_file:
|
|
for line in readme_file:
|
|
# Start capturing from the line containing "HUNT-AI"
|
|
if "HUNT-AI" in line:
|
|
capture = True
|
|
description.append(line.strip())
|
|
# Continue capturing until a blank line is encountered
|
|
elif capture:
|
|
if line.strip() == "":
|
|
break
|
|
description.append(line.strip())
|
|
except Exception as e:
|
|
return f"Error reading README.md: {e}"
|
|
|
|
return " ".join(description) if description else "No description available."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/')
|
|
def home():
|
|
# Read description from README.md
|
|
readme_description = get_readme_description()
|
|
|
|
# Links to display on the home page
|
|
links = [
|
|
{"name": "Visit Start.me", "url": "https://start.me/p/qbzw4e/cyber-security"},
|
|
{"name": "Visit My Website", "url": "https://infinit3i.com/"}
|
|
]
|
|
return render_template(
|
|
'index.html',
|
|
full_ascii_art=full_ascii_art_stripped,
|
|
infinitei=infinitei_stripped,
|
|
links=links,
|
|
readme_description=readme_description
|
|
)
|
|
|
|
@app.route('/methodology')
|
|
def methodology():
|
|
content = get_methodology_content()
|
|
return render_template('methodology.html', content=content)
|
|
|
|
@app.route('/linux')
|
|
def linux():
|
|
sections = get_linux_content()
|
|
return render_template('linux.html', sections=sections)
|
|
|
|
@app.route('/linux/<title>')
|
|
def linux_section(title):
|
|
sections = get_linux_content()
|
|
section = next((s for s in sections if s["title"].replace(" ", "_").lower() == title.lower()), None)
|
|
if not section:
|
|
abort(404)
|
|
return render_template('section.html', section=section)
|
|
|
|
@app.route('/rule_creation')
|
|
def rule_creation():
|
|
return render_template('rule_creation.html')
|
|
|
|
@app.route('/windows')
|
|
def windows():
|
|
# Load all sections
|
|
sections = get_windows_content()
|
|
return render_template('windows.html', sections=sections)
|
|
|
|
@app.route('/windows/<title>')
|
|
def windows_section(title):
|
|
# Find the section matching the title
|
|
sections = get_windows_content()
|
|
section = next((s for s in sections if s["title"].replace(" ", "_").lower() == title.lower()), None)
|
|
|
|
if not section:
|
|
abort(404) # Return a 404 if the section is not found
|
|
|
|
return render_template('section.html', section=section)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/persistence')
|
|
def persistence_submenu():
|
|
"""
|
|
Displays the submenu for all persistence methods.
|
|
"""
|
|
menu = get_persistence_menu()
|
|
return render_template('persistence_submenu.html', menu=menu)
|
|
|
|
@app.route('/persistence/<method>')
|
|
def persistence_method(method):
|
|
"""
|
|
Dynamically load content for a specific persistence method.
|
|
"""
|
|
try:
|
|
# Dynamically import the requested method module
|
|
module = __import__(f"Modules.Persistence.{method}", fromlist=["get_content"])
|
|
content = module.get_content()
|
|
return render_template('persistence_method.html', content=content)
|
|
except ModuleNotFoundError:
|
|
abort(404, description=f"Persistence method '{method}' not found.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/investigate')
|
|
def investigate():
|
|
content = get_investigate_content()
|
|
return render_template('investigate.html', content=content)
|
|
|
|
@app.route('/investigate/threat')
|
|
def investigate_threat():
|
|
content = get_threat_content()
|
|
return render_template('investigate.html', content=content)
|
|
|
|
@app.route('/investigate/domain')
|
|
def investigate_domain():
|
|
content = get_domain_content()
|
|
return render_template('investigate.html', content=content)
|
|
|
|
@app.route('/investigate/filehash')
|
|
def investigate_filehash():
|
|
content = get_filehash_content()
|
|
return render_template('investigate.html', content=content)
|
|
|
|
@app.route('/investigate/ip')
|
|
def investigate_ip():
|
|
content = get_ip_content()
|
|
return render_template('investigate.html', content=content)
|
|
|
|
@app.route('/investigate/malware')
|
|
def investigate_malware():
|
|
content = get_malware_content()
|
|
return render_template('investigate.html', content=content)
|
|
|
|
def display_help():
|
|
"""
|
|
Display help information for the command-line interface.
|
|
"""
|
|
help_text = f"""
|
|
Usage:
|
|
python3 app.py Start the Flask application
|
|
python3 app.py -v Display the current version
|
|
python3 app.py -h Show this help page
|
|
python3 app.py -f <file> Load the last session file for collaboration
|
|
"""
|
|
print(help_text)
|
|
|
|
def get_version():
|
|
"""
|
|
Display the version of the application.
|
|
"""
|
|
print(f"App Version: {VERSION}")
|
|
|
|
def load_session(file_path):
|
|
"""
|
|
Load a session file and display its contents.
|
|
"""
|
|
try:
|
|
with open(file_path, "r") as file:
|
|
session_data = file.read()
|
|
print(f"Session loaded successfully from {file_path}:\n")
|
|
print(session_data)
|
|
except FileNotFoundError:
|
|
print(f"Error: File '{file_path}' not found.")
|
|
except Exception as e:
|
|
print(f"Error: {e}")
|
|
|
|
def handle_arguments():
|
|
"""
|
|
Parse and handle command-line arguments.
|
|
"""
|
|
parser = argparse.ArgumentParser(
|
|
description="App Runner - Threat AI Command Interface",
|
|
usage="python3 app.py [-v | -h | -f <file>]"
|
|
)
|
|
parser.add_argument("-v", "--version", action="store_true", help="Display the current version")
|
|
parser.add_argument("-f", "--file", type=str, help="Load the last session file for collaboration")
|
|
args = parser.parse_args()
|
|
|
|
if args.version:
|
|
get_version()
|
|
sys.exit(0)
|
|
elif args.file:
|
|
load_session(args.file)
|
|
sys.exit(0)
|
|
|
|
@app.route('/notebook', methods=['GET', 'POST'])
|
|
def notebook_page():
|
|
if request.method == 'POST':
|
|
# Capture data from form submission
|
|
category = request.form.get('category')
|
|
entry = request.form.get('entry')
|
|
if category in notebook and entry:
|
|
notebook[category].append(entry)
|
|
return render_template('notebook.html', notebook=notebook)
|
|
|
|
@app.route('/delete/<category>/<int:index>')
|
|
def delete_entry(category, index):
|
|
if category in notebook and 0 <= index < len(notebook[category]):
|
|
notebook[category].pop(index)
|
|
return redirect(url_for('notebook_page'))
|
|
|
|
if __name__ == '__main__':
|
|
# If arguments are passed, handle them; otherwise, run the Flask app.
|
|
if len(sys.argv) > 1:
|
|
handle_arguments()
|
|
else:
|
|
app.run(debug=True) |