soc-mre 1.0.0__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.
soc_mre-1.0.0/PKG-INFO ADDED
@@ -0,0 +1,119 @@
1
+ Metadata-Version: 2.4
2
+ Name: soc-mre
3
+ Version: 1.0.0
4
+ Summary: Credential Intelligence Tool for SOC
5
+ Requires-Python: >=3.10
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: rich>=13.0
8
+ Requires-Dist: tqdm>=4.0
9
+ Requires-Dist: psutil>=5.9
10
+ Requires-Dist: python-magic>=0.4
11
+ Requires-Dist: py7zr<1,>=0.20
12
+ Requires-Dist: rarfile>=4.0
13
+ Requires-Dist: pdfplumber>=0.10
14
+ Requires-Dist: openpyxl>=3.1
15
+
16
+ # SOC MRE
17
+
18
+ Ferramenta defensiva de análise de credenciais vazadas para equipes de SOC. Lê ficheiros na pasta de leaks, cruza com domínios monitorados (pastas sob **CTI**) e grava resultados em SQLite e ficheiros de blacklist por domínio.
19
+
20
+ ## Dependências de sistema (Linux)
21
+
22
+ O pacote Python inclui bibliotecas para vários formatos; no sistema é recomendado:
23
+
24
+ ```bash
25
+ sudo apt install libmagic1 unrar
26
+ ```
27
+
28
+ - **libmagic1** — deteção MIME (`python-magic`).
29
+ - **unrar** — leitura de alguns ficheiros `.rar` via `rarfile` (sem extrair para disco).
30
+
31
+ No Windows, instale o binário **UnRAR** se precisar de `.rar`, e as DLLs necessárias para `python-magic`.
32
+
33
+ ## Instalação
34
+
35
+ ```bash
36
+ cd soc-mre
37
+ pip install .
38
+ ```
39
+
40
+ ## Instalação a partir de um repositório Git
41
+
42
+ Substitua o URL pelo do seu fork ou organização:
43
+
44
+ ```bash
45
+ pip install git+https://github.com/SEU-USUARIO/soc-mre.git
46
+ ```
47
+
48
+ ## Configuração
49
+
50
+ Gere um ficheiro JSON de exemplo e edite os caminhos (`leaks`, `cti`, `database_dir`):
51
+
52
+ ```bash
53
+ soc-mre --init-config
54
+ ```
55
+
56
+ Ficheiro padrão: `soc_mre.json` no diretório atual (alterável com `--config`).
57
+
58
+ ## Uso interativo
59
+
60
+ ```bash
61
+ soc-mre --leaks /caminho/leaks --cti /caminho/CTI --database-dir /caminho/database
62
+ ```
63
+
64
+ Ou preencha os mesmos caminhos no `soc_mre.json` e execute:
65
+
66
+ ```bash
67
+ soc-mre
68
+ ```
69
+
70
+ ## Linha de comando e modo stdin
71
+
72
+ ```bash
73
+ soc-mre --help
74
+ python -m soc_mre --help
75
+ ```
76
+
77
+ Modo pipe (exige CTI válido para localizar a pasta do domínio e exportar blacklist):
78
+
79
+ ```bash
80
+ rg -i "@exemplo.com" /caminho/leaks | soc-mre --stdin --domain @exemplo.com -c /caminho/CTI -d /caminho/database
81
+ ```
82
+
83
+ ## Persistência (SQLite)
84
+
85
+ - **`database.db`** — criado/atualizado dentro do diretório passado em `--database-dir` / `database_dir`. Tabela `credentials` com chave `(email, password)`, modo WAL.
86
+ - **Migração** — se existir `masterList.txt` nesse diretório na primeira execução, o conteúdo é importado para o SQLite e o ficheiro legado é renomeado para `masterList.txt.bak` (mensagem na consola).
87
+
88
+ ## Blacklists por domínio
89
+
90
+ - Ficheiros exportados seguem o padrão lógico **`blackList-<dominio-sanitizado>.txt`**, mas **cada exportação com dados** gera um **novo ficheiro** com timestamp e microssegundos no nome, por exemplo:
91
+
92
+ `blackList-exemplo.com.br_2026-05-03_14-30-00-123456.txt`
93
+
94
+ - **Não** se sobrescrevem exportações anteriores; o histórico acumula-se no disco.
95
+ - Se **não** houver credenciais para aquele domínio na base, a exportação **não** cria ficheiro novo (retorno `0`).
96
+ - O menu continua a carregar credenciais já guardadas a partir do caminho “canónico” da pasta do domínio (`blackList-*.txt` existentes); novas execuções acrescentam ficheiros com timestamp.
97
+
98
+ ## Formatos de leak suportados
99
+
100
+ | Formato | Comportamento |
101
+ |---------|-----------------|
102
+ | `.txt`, `.csv` | Leitura em fluxo (linhas em bytes). |
103
+ | `.gz` | Descompressão em fluxo. |
104
+ | `.zip` | Leitura com `zipfile` **sem** extrair para disco; vários membros e subpastas internas. |
105
+ | `.7z`, `.rar`, `.pdf`, `.xlsx` | Tratados como **formatos lentos**: é pedida confirmação no terminal antes de processar; leitura em memória/streaming conforme o tipo (**sem** `extractall` para disco nos arquivos compactados). |
106
+
107
+ Extensões reconhecidas na pasta de leaks estão alinhadas com o que o motor de deteção e o `rg` (quando instalado) consideram.
108
+
109
+ ## Outras dependências Python
110
+
111
+ Instaladas automaticamente com `pip install .` (ver `pyproject.toml`): Rich, tqdm, psutil, python-magic, py7zr, rarfile, pdfplumber, openpyxl.
112
+
113
+ ## Avisos de memória
114
+
115
+ Durante análise de ficheiros muito grandes, pode ser mostrado um aviso se a RAM do sistema ultrapassar um limiar (percentagem configurada no código); o processo **não** termina so por isso.
116
+
117
+ ## Repositório
118
+
119
+ O código-fonte vive no pacote **`soc_mre/`** (nome com underscore). A pasta **`soc-mre/`** (hífen) é a raiz do projeto instalável.
@@ -0,0 +1,104 @@
1
+ # SOC MRE
2
+
3
+ Ferramenta defensiva de análise de credenciais vazadas para equipes de SOC. Lê ficheiros na pasta de leaks, cruza com domínios monitorados (pastas sob **CTI**) e grava resultados em SQLite e ficheiros de blacklist por domínio.
4
+
5
+ ## Dependências de sistema (Linux)
6
+
7
+ O pacote Python inclui bibliotecas para vários formatos; no sistema é recomendado:
8
+
9
+ ```bash
10
+ sudo apt install libmagic1 unrar
11
+ ```
12
+
13
+ - **libmagic1** — deteção MIME (`python-magic`).
14
+ - **unrar** — leitura de alguns ficheiros `.rar` via `rarfile` (sem extrair para disco).
15
+
16
+ No Windows, instale o binário **UnRAR** se precisar de `.rar`, e as DLLs necessárias para `python-magic`.
17
+
18
+ ## Instalação
19
+
20
+ ```bash
21
+ cd soc-mre
22
+ pip install .
23
+ ```
24
+
25
+ ## Instalação a partir de um repositório Git
26
+
27
+ Substitua o URL pelo do seu fork ou organização:
28
+
29
+ ```bash
30
+ pip install git+https://github.com/SEU-USUARIO/soc-mre.git
31
+ ```
32
+
33
+ ## Configuração
34
+
35
+ Gere um ficheiro JSON de exemplo e edite os caminhos (`leaks`, `cti`, `database_dir`):
36
+
37
+ ```bash
38
+ soc-mre --init-config
39
+ ```
40
+
41
+ Ficheiro padrão: `soc_mre.json` no diretório atual (alterável com `--config`).
42
+
43
+ ## Uso interativo
44
+
45
+ ```bash
46
+ soc-mre --leaks /caminho/leaks --cti /caminho/CTI --database-dir /caminho/database
47
+ ```
48
+
49
+ Ou preencha os mesmos caminhos no `soc_mre.json` e execute:
50
+
51
+ ```bash
52
+ soc-mre
53
+ ```
54
+
55
+ ## Linha de comando e modo stdin
56
+
57
+ ```bash
58
+ soc-mre --help
59
+ python -m soc_mre --help
60
+ ```
61
+
62
+ Modo pipe (exige CTI válido para localizar a pasta do domínio e exportar blacklist):
63
+
64
+ ```bash
65
+ rg -i "@exemplo.com" /caminho/leaks | soc-mre --stdin --domain @exemplo.com -c /caminho/CTI -d /caminho/database
66
+ ```
67
+
68
+ ## Persistência (SQLite)
69
+
70
+ - **`database.db`** — criado/atualizado dentro do diretório passado em `--database-dir` / `database_dir`. Tabela `credentials` com chave `(email, password)`, modo WAL.
71
+ - **Migração** — se existir `masterList.txt` nesse diretório na primeira execução, o conteúdo é importado para o SQLite e o ficheiro legado é renomeado para `masterList.txt.bak` (mensagem na consola).
72
+
73
+ ## Blacklists por domínio
74
+
75
+ - Ficheiros exportados seguem o padrão lógico **`blackList-<dominio-sanitizado>.txt`**, mas **cada exportação com dados** gera um **novo ficheiro** com timestamp e microssegundos no nome, por exemplo:
76
+
77
+ `blackList-exemplo.com.br_2026-05-03_14-30-00-123456.txt`
78
+
79
+ - **Não** se sobrescrevem exportações anteriores; o histórico acumula-se no disco.
80
+ - Se **não** houver credenciais para aquele domínio na base, a exportação **não** cria ficheiro novo (retorno `0`).
81
+ - O menu continua a carregar credenciais já guardadas a partir do caminho “canónico” da pasta do domínio (`blackList-*.txt` existentes); novas execuções acrescentam ficheiros com timestamp.
82
+
83
+ ## Formatos de leak suportados
84
+
85
+ | Formato | Comportamento |
86
+ |---------|-----------------|
87
+ | `.txt`, `.csv` | Leitura em fluxo (linhas em bytes). |
88
+ | `.gz` | Descompressão em fluxo. |
89
+ | `.zip` | Leitura com `zipfile` **sem** extrair para disco; vários membros e subpastas internas. |
90
+ | `.7z`, `.rar`, `.pdf`, `.xlsx` | Tratados como **formatos lentos**: é pedida confirmação no terminal antes de processar; leitura em memória/streaming conforme o tipo (**sem** `extractall` para disco nos arquivos compactados). |
91
+
92
+ Extensões reconhecidas na pasta de leaks estão alinhadas com o que o motor de deteção e o `rg` (quando instalado) consideram.
93
+
94
+ ## Outras dependências Python
95
+
96
+ Instaladas automaticamente com `pip install .` (ver `pyproject.toml`): Rich, tqdm, psutil, python-magic, py7zr, rarfile, pdfplumber, openpyxl.
97
+
98
+ ## Avisos de memória
99
+
100
+ Durante análise de ficheiros muito grandes, pode ser mostrado um aviso se a RAM do sistema ultrapassar um limiar (percentagem configurada no código); o processo **não** termina so por isso.
101
+
102
+ ## Repositório
103
+
104
+ O código-fonte vive no pacote **`soc_mre/`** (nome com underscore). A pasta **`soc-mre/`** (hífen) é a raiz do projeto instalável.
@@ -0,0 +1,26 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "soc-mre"
7
+ version = "1.0.0"
8
+ description = "Credential Intelligence Tool for SOC"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ dependencies = [
12
+ "rich>=13.0",
13
+ "tqdm>=4.0",
14
+ "psutil>=5.9",
15
+ "python-magic>=0.4",
16
+ "py7zr>=0.20,<1",
17
+ "rarfile>=4.0",
18
+ "pdfplumber>=0.10",
19
+ "openpyxl>=3.1",
20
+ ]
21
+
22
+ [project.scripts]
23
+ soc-mre = "soc_mre.main:main"
24
+
25
+ [tool.setuptools]
26
+ packages = ["soc_mre"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1 @@
1
+ """SOC MRE — pacote de análise de credenciais para SOC."""
@@ -0,0 +1,6 @@
1
+ """Permite: python -m soc_mre [args]"""
2
+
3
+ from .main import main
4
+
5
+ if __name__ == "__main__":
6
+ raise SystemExit(main())
@@ -0,0 +1,37 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from pathlib import Path
5
+ from typing import Any, Dict
6
+
7
+
8
+ DEFAULT_CONFIG_FILE = "soc_mre.json"
9
+
10
+ MASTERLIST_FILENAME = "masterList.txt"
11
+
12
+
13
+ def load_config(config_path: Path) -> Dict[str, Any]:
14
+ if not config_path.exists():
15
+ return {}
16
+ try:
17
+ raw = json.loads(config_path.read_text(encoding="utf-8"))
18
+ except (json.JSONDecodeError, OSError):
19
+ return {}
20
+ if not isinstance(raw, dict):
21
+ return {}
22
+ return raw
23
+
24
+
25
+ def save_default_config(config_path: Path) -> None:
26
+ template = {
27
+ "leaks": "/home/kali/Area de trabalho/leaks_23-04-2026",
28
+ "cti": "/home/kali/Area de trabalho/CTI",
29
+ "database_dir": "/home/kali/Area de trabalho/database",
30
+ "blacklist_pattern": "blackList-<dominio>.txt",
31
+ "recent_hours": 24,
32
+ "state_file": ".processed_state.json",
33
+ }
34
+ config_path.write_text(
35
+ json.dumps(template, ensure_ascii=True, indent=2),
36
+ encoding="utf-8",
37
+ )
@@ -0,0 +1,58 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+ from typing import Dict, Set
5
+
6
+
7
+ CredentialDB = Dict[str, Set[str]]
8
+
9
+
10
+ def load_database(db_path: Path) -> CredentialDB:
11
+ db: CredentialDB = {}
12
+ if not db_path.exists():
13
+ return db
14
+
15
+ with db_path.open("r", encoding="utf-8", errors="replace") as f:
16
+ for raw in f:
17
+ line = raw.strip()
18
+ if not line or ":" not in line:
19
+ continue
20
+ email, passwords_raw = line.split(":", 1)
21
+ email = email.strip().lower()
22
+ if not email:
23
+ continue
24
+ password_set = {
25
+ p.strip()
26
+ for p in passwords_raw.split(",")
27
+ if p.strip()
28
+ }
29
+ if not password_set:
30
+ continue
31
+ db.setdefault(email, set()).update(password_set)
32
+ return db
33
+
34
+
35
+ def add_credential(db: CredentialDB, email: str, password: str) -> bool:
36
+ """Retorna True se foi novidade na base."""
37
+ email = email.lower().strip()
38
+ password = password.strip()
39
+ if not email or not password:
40
+ return False
41
+
42
+ known = db.setdefault(email, set())
43
+ if password in known:
44
+ return False
45
+
46
+ known.add(password)
47
+ return True
48
+
49
+
50
+ def save_database(db_path: Path, db: CredentialDB) -> None:
51
+ tmp = db_path.with_suffix(".tmp")
52
+ with tmp.open("w", encoding="utf-8") as f:
53
+ for email in sorted(db.keys()):
54
+ values = sorted(db[email])
55
+ if not values:
56
+ continue
57
+ f.write(f"{email}:{','.join(values)}\n")
58
+ tmp.replace(db_path)
@@ -0,0 +1,140 @@
1
+ from __future__ import annotations
2
+
3
+ import sqlite3
4
+ from datetime import datetime
5
+ from pathlib import Path
6
+ from typing import TYPE_CHECKING, Optional
7
+
8
+ if TYPE_CHECKING:
9
+ from .database import CredentialDB
10
+
11
+
12
+ def init_db(db_path: Path) -> sqlite3.Connection:
13
+ conn = sqlite3.connect(db_path)
14
+ conn.execute("PRAGMA journal_mode=WAL")
15
+ conn.execute("PRAGMA synchronous=NORMAL")
16
+ conn.execute("""
17
+ CREATE TABLE IF NOT EXISTS credentials (
18
+ email TEXT NOT NULL,
19
+ password TEXT NOT NULL,
20
+ domain TEXT NOT NULL,
21
+ source TEXT,
22
+ found_at TEXT DEFAULT (datetime('now')),
23
+ PRIMARY KEY (email, password)
24
+ )
25
+ """)
26
+ conn.commit()
27
+ return conn
28
+
29
+
30
+ def add_credential_sql(
31
+ conn: sqlite3.Connection,
32
+ email: str,
33
+ password: str,
34
+ domain: str,
35
+ source: Optional[str] = None,
36
+ insert_count: Optional[list] = None,
37
+ ) -> bool:
38
+ cursor = conn.execute(
39
+ "INSERT OR IGNORE INTO credentials "
40
+ "(email, password, domain, source) VALUES (?,?,?,?)",
41
+ (email.lower(), password, domain, source),
42
+ )
43
+ inserted = cursor.rowcount > 0
44
+ if inserted and insert_count is not None:
45
+ insert_count[0] += 1
46
+ if insert_count[0] % 100_000 == 0:
47
+ conn.commit()
48
+ return inserted
49
+
50
+
51
+ def _get_timestamped_path(output_path: Path) -> Path:
52
+ """
53
+ Gera um nome de arquivo único usando timestamp com microssegundos.
54
+ Evita colisão mesmo em execuções simultâneas.
55
+ """
56
+ timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S-%f")
57
+
58
+ base = output_path.stem
59
+ suffix = output_path.suffix
60
+ parent = output_path.parent
61
+
62
+ return parent / f"{base}_{timestamp}{suffix}"
63
+
64
+
65
+ def export_domain_txt(
66
+ conn: sqlite3.Connection,
67
+ domain: str,
68
+ output_path: Path,
69
+ ) -> int:
70
+ rows = conn.execute(
71
+ "SELECT email, GROUP_CONCAT(password, ',' ORDER BY password) "
72
+ "FROM credentials WHERE domain=? "
73
+ "GROUP BY email ORDER BY email",
74
+ (domain,),
75
+ ).fetchall()
76
+ if not rows:
77
+ return 0
78
+ target_path = _get_timestamped_path(output_path)
79
+ tmp = target_path.with_suffix(".tmp")
80
+ with tmp.open("w", encoding="utf-8") as f:
81
+ for email, passwords in rows:
82
+ f.write(f"{email}:{passwords}\n")
83
+ tmp.replace(target_path)
84
+ return len(rows)
85
+
86
+
87
+ def close_db(conn: sqlite3.Connection) -> None:
88
+ conn.commit()
89
+ conn.close()
90
+
91
+
92
+ # Linhas migradas de masterList.txt sem dominio por linha.
93
+ _MASTERLIST_DOMAIN = "__masterlist__"
94
+
95
+
96
+ def import_masterlist_txt_to_sql(
97
+ conn: sqlite3.Connection,
98
+ masterlist_path: Path,
99
+ insert_count: Optional[list] = None,
100
+ ) -> int:
101
+ """Importa conteudo de masterList.txt (formato database.load_database) para o SQLite."""
102
+ from .database import load_database
103
+
104
+ if not masterlist_path.exists():
105
+ return 0
106
+ legacy: CredentialDB = load_database(masterlist_path)
107
+ n = 0
108
+ for email, passwords in legacy.items():
109
+ for password in passwords:
110
+ if add_credential_sql(
111
+ conn,
112
+ email,
113
+ password,
114
+ _MASTERLIST_DOMAIN,
115
+ "migration:masterList.txt",
116
+ insert_count,
117
+ ):
118
+ n += 1
119
+ conn.commit()
120
+ return n
121
+
122
+
123
+ def sync_credential_dict_to_sql(
124
+ conn: sqlite3.Connection,
125
+ domain: str,
126
+ cred_db: "CredentialDB",
127
+ insert_count: Optional[list] = None,
128
+ ) -> None:
129
+ """Garante no SQLite as credenciais ja carregadas do blackList-<dominio>.txt em RAM."""
130
+ for email, passwords in cred_db.items():
131
+ for password in passwords:
132
+ add_credential_sql(
133
+ conn,
134
+ email,
135
+ password,
136
+ domain,
137
+ "import:blackList",
138
+ insert_count,
139
+ )
140
+ conn.commit()