forked from barvhaim/AutoC
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcli.py
More file actions
158 lines (127 loc) · 4.54 KB
/
cli.py
File metadata and controls
158 lines (127 loc) · 4.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
from typing import Optional
import logging
import sys
from datetime import datetime
import click
from rich.console import Console
from rich.panel import Panel
from rich.text import Text
from rich.table import Table
from rich.columns import Columns
from backend.run import run
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("cli")
auto_c_logo = """ _ _ ____
/ \ _ _| |_ ___ / ___|
/ _ \| | | | __/ _ \| |
/ ___ \ |_| | || (_) | |___
/_/ \_\__,_|\__\___/ \____|
"""
def _create_tag(keyword):
"""Create a styled tag string"""
return f"[black on cyan] {keyword} [/]"
def _create_qa_panel(question, answer):
"""Create a styled Q&A panel"""
content = f"[bold cyan]Q:[/] {question}\n\n" f"[bold green]A:[/] {answer}"
return Panel(content, border_style="bright_black", padding=(1, 2))
def _display_header(console: Console):
console.print(
Panel(
Text(auto_c_logo, style="bold white"),
subtitle=f"Automated IoCs Extraction Tool",
)
)
def _display_results(console: Console, res: dict, url: str):
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
console.print(
Panel(
Text(f"🕵️♂️ Blog Analysis Report: {url}", style="bold white"),
subtitle=f"Generated at {timestamp}",
style="blue",
)
)
keywords = res.get("keywords_found")
qna = res.get("qna")
iocs = res.get("iocs_found")
# Keywords
keyword_text = Text(
f"\n🔍 DETECTED KEYWORDS ({len(keywords)})\n", style="bold yellow"
)
console.print(keyword_text)
if keywords:
tags = " ".join(_create_tag(keyword) for keyword in keywords)
console.print(tags + "\n")
else:
console.print("No keywords found\n")
# Q&A
qna_text = Text(f"\n📝 Q&A ({len(qna)})\n", style="bold yellow")
console.print(qna_text)
if qna:
qa_panels = [_create_qa_panel(item["question"], item["answer"]) for item in qna]
# Display panels in columns if terminal is wide enough
console.print(Columns(qa_panels, equal=True, expand=True))
else:
console.print("No Q&A found\n")
# IoCs
iocs_text = Text(f"\n⚠️ DETECTED IoCs ({len(iocs)})\n", style="bold yellow")
console.print(iocs_text)
if iocs:
ioc_table = Table(show_header=True, header_style="bold magenta")
ioc_table.add_column("Type", style="yellow")
ioc_table.add_column("Value", style="white")
for ioc in iocs:
ioc_table.add_row(ioc["type"], ioc["value"])
console.print(ioc_table)
else:
console.print("No IoCs found\n")
# MITRE ATT&CK TTPs Classification
mitre_ttps = res.get("mitre_ttps")
if mitre_ttps is None:
return
mitre_text = Text(f"\n🧑💻 MITRE TTPs ({len(mitre_ttps)})\n", style="bold yellow")
console.print(mitre_text)
if mitre_ttps:
table = Table(show_header=True, header_style="bold magenta")
table.add_column("ID", style="cyan")
table.add_column("Name", style="white")
table.add_column("Max Confidence", style="green", justify="right")
table.add_column("URL", style="blue", overflow="fold")
for ttp in mitre_ttps:
confidence = f"{ttp.get('confidence', 0):.3f}"
table.add_row(
ttp["id"],
ttp["name"],
confidence,
ttp["url"],
)
console.print(table)
else:
console.print("No MITRE ATT&CK TTPs detected\n")
@click.group()
def cli():
"""AutoC is a framework for Automated IoCs extraction."""
@click.command()
@click.option("--url", help="URL of the blog post to extract IoCs from.")
def extract(url: Optional[str]):
"""Extract IoCs from a blog post."""
console = Console()
try:
_display_header(console=console)
if not url:
url = input("Enter the URL of the blog post: ")
res = run(url=url)
_display_results(console=console, res=res, url=url)
except Exception as e:
logger.error(f"Error: {str(e)}")
raise SystemExit(1)
cli.add_command(extract)
def custom_excepthook(exc_type, exc_value, exc_traceback):
"""Custom exception hook to prevent sys.excepthook errors"""
if exc_type is KeyboardInterrupt:
sys.__excepthook__(exc_type, exc_value, exc_traceback)
return
logger.error(f"Uncaught exception: {exc_type.__name__}: {exc_value}")
sys.exit(1)
if __name__ == "__main__":
sys.excepthook = custom_excepthook
cli()