forensic-cli 1.4.3__tar.gz → 1.4.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {forensic_cli-1.4.3/src/forensic_cli.egg-info → forensic_cli-1.4.4}/PKG-INFO +1 -1
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/pyproject.toml +1 -1
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/setup.py +2 -2
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/cli/commands/browser.py +11 -8
- forensic_cli-1.4.4/src/cli/commands/describe.py +153 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4/src/forensic_cli.egg-info}/PKG-INFO +1 -1
- forensic_cli-1.4.3/src/cli/commands/describe.py +0 -54
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/LICENSE +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/LICENSE-GPL +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/README.md +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/setup.cfg +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/cli/__init__.py +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/cli/commands/__init__.py +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/cli/commands/email.py +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/cli/commands/network.py +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/cli/commands/utils.py +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/cli/main.py +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/core/__init__.py +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/core/browser/browser_history.py +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/core/browser/common_words.py +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/core/browser/downloads_history.py +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/core/browser/fav_screen.py +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/core/browser/logins.py +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/core/browser/unusual_patterns.py +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/core/data/__init__.py +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/core/data/data_recovery.py +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/core/db/db.py +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/core/email/email_parser.py +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/core/email/header_analysis.py +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/core/models/orm.py +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/core/models/schemas.py +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/core/network/__init__.py +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/core/network/arp_scan.py +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/core/network/dns_recon.py +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/core/network/fingerprinting.py +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/core/network/ip_info.py +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/core/network/network_map.py +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/core/network/ping_sweep.py +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/core/network/port_scanner.py +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/core/network/smb_scan.py +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/core/network/snmp_scan.py +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/core/network/traceroute.py +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/core/network/utils.py +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/core/registry.py +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/core/utils/__init__.py +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/core/utils/gerar_amostras.py +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/forensic_cli.egg-info/SOURCES.txt +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/forensic_cli.egg-info/dependency_links.txt +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/forensic_cli.egg-info/entry_points.txt +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/forensic_cli.egg-info/requires.txt +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/src/forensic_cli.egg-info/top_level.txt +0 -0
- {forensic_cli-1.4.3 → forensic_cli-1.4.4}/tests/test_file_inspector.py +0 -0
|
@@ -2,11 +2,11 @@ from setuptools import setup, find_packages
|
|
|
2
2
|
|
|
3
3
|
setup(
|
|
4
4
|
name="forensic_cli",
|
|
5
|
-
version="1.4.
|
|
5
|
+
version="1.4.4",
|
|
6
6
|
author="Erick Gabriel dos Santos Alves",
|
|
7
7
|
author_email="erickgabrielalves0@gmail.com",
|
|
8
8
|
description="Toolkit modular para análise de evidências digitais",
|
|
9
|
-
long_description=open("README.md").read(),
|
|
9
|
+
long_description=open("README.md", encoding="utf-8").read(),
|
|
10
10
|
long_description_content_type="text/markdown",
|
|
11
11
|
url="https://github.com/ErickG123/devkit_forense",
|
|
12
12
|
packages=find_packages(),
|
|
@@ -10,14 +10,17 @@ from core.browser.unusual_patterns import processar_historico_da_pasta
|
|
|
10
10
|
from core.browser.logins import collect_chrome_logins, collect_edge_logins
|
|
11
11
|
from core.browser.common_words import extract_words
|
|
12
12
|
|
|
13
|
-
browser_app = typer.Typer(
|
|
13
|
+
browser_app = typer.Typer(
|
|
14
|
+
help="Conjunto de ferramentas para extrair e processar artefatos de navegadores "
|
|
15
|
+
"(histórico, downloads, logins, favicons/screens e análises de padrões)."
|
|
16
|
+
)
|
|
14
17
|
|
|
15
|
-
@browser_app.command("history")
|
|
18
|
+
@browser_app.command("history", help="Extrai o histórico dos navegadores especificados (Chrome, Edge, Firefox ou todos).")
|
|
16
19
|
def history(
|
|
17
20
|
chrome: bool = typer.Option(False, "--chrome", help="Extrair histórico do Chrome"),
|
|
18
21
|
edge: bool = typer.Option(False, "--edge", help="Extrair histórico do Edge"),
|
|
19
22
|
firefox: bool = typer.Option(False, "--firefox", help="Extrair histórico do Firefox"),
|
|
20
|
-
all: bool = typer.Option(False, "--all", help="Extrair histórico de todos navegadores")
|
|
23
|
+
all: bool = typer.Option(False, "--all", help="Extrair histórico de todos os navegadores")
|
|
21
24
|
):
|
|
22
25
|
usuario = os.getlogin()
|
|
23
26
|
home = str(Path.home())
|
|
@@ -52,7 +55,7 @@ def history(
|
|
|
52
55
|
else:
|
|
53
56
|
typer.echo("[!] Perfis do Firefox não encontrados.")
|
|
54
57
|
|
|
55
|
-
@browser_app.command("downloads")
|
|
58
|
+
@browser_app.command("downloads", help="Extrai registros de downloads dos navegadores e salva artefatos no diretório indicado.")
|
|
56
59
|
def downloads(
|
|
57
60
|
output_dir: Path = typer.Option(
|
|
58
61
|
Path("artefatos/downloads"),
|
|
@@ -87,7 +90,7 @@ def downloads(
|
|
|
87
90
|
|
|
88
91
|
typer.echo("✅ Extração concluída!")
|
|
89
92
|
|
|
90
|
-
@browser_app.command("favscreen")
|
|
93
|
+
@browser_app.command("favscreen", help="Processa JSONs de histórico, extrai URLs válidas e captura favicons/screenshots.")
|
|
91
94
|
def favscreen(
|
|
92
95
|
input_dir: Path = typer.Option(
|
|
93
96
|
Path("artefatos/historico"),
|
|
@@ -130,7 +133,7 @@ def favscreen(
|
|
|
130
133
|
except Exception as erro:
|
|
131
134
|
typer.echo(f"\n❌ Erro geral: {erro}")
|
|
132
135
|
|
|
133
|
-
@browser_app.command("logins")
|
|
136
|
+
@browser_app.command("logins", help="Coleta credenciais/entradas de login dos navegadores suportados e grava JSONs com os resultados.")
|
|
134
137
|
def logins(
|
|
135
138
|
chrome: bool = typer.Option(False, "--chrome", help="Extrair logins do Chrome"),
|
|
136
139
|
edge: bool = typer.Option(False, "--edge", help="Extrair logins do Edge"),
|
|
@@ -169,7 +172,7 @@ def logins(
|
|
|
169
172
|
json.dump(data_edge, f, indent=2, ensure_ascii=False)
|
|
170
173
|
typer.echo(f"✅ Logins do Edge salvos em: {arquivo_edge}")
|
|
171
174
|
|
|
172
|
-
@browser_app.command("patterns")
|
|
175
|
+
@browser_app.command("patterns", help="Analisa históricos para identificar padrões incomuns e gera gráficos/relatórios na pasta de saída.")
|
|
173
176
|
def patterns(
|
|
174
177
|
input_dir: Path = typer.Option(
|
|
175
178
|
Path("artefatos/historico"),
|
|
@@ -204,7 +207,7 @@ def patterns(
|
|
|
204
207
|
except Exception as erro:
|
|
205
208
|
typer.echo(f"\n❌ Erro ao executar patterns: {erro}")
|
|
206
209
|
|
|
207
|
-
@browser_app.command("words")
|
|
210
|
+
@browser_app.command("words", help="Extrai palavras/termos mais frequentes do histórico (ex.: pesquisas) e salva um JSON com os resultados.")
|
|
208
211
|
def words(
|
|
209
212
|
chrome: bool = typer.Option(True, "--chrome", help="Extrair palavras mais pesquisadas do Chrome"),
|
|
210
213
|
output_dir: Path = typer.Option(
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import difflib
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
from rich import print
|
|
7
|
+
from rich.table import Table
|
|
8
|
+
from rich.pretty import Pretty
|
|
9
|
+
|
|
10
|
+
describe_app = typer.Typer(help="Ajuda interativa para os comandos/funcionalidades do toolkit forense.")
|
|
11
|
+
|
|
12
|
+
docs = {
|
|
13
|
+
"map": {
|
|
14
|
+
"name": "map / run_network_map",
|
|
15
|
+
"description": "Retorna informações detalhadas de cada host da rede.",
|
|
16
|
+
"example_return": [
|
|
17
|
+
{
|
|
18
|
+
"host": "192.168.1.1",
|
|
19
|
+
"hostname": "router",
|
|
20
|
+
"mac": "AA:BB:CC:DD:EE:FF",
|
|
21
|
+
"vendor": "Cisco",
|
|
22
|
+
"open_ports": [22, 80],
|
|
23
|
+
"os_info": "Linux"
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
"sweep": {
|
|
28
|
+
"name": "sweep / ping_sweep",
|
|
29
|
+
"description": "Faz um ping sweep na rede e retorna os hosts ativos.",
|
|
30
|
+
"example_return": ["192.168.1.1", "192.168.1.3"],
|
|
31
|
+
},
|
|
32
|
+
"scan": {
|
|
33
|
+
"name": "scan / port_scanner",
|
|
34
|
+
"description": "Verifica quais portas estão abertas, fechadas e filtradas.",
|
|
35
|
+
"example_return": [
|
|
36
|
+
{
|
|
37
|
+
"port": 53,
|
|
38
|
+
"protocol": "UDP",
|
|
39
|
+
"status": "open|filtered",
|
|
40
|
+
"banner": "sem resposta",
|
|
41
|
+
"alert": "DNS"
|
|
42
|
+
}
|
|
43
|
+
],
|
|
44
|
+
},
|
|
45
|
+
"fingerprinting": {
|
|
46
|
+
"name": "fingerprinting / detect_os",
|
|
47
|
+
"description": "Detecta o sistema operacional, tipo de host, serviços e possíveis alertas de vulnerabilidade de um host.",
|
|
48
|
+
"example_return": {
|
|
49
|
+
"os": "Windows",
|
|
50
|
+
"host_type": "Servidor",
|
|
51
|
+
"services": ["SMB", "Web HTTP", "MySQL"],
|
|
52
|
+
"alerts": ["SMB vulnerável (Samba 3.0)"]
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
"traceroute": {
|
|
56
|
+
"name": "traceroute / traceroute_host",
|
|
57
|
+
"description": "Executa um traceroute até um host e retorna a rota (hops) percorrida.",
|
|
58
|
+
"example_return": [
|
|
59
|
+
{"hop": 1, "ip": "192.168.1.1", "rtt_ms": 1.2},
|
|
60
|
+
{"hop": 2, "ip": "10.0.0.1", "rtt_ms": 10.5},
|
|
61
|
+
],
|
|
62
|
+
},
|
|
63
|
+
"arp_scan": {
|
|
64
|
+
"name": "arp_scan / arp_scan",
|
|
65
|
+
"description": "Faz uma varredura ARP na sub-rede para descobrir MACs/IPs ativos.",
|
|
66
|
+
"example_return": [
|
|
67
|
+
{"ip": "192.168.1.10", "mac": "AA:BB:CC:11:22:33", "vendor": "Intel"},
|
|
68
|
+
],
|
|
69
|
+
},
|
|
70
|
+
"parse_ports": {
|
|
71
|
+
"name": "parse_ports",
|
|
72
|
+
"description": "Função auxiliar que transforma a saída do scanner em um formato padronizado.",
|
|
73
|
+
"example_return": [
|
|
74
|
+
{"port": 22, "state": "open", "service": "ssh"},
|
|
75
|
+
{"port": 80, "state": "open", "service": "http"},
|
|
76
|
+
],
|
|
77
|
+
},
|
|
78
|
+
"parse_network": {
|
|
79
|
+
"name": "parse_network / ping_sweep.parse_network",
|
|
80
|
+
"description": "Analisa e normaliza a representação da rede (ex: 192.168.0.0/24).",
|
|
81
|
+
"example_return": {"network": "192.168.0.0/24", "hosts": 254},
|
|
82
|
+
},
|
|
83
|
+
"scan_host": {
|
|
84
|
+
"name": "scan_host",
|
|
85
|
+
"description": "Escaneia portas de um único host (wrapper do port_scanner).",
|
|
86
|
+
"example_return": [
|
|
87
|
+
{"port": 443, "protocol": "tcp", "status": "open", "service": "https"},
|
|
88
|
+
],
|
|
89
|
+
},
|
|
90
|
+
"ping_host": {
|
|
91
|
+
"name": "ping_host",
|
|
92
|
+
"description": "Faz ping em um host e retorna latência e status.",
|
|
93
|
+
"example_return": {"host": "192.168.1.5", "alive": True, "rtt_ms": 2.3},
|
|
94
|
+
},
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
def _find_key(key: str) -> str | None:
|
|
98
|
+
key_lower = key.lower()
|
|
99
|
+
keys = list(docs.keys())
|
|
100
|
+
for k in keys:
|
|
101
|
+
if k == key_lower or docs[k].get("name", "").lower().split()[0] == key_lower:
|
|
102
|
+
return k
|
|
103
|
+
|
|
104
|
+
matches = difflib.get_close_matches(key_lower, keys, n=3, cutoff=0.5)
|
|
105
|
+
|
|
106
|
+
return matches[0] if matches else None
|
|
107
|
+
|
|
108
|
+
def _print_example(example: Any, full: bool):
|
|
109
|
+
if full:
|
|
110
|
+
print(Pretty(example))
|
|
111
|
+
else:
|
|
112
|
+
try:
|
|
113
|
+
s = json.dumps(example, indent=2, ensure_ascii=False)
|
|
114
|
+
except Exception:
|
|
115
|
+
s = str(example)
|
|
116
|
+
print(s)
|
|
117
|
+
|
|
118
|
+
@describe_app.command("func", help="Mostra a descrição e exemplo de retorno de uma função/command do toolkit.")
|
|
119
|
+
def describe(
|
|
120
|
+
func: str = typer.Argument(..., help="Nome da função que você deseja entender (ex: map, scan, sweep)"),
|
|
121
|
+
full: bool = typer.Option(False, "--full", "-f", help="Mostrar exemplo formatado (mais detalhado)."),
|
|
122
|
+
):
|
|
123
|
+
key = _find_key(func)
|
|
124
|
+
if not key:
|
|
125
|
+
candidates = difflib.get_close_matches(func.lower(), list(docs.keys()), n=5, cutoff=0.4)
|
|
126
|
+
if candidates:
|
|
127
|
+
print(f"[yellow]Função '{func}' não encontrada. Você quis dizer:[/yellow]")
|
|
128
|
+
for c in candidates:
|
|
129
|
+
print(f" • {c} — {docs[c]['description']}")
|
|
130
|
+
raise typer.Exit(code=1)
|
|
131
|
+
else:
|
|
132
|
+
print(f"[red]Função '{func}' não encontrada e nenhuma sugestão foi localizada.[/red]")
|
|
133
|
+
raise typer.Exit(code=1)
|
|
134
|
+
|
|
135
|
+
info = docs[key]
|
|
136
|
+
|
|
137
|
+
print(f"[bold blue]Nome da Função:[/bold blue] {info.get('name', key)}")
|
|
138
|
+
print(f"[bold blue]Descrição:[/bold blue] {info.get('description')}")
|
|
139
|
+
print("[bold blue]Exemplo de Retorno:[/bold blue]")
|
|
140
|
+
_print_example(info.get("example_return"), full=full)
|
|
141
|
+
|
|
142
|
+
@describe_app.command("list", help="Lista todas as funções/commands documentados.")
|
|
143
|
+
def list_commands():
|
|
144
|
+
table = Table(title="Comandos documentados", show_lines=False)
|
|
145
|
+
table.add_column("chave", style="cyan", no_wrap=True)
|
|
146
|
+
table.add_column("nome", style="magenta")
|
|
147
|
+
table.add_column("descrição", style="white")
|
|
148
|
+
for k, v in sorted(docs.items()):
|
|
149
|
+
table.add_row(k, v.get("name", ""), v.get("description", ""))
|
|
150
|
+
print(table)
|
|
151
|
+
|
|
152
|
+
if __name__ == "__main__":
|
|
153
|
+
describe_app()
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import typer
|
|
2
|
-
from rich import print
|
|
3
|
-
|
|
4
|
-
describe_app = typer.Typer()
|
|
5
|
-
|
|
6
|
-
@describe_app.command("func")
|
|
7
|
-
def describe(
|
|
8
|
-
func: str = typer.Argument(..., help="Digite o nome da função que você deseja entender")
|
|
9
|
-
):
|
|
10
|
-
docs = {
|
|
11
|
-
"map": {
|
|
12
|
-
"description": "Retorna informações detalhadas de cada host da rede.",
|
|
13
|
-
"example_return": [{
|
|
14
|
-
"host": "192.168.1.1",
|
|
15
|
-
"hostname": "router",
|
|
16
|
-
"mac": "AA:BB:CC:DD:EE:FF",
|
|
17
|
-
"vendor": "Cisco",
|
|
18
|
-
"open_ports": [22, 80],
|
|
19
|
-
"os_info": "Linux"
|
|
20
|
-
}]
|
|
21
|
-
},
|
|
22
|
-
"sweep": {
|
|
23
|
-
"description": "Faz um ping sweep na rede e retorna os hosts ativos.",
|
|
24
|
-
"example_return": ["192.168.1.1", "192.168.1.3"]
|
|
25
|
-
},
|
|
26
|
-
"scan": {
|
|
27
|
-
"description": "Verifica quais portas estão abertas, fechadas e filtradas.",
|
|
28
|
-
"example_return": [{
|
|
29
|
-
"port": 53,
|
|
30
|
-
"protocol": "UDP",
|
|
31
|
-
"status": "open|filtered",
|
|
32
|
-
"banner": "sem resposta",
|
|
33
|
-
"alert": "DNS"
|
|
34
|
-
}]
|
|
35
|
-
},
|
|
36
|
-
"fingerprinting": {
|
|
37
|
-
"description": "Detecta o sistema operacional, tipo de host, serviços e possíveis alertas de vulnerabilidade de um host.",
|
|
38
|
-
"example_return": {
|
|
39
|
-
"os": "Windows",
|
|
40
|
-
"host_type": "Servidor",
|
|
41
|
-
"services": ["SMB", "Web HTTP", "MySQL"],
|
|
42
|
-
"alerts": ["SMB vulnerável (Samba 3.0)"]
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if func in docs:
|
|
48
|
-
info = docs[func]
|
|
49
|
-
print(f"[bold blue]Nome da Função:[/bold blue] {func}")
|
|
50
|
-
print(f"[bold blue]Descrição:[/bold blue] {info['description']}")
|
|
51
|
-
print("[bold blue]Exemplo de Retorno:[/bold blue]")
|
|
52
|
-
print(info['example_return'])
|
|
53
|
-
else:
|
|
54
|
-
typer.echo(f"Função {func} não encontrada.")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|