Skip to content
KitploitKITPLOIT
FerramentasExploitsBlog
Log in
Enviar
FerramentasExploitsBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

FeedsContatoPrivacidade© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
hate_crack — Uma ferramenta para automatizar metodologias de cracking através do Hashcat da equipe TrustedSec. | Kitploit
Ferramentas/GitHubGitHub/trustedsec/hate_crack
Quebra de SenhasAtaques de SenhaAnálise de HashTestes de Penetração
GitHubtrustedsec/hate_crack

hate_crack

Uma ferramenta para automatizar metodologias de cracking através do Hashcat da equipe TrustedSec.

Ver Repositório
1.9k28741há 17h 32mRevisado pelo Kitploit

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar
Site
```
  ___ ___         __             _________                       __
 /   |   \_____ _/  |_  ____     \_   ___ \____________    ____ |  | __
/    ~    \__  \\   __\/ __ \    /    \  \/\_  __ \__  \ _/ ___\|  |/ /
\    Y    // __ \|  | \  ___/    \     \____|  | \// __ \\  \___|    <
 \___|_  /(____  /__|  \___  >____\______  /|__|  (____  /\___  >__|_ \
       \/      \/          \/_____/      \/            \/     \/     \/
```

## Instalação

Instalar a partir do código-fonte é o único caminho suportado. hate_crack **não** é
distribuído no PyPI: `pip install hate-crack` resolve para um placeholder `0.0.0`
que falha de propósito e aponta de volta para aqui. O nome é mantido apenas para que ninguém mais
possa publicar um sósia sob ele — veja
[`packaging/pypi-placeholder/`](https://github.com/trustedsec/hate_crack/blob/main/packaging/pypi-placeholder).

### 1. Instalar o hashcat

O Hashcat deve estar instalado e disponível no seu PATH:

Ubuntu/Kali:
```bash
sudo apt-get install -y hashcat
```

macOS (Homebrew):
```bash
brew install hashcat
```

Ou baixe um binário pré-compilado de https://hashcat.net/hashcat/ e defina `hcatPath` em `config.json` para o seu local.

### 2. Baixar o hate_crack

Clone com submódulos (necessário para hashcat-utils, princeprocessor, pcfg_cracker, Corporate_Masks e, opcionalmente, omen):

```bash
git clone --recurse-submodules https://github.com/trustedsec/hate_crack.git
cd hate_crack
```

Se você clonou sem submódulos, inicialize-os:

```bash
git submodule update --init --recursive
```

Em seguida, personalize a configuração se necessário. O hate_crack usa dois arquivos de configuração, cada um com um conjunto distinto de definições:

- **`config.json`** — caminhos de wordlist, máscaras, regras, ajustes, potfile, caminho do hashcat, limites de candidatos, alternâncias de notificação, padrões de preferência da CLI (35 definições).
- **`.env`** — apenas definições de integração com terceiros: credenciais do Hashview e Hashmob, credenciais do Pushover, Ollama e pipal (14 definições). Não rastreado pelo git, criado com modo `0600`.

A linha fica aí por uma razão: `.env` é o arquivo que pode conter segredos. As credenciais para, e a configuração de, serviços de terceiros vão para o arquivo não rastreado, com modo `0600`; tudo o que o hate_crack faz localmente fica em `config.json`, que é seguro para compartilhar, comparar e guardar nas suas próprias notas. É também por isso que as *credenciais* do Pushover estão em `.env` enquanto as *alternâncias* de ligar/desligar do Pushover estão em `config.json` — as alternâncias são preferências locais, não segredos.

Cada chave tem exatamente um lar. Uma chave colocada no outro arquivo é ignorada, e o hate_crack imprime um aviso indicando o arquivo a que pertence. Qualquer chave pode ainda ser substituída para uma única execução exportando a sua variável de ambiente. A maioria dos utilizadores pode saltar este passo, pois os caminhos predefinidos funcionam de imediato.

`config.json` é permanente e de primeira classe — não está obsoleto e não há prazo de remoção para ele. Apenas as definições de integração foram movidas.

**A atualizar a partir de um único `config.json`?** O hate_crack migra-o por si na primeira execução: as definições de integração são copiadas para um novo `.env` com modo `0600`, depois removidas de `config.json` para que os dois arquivos não as reivindiquem ambos. Imprime quais as chaves que foram movidas (nunca os seus valores) e guarda o seu original como `config.json.pre-split.bak` antes de o tocar. Tudo o resto em `config.json` é deixado exatamente como estava, incluindo a ordem das chaves.

**Primeira execução:** o hate_crack cria ambos os arquivos por si, por isso não há nada a fazer. Para configurar `.env` manualmente, copie o modelo rastreado:

```bash
cp .env.example .env
chmod 600 .env
```

`.env.example` é versionado e é distribuído com todas as chaves de credenciais vazias. O próprio `.env` **nunca** deve ser versionado — está no gitignore, juntamente com as suas habituais variantes de backup, e o hate_crack cria-o sempre com o modo `0600` (apenas leitura/escrita pelo proprietário). O `.env.example` é gerado a partir do schema; regenere-o após alterar `hate_crack/config_schema.py` com `uv run python -m hate_crack.config_writer`.

### 3. Instalar dependências e o hate_crack

A forma mais fácil é executar `make` (ou `make install`), que deteta automaticamente o seu SO e instala:
- Dependências externas (p7zip, transmission-daemon / transmission-remote)
- Compila os submódulos (hashcat-utils, princeprocessor, pcfg_cracker e, opcionalmente, omen) e faz checkout do conjunto de máscaras Corporate_Masks apenas com dados
- Dependências Python via uv e um shim de CLI em `~/.local/bin/hate_crack`

```bash
make
```

Isso é idempotente - ele ignora ferramentas já instaladas. Para forçar uma reinstalação limpa:

```bash
make reinstall
```

**Ou instale as dependências manualmente:**

### Dependências Externas
Estas são necessárias para certos fluxos de download/extração:

- `7z`/`7za` (p7zip) — usado para extrair arquivos `.7z`.
- `transmission-daemon` / `transmission-remote` — usado para baixar torrents do Weakpass.

Comandos de instalação manual:

Ubuntu/Kali:
```bash
sudo apt-get update
sudo apt-get install -y p7zip-full transmission-daemon
```

macOS (Homebrew):
```bash
brew install p7zip transmission-cli  # provides transmission-daemon and transmission-remote
```

Em seguida, instale as dependências Python e o shim de CLI:
```bash
uv sync
mkdir -p ~/.local/bin
printf '#!/usr/bin/env bash\nset -euo pipefail\nexec uv run --directory %s python -m hate_crack "$@"\n' "$(pwd)" > ~/.local/bin/hate_crack
chmod +x ~/.local/bin/hate_crack
```

-------------------------------------------------------------------
## Estrutura do Projeto
A lógica principal agora está dividida em módulos sob `hate_crack/`:

- `hate_crack/cli.py`: auxiliares de argparse e substituições de configuração.
- `hate_crack/api.py`: integrações com Hashview, Weakpass e Hashmob (downloads/menus/auxiliares).
- `hate_crack/attacks.py`: manipuladores de ataques do menu.
- `hate_crack/corpus_stats.py`: estatísticas de senhas de todo o corpus usadas para descrever um corpus ao LLM.
- `hate_crack/plaintext.py`: recupera a senha de uma linha do corpus (remoção de prefixo de hash, decodificação `$HEX[...]`); compartilhado pelos modos LLM, corpus_stats e rulegen.
- `hate_crack/llm.py`: geração estruturada (JSON) de candidatos por LLM via Atomic Agents.
- `hate_crack/menu.py`: renderizador de menu compartilhado, incluindo navegação opcional por teclas de seta.
- `hate_crack/noninteractive.py`: despachante para os subcomandos de ataque scriptados.
- `hate_crack/notify/`: pacote de notificações (backend Pushover, tailer por crack).
- `hate_crack/username_detect.py`: detecta arquivos de entrada `username:hash` para decidir sobre o `--username` do hashcat.
- `hate_crack/formatting.py`, `hate_crack/progress.py`: auxiliares de formatação de saída e exibição de progresso.
- `hate_crack/main.py`: implementação principal da CLI.

O `hate_crack.py` de nível superior permanece como ponto de entrada principal e orquestra esses módulos.

-------------------------------------------------------------------
## Referências e Agradecimentos

Este projeto depende e é inspirado por vários projetos e serviços externos. Agradecimentos a:

- Hashview (http://github.com/hashview/)
- Weakpass (https://weakpass.com)
- Hashmob (https://hashmob.net)

-------------------------------------------------------------------
## Uso

Após instalar com `make`, execute o hate_crack de qualquer lugar:

```bash
hate_crack
# or with arguments:
hate_crack <hash_file> <hash_type> [options]
```

Como alternativa, execute via `uv`:

```bash
uv run hate_crack.py <hash_file> <hash_type>
```

### Executar como ferramenta (recomendado)

Instale usando `make` a partir da raiz do repositório - isso compila submódulos e empacota os recursos:

```bash
cd /path/to/hate_crack
make
hate_crack
```

O comando `make install` cria um shim bash em `~/.local/bin/hate_crack` que é executado a partir do diretório do repositório, para que a configuração e os assets sejam sempre encontrados independentemente do seu diretório de trabalho atual.

A configuração também é procurada em:
- A raiz do repositório e o diretório do pacote
- `~/.hate_crack`

**Nota:** O `hcatPath` em `config.json` é apenas para a localização do binário hashcat (opcional se o hashcat estiver no PATH). Os assets do Hate_crack (hashcat-utils, princeprocessor, pcfg_cracker, Corporate_Masks, omen) são carregados a partir do diretório do repositório e empacotados automaticamente pelo `make install`.

### Executar como script
O script usa um shebang `uv`. Torne-o executável e execute:

```bash
chmod +x hate_crack.py
./hate_crack.py
```

Também pode usar Python diretamente:

```bash
python hate_crack.py
```

### Uso não interativo / com script

Para automação, você pode iniciar um único ataque diretamente, ignorando o menu. O nome do ataque é o primeiro argumento, seguido pelo arquivo de hash e pelo tipo de hash do hashcat. Os prompts de pré-processamento (filtragem de contas de computador, força bruta com LM primeiro, deduplicação de contas duplicadas) aceitam automaticamente seus padrões neste modo. O processo sai com `0` em caso de sucesso e com valor diferente de zero em caso de erro (arquivo de hash ausente, tipo de hash não numérico, wordlist ausente ou um nome de arquivo de regra desconhecido).

```bash
# Quick crack: one wordlist + optional rule(s) from the rules directory
hate_crack quick hashes.txt 1000 --wordlist rockyou.txt --rules best64.rule

# Chain two rules in a single run
hate_crack quick hashes.txt 1000 --wordlist rockyou.txt --rules best64.rule+d3ad0ne.rule

# Run two rules as two separate passes
hate_crack quick hashes.txt 1000 --wordlist rockyou.txt --rules best64.rule d3ad0ne.rule

# Canned dictionary methodology (uses your configured wordlists)
hate_crack dict hashes.txt 1000

# Brute force lengths 1-8
hate_crack brute hashes.txt 1000 --min 1 --max 8

# Top-mask attack targeting ~4 hours
hate_crack topmask hashes.txt 1000 --target-time 4
```

A maioria dos ataques do menu está disponível da mesma forma. Estes não precisam de nada além do arquivo de hash e do tipo de hash:

```bash
hate_crack fingerprint hashes.txt 1000
hate_crack pathwell    hashes.txt 1000
hate_crack prince      hashes.txt 1000
hate_crack pcfg        hashes.txt 1000
hate_crack princeling  hashes.txt 1000
hate_crack smartmask   hashes.txt 1000
hate_crack corporate   hashes.txt 1000
hate_crack combinator  hashes.txt 1000     # configured wordlists
hate_crack hybrid      hashes.txt 1000     # configured wordlists
```

Cada um também aceita as configurações que sua entrada de menu solicita:

```bash
# Fingerprint, tuned: escalate to 24-character fragments and cap the keyspace
hate_crack fingerprint hashes.txt 1000 --max-expander-len 24 \
    --run-hybrid-on-expanded --keyspace-limit 50000000000

# Skip the fragment/wordlist combination step entirely
hate_crack fingerprint hashes.txt 1000 --no-dictionary-wordlist

# Override the configured wordlists (combinator needs at least two).
# Two wordlists use combinator, three use combinator3, more -- or any
# --separator -- use combinatorX, matching what the menu does.
hate_crack combinator hashes.txt 1000 --wordlist first.txt second.txt
hate_crack combinator hashes.txt 1000 --wordlist a.txt b.txt c.txt
hate_crack combinator hashes.txt 1000 --wordlist a.txt b.txt --separator -
hate_crack hybrid     hashes.txt 1000 --wordlist rockyou.txt

# Corporate masks, lengths 8-12 only
hate_crack corporate hashes.txt 1000 --min 8 --max 12

# Smart mask, skipping templates over 10 billion candidates
hate_crack smartmask hashes.txt 1000 --keyspace-limit 10000000000
```

Os restantes recebem a única entrada que a sua entrada de menu solicita:

```bash
# Bandrel methodology (comma-separate multiple companies)
hate_crack bandrel hashes.txt 1000 --company "Acme,Acme Corp"

# Permutation attack over a short targeted wordlist
hate_crack permute hashes.txt 1000 --wordlist names.txt

# Ad-hoc mask -- a literal mask or a .hcmask file, optionally incrementing
hate_crack adhocmask hashes.txt 1000 --mask '?u?l?l?l?d?d'
hate_crack adhocmask hashes.txt 1000 --mask masks/corporate.hcmask
hate_crack adhocmask hashes.txt 1000 --mask '?a?a?a?a?a?a?a?a' \
    --increment-min 4 --increment-max 8
hate_crack adhocmask hashes.txt 1000 --mask '?a?a?a?a' --increment

# N-gram candidates from a corpus
hate_crack ngram hashes.txt 1000 --corpus corpus.txt --group-size 3

# Combipow passphrases (wordlist capped at 63 lines: it generates 2^n-1)
hate_crack combipow hashes.txt 1000 --wordlist words.txt
hate_crack combipow hashes.txt 1000 --wordlist words.txt --no-spaces

# Spoonman: basewords and rules derived from a corpus of known passwords
hate_crack spoonman hashes.txt 1000 --corpus previous-engagement.txt
hate_crack spoonman hashes.txt 1000 --corpus previous.txt --rule-coverage 95
# --rule-coverage accepts 50, 75, 95 or 99 -- the only capped rule files
# derived. Omit it for the full rule set.

# OMEN -- requires a model trained beforehand from the interactive menu
hate_crack omen hashes.txt 1000 --max-candidates 1000000

# Loopback: re-run rules against the plaintexts already cracked
hate_crack loopback hashes.txt 1000 --rules best64.rule
```

`fingerprint` é o único comando cuja forma simples não é idêntica à sua entrada de menu: a opção 5 do menu executa sempre as passagens híbridas sobre fragmentos expandidos, enquanto o subcomando usa por omissão o valor predefinido do próprio `hcatFingerprint`, que é desativado. Passe `--run-hybrid-on-expanded` para corresponder ao menu.

Cinco entradas de menu continuam a ser apenas interativas, porque precisam de entrada que uma única flag não consegue transportar: força bruta de Markov, Random Rules, o ataque Rosetta, o ataque LLM e a metodologia Extensive Pure_Hate (um orquestrador sobre os outros em vez de um único ataque).

#### Códigos de saída

| Código | Significado |
|---|---|
| `0` | O ataque foi executado |
| `1` | Entrada inválida — ficheiro de hash ou wordlist em falta, tipo de hash não numérico, nome de ficheiro de regras desconhecido, argumento fora do intervalo |
| `2` | Subcomando desconhecido — esta compilação do hate_crack não o tem |
| `3` | Apenas com `--exit-code-on-skip`: a cobertura já tinha visto todas as passagens, por isso nada foi lançado |

A saída `2` e a saída `3` são o que permite a um driver com script distinguir "esta versão não consegue executar esse ataque" e "era redundante" de "foi executado e não encontrou nada". O `--exit-code-on-skip` é opt-in para que ativar a cobertura não comece a fazer falhar harnesses anteriores a ela.

-------------------------------------------------------------------
## Resolução de problemas

### Erro: "would clobber existing tag" ao atualizar

Um clone mais antigo pode recusar-se a atualizar, imprimindo uma longa lista de linhas como:

```
 ! [rejected]        v2.5.0     -> v2.5.0  (would clobber existing tag)
```

Isso afeta clones criados antes de julho de 2026. O histórico publicado foi reescrito
naquela época para remover alguns arquivos que nunca deveriam ter sido commitados, o que deu
a cada commit um novo ID; portanto, as tags de um clone mais antigo apontam para objetos que este
repositório não contém mais, e o git se recusa a mover uma tag que já possui.
Não há nada de errado com o seu checkout e nenhum dado de cracking está em risco.

Recupere com um reset único. Isso descarta commits e edições locais no
checkout, então, se você personalizou algo rastreado pelo git (em oposição a
`config.json`, que não é rastreado), faça commit em um branch primeiro:

```bash
cd /path/to/hate_crack
git fetch --tags --force origin
git checkout -B main origin/main
make install
```

`--force` aqui apenas atualiza as tags; não consegue tocar nos seus commits. Depois disso, o
atualizador integrado funciona normalmente. Versões anteriores à 2.18 não conseguiam realizar esta
recuperação por conta própria, e é por isso que ela precisa ser feita manualmente uma vez.

### Erro: O diretório de build não existe

Se você vir um erro como:
```
Error: Build directory /opt/hashcat/hashcat-utils does not exist.
Expected to find expander at /opt/hashcat/hashcat-utils/bin/expander.
```

Isso significa que os assets do hate_crack não foram incluídos no pacote instalado.

**Compreendendo os caminhos:**
- `hcatPath` em config.json → aponta para o **local do binário hashcat** (opcional, pode estar no PATH)
- `hashcat-utils/` e `princeprocessor/` → incluídos no pacote pelo `make install`

**Solução:**
Reinstale usando o Makefile, que compila os submódulos e instala a ferramenta:
```bash
cd /path/to/hate_crack  # the repository checkout
make install
```

**Configuração padrão (config.json.example):**

A maioria dos usuários pode usar os padrões sem personalização:
- `hcatWordlists`: `./wordlists` (relativo à raiz do repositório ou HOME/.hate_crack)
- `hcatOptimizedWordlists`: `./optimized_wordlists` (diretório usado pelo Quick Crack; recorre a `hcatWordlists` se não for encontrado)
- `rules_directory`: `./hashcat/rules` (inclui regras do submódulo)
- `hcatTuning`: `` (string vazia - sem flags de ajuste padrão)

**Exemplos de personalizações do config.json:**
```json
{
  "hcatPath": "/usr/local/bin",          # Location of hashcat binary (optional, auto-detected from PATH)
  "hcatBin": "hashcat",                  # Hashcat binary name
  "hcatWordlists": "./wordlists",        # Dictionary wordlist directory (relative or absolute)
  "rules_directory": "./hashcat/rules",  # Rules directory (relative or absolute)
  "hcatTuning": "",                      # Additional hashcat flags (empty by default)
  ...
}
```

**Carregamento de configuração:**
- Precedência para cada chave: `os.environ` > o próprio arquivo home dessa chave (`.env` ou `config.json`) > padrão embutido
- Chaves ausentes recorrem aos padrões embutidos; `config.json.example` documenta todas as chaves de `config.json`
- Ambos os arquivos são procurados, independentemente um do outro, nesta ordem: **raiz do repositório**, depois o **diretório do pacote instalado**, depois **`~/.hate_crack`**. A primeira correspondência vence; é normal que os dois arquivos venham de diretórios diferentes.
- Na primeira execução, ambos são criados — `config.json` a partir de `config.json.example`, `.env` a partir dos padrões embutidos. Se um `config.json` mais antigo ainda contiver chaves de integração, elas são copiadas para o novo `.env` e o hate_crack informa quais delas devem ser excluídas do `config.json`; ele nunca edita esse arquivo por conta própria.
- Em cada execução, o hate_crack imprime os dois arquivos que realmente carregou:

  ```
  [*] config.json: /home/you/.hate_crack/config.json
  [*] .env:        /home/you/.hate_crack/.env
  ```

  Leia essas duas linhas antes de depurar uma configuração que "não está surtindo efeito". Elas existem por causa de duas armadilhas na ordem de busca:

  - **Um checkout tem precedência sobre seu diretório home.** A raiz do repositório é buscada primeiro, então um `.env` ou `config.json` presente em *qualquer* checkout a partir do qual você execute a ferramenta prevalece sobre o que está em `~/.hate_crack` — e executar a ferramenta a partir de um checkout é exatamente o que cria esses arquivos ali em primeiro lugar. Se isso algum dia sobrepuser uma configuração real de `~/.hate_crack`, o hate_crack agora avisa com uma terceira linha `[!]` nomeando ambos os caminhos — trate essa linha como "o arquivo abaixo está sendo ignorado", não como uma segunda configuração igualmente válida.
  - **O diretório de trabalho atual nunca é buscado.** Um `.env` no diretório em que você estiver é ignorado, deliberadamente: diretórios de engajamento estão cheios de arquivos que ninguém pretendia que fossem configuração. Coloque-o na raiz do repositório ou em `~/.hate_crack`.

### Erro: merge with ref 'refs/heads/master' but no such ref was fetched

Se você vir:
```
Your configuration specifies to merge with the ref 'refs/heads/master'
from the remote, but no such ref was fetched.
```

O branch padrão foi renomeado de `master` para `main`. Corrija com:
```bash
git remote set-head origin -a
git branch -m master main
git branch --set-upstream-to=origin/main main
git pull
```

### Alvos do Makefile

**Padrão (instalação completa)** - compila submódulos, instala dependências e instala a ferramenta:

```bash
make
# or explicitly:
make install
```

Isto é idempotente - ignora ferramentas já instaladas.

**Forçar reinstalação limpa:**

```bash
make reinstall
```

**Atualização rápida** - reconstrói submódulos e reinstala a ferramenta (após puxar as alterações):

```bash
make update
```

**Desinstalar** - remove as dependências do SO e a ferramenta:

```bash
make uninstall
```

**Compilar apenas o hashcat-utils:**

```bash
make hashcat-utils
```

**Executar testes** - lida automaticamente com HATE_CRACK_SKIP_INIT quando necessário:

```bash
make test
```

**Relatório de cobertura:**

```bash
make coverage
```

**Limpar artefatos de build/teste:**

```bash
make clean
```

## Desenvolvimento

### Configurando o Ambiente de Desenvolvimento

Instale o projeto com dependências opcionais de desenvolvimento (inclui linters e ferramentas de teste):

```bash
make dev-install
```

### Executando Linters e Verificações de Tipos

Antes de enviar alterações, execute estas verificações localmente. Use `make lint` para tudo, ou execute verificações individuais:

**Ruff (linting e formatação):**
```bash
make ruff
# or manually:
uv run ruff check hate_crack tests tools packaging hate_crack.py
```

Corrigir problemas automaticamente:
```bash
uv run ruff format hate_crack tests tools packaging hate_crack.py
uv run ruff check --fix hate_crack tests tools packaging hate_crack.py
```

**ty (verificação de tipos):**
```bash
make ty
# or manually:
uv run ty check hate_crack
```

**Executar todas as verificações em conjunto:**
```bash
make lint
```

### Executando Testes

Os testes detectam automaticamente quando os submódulos não estão compilados e definem `HATE_CRACK_SKIP_INIT=1` automaticamente.

```bash
make test
```

Ou execute pytest diretamente:

```bash
uv run pytest -v
```

Com cobertura:

```bash
make coverage
```

Ou com pytest:

```bash
uv run pytest --cov=hate_crack
```

### Git Hooks (prek)

Os Git hooks são gerenciados pelo [prek](https://github.com/j178/prek) (v0.3.3+). Instale os hooks com:

```bash
prek install --hook-type pre-push --hook-type pre-commit
```

Isso instala os hooks definidos em `prek.toml` usando o esquema TOML
local-repo do pre-commit:
- **pre-push** (hooks locais): ruff, ruff-format, ty, pytest, pytest-lima, bandit
- **pre-commit** (de `pre-commit/pre-commit-hooks`): trailing-whitespace,
  end-of-file-fixer, check-yaml, check-merge-conflict, check-added-large-files,
  detect-private-key

Os auto-corretores do pre-commit reescrevem os ficheiros no local, por isso
volte a fazer stage e commit depois de serem executados.

Nota: o prek 0.3.3 espera `repos = [...]` no nível superior. O formato antigo
`[hooks.<stage>] commands = [...]` não é suportado.

### Navegação de Menus com Teclas de Seta

Os menus usam, por predefinição, a seleção clássica numerada com `print()` +
`input()`, que aceita chaves completas com vários dígitos.

Para ativar a navegação com teclas de seta através do `simple-term-menu`,
defina `HATE_CRACK_ARROW_MENU=1`. Nesse modo pode mover-se com as teclas de
seta ou escrever o número da opção (incluindo números com vários dígitos, como
`99`) e premir Enter. Escrever qualquer outra coisa filtra a lista. O modo de
teclas de seta também requer um TTY, por isso fica desativado quando a saída é
canalizada.

Os seletores que imprimem uma lista e depois aceitam entrada escrita
(wordlists, rules, a lista Weakpass, wordlist e IDs de regras do Hashview)
aceitam Up/Down em todos os backends, sem `HATE_CRACK_ARROW_MENU`. Up preenche
a última chave listada, Up novamente a anterior, Down volta atrás; pode ainda
escrever um número, um caminho ou uma lista como `1,3`. Um `,`, `+` ou `-`
escrito logo a seguir a uma chave preenchida por seta estende-a. Nos backends
`plain` e `rich` isto funciona carregando as chaves listadas no histórico do
readline apenas para esse prompt, pelo que o seu próprio histórico é reposto
depois e não é acessível dentro de um prompt de lista.

### Dependências de Desenvolvimento

O grupo opcional `[dev]` inclui:
- **ty** - Verificador de tipos estático
- **ruff** - Linter e formatador Python rápido
- **pytest** - Framework de testes
- **pytest-cov** - Relatório de cobertura

-------------------------------------------------------------------
Opções comuns:
- `--download-hashview`: Descarregar hashes do Hashview antes de fazer cracking.
- `--hashview`: Menu interativo do Hashview para gerir hashes, wordlists e jobs.
- `--hashview --help`: Mostrar as opções de linha de comandos do Hashview.
- `--weakpass`: Descarregar wordlists do Weakpass.
- `--rank`: Mostrar apenas wordlists do Weakpass com um nível específico (0=todos, -1=níveis S/A/B). Níveis: 7=S, 6=A, 5=B, 4=C, 3=D, 2=E, 1=F.
- `--hashmob`: Descarregar wordlists do Hashmob.net.
- `--hashmob-masks`: Descarregar masks do Hashmob.net.
- `--download-torrent <FILENAME>`: Descarregar um ficheiro torrent específico do Weakpass.
- `--download-all-torrents`: Descarregar todos os torrents do Weakpass disponíveis a partir da cache.
- `--wordlists-dir <PATH>` / `--optimized-wordlists-dir <PATH>`: Substituir os diretórios de wordlists.
- `--pipal-path <PATH>`: Substituir o caminho do pipal.
- `--restore-potfile`: Reconstruir `<hashfile>.out` a partir do ficheiro POT do hashcat no arranque, substituindo qualquer conteúdo existente, e depois continuar para o menu normal. Sem esta flag, a consulta ao POT só é executada quando `.out` ainda não existe. A opção 93 do menu faz o mesmo a pedido, com um prompt de confirmação.
- `--maxruntime <SECONDS>`: Substituir o tempo máximo de execução.
- `--bandrel-basewords <PATH>`: Substituir o ficheiro de basewords do bandrel.
- `--update`: Atualizar para a versão mais recente e reinstalar. Muda o checkout para `main` se estiver noutro branch, uma vez que as tags de release ficam lá.
- `--nightly`: Atualizar para a nightly mais recente, a partir do branch `nightly-dev`. As nightlies passaram a CI mas não fazem parte de uma release final. Também pode ser escrito `--update --nightly`.
- `--no-optimized-kernel` (ou `--no-optimize`): Nunca passar `-O` ao hashcat durante toda a execução. Substitui `optimizedKernelAttacks` em `config.json` e remove qualquer `-O` que tenha colocado em `hcatTuning`. Nada é escrito de volta na configuração, por isso aplica-se apenas a esta execução. Com um subcomando, coloque-o antes do subcomando: `./hate_crack.py --no-optimize quick hashes.txt 1000 --wordlist words.txt`.
- `--debug`: Ativar o registo de depuração (escreve para stderr).

### Integração com o Hashview

O hate_crack integra-se com o Hashview para gestão centralizada de hashes e cracking distribuído.

#### Menu Interativo

Aceder ao menu interativo do Hashview:
```bash
hate_crack.py --hashview
```

Opções de menu:
- **(1) Upload Cracked Hashes** - Envia resultados quebrados da sessão atual para o Hashview
- **(2) Upload Wordlist** - Envia um arquivo de wordlist para o Hashview
- **(3) Download Wordlist** - Baixa uma wordlist do Hashview
- **Download Rule** - Baixa um arquivo de regras do Hashview (descomprimido para texto simples, pronto para `hashcat -r`). Digite `a` (ou `all`) no prompt de ID da regra para baixar todas as regras listadas em vez de apenas uma
- **Download All Rules** - Baixa todos os arquivos de regras listados pelo Hashview em uma única passagem; falhas por regra são reportadas sem abortar o restante
- **(4) Download Left Hashes** - Baixa os hashes restantes não quebrados (solicita a troca para quebra)
- **(5) Download Found Hashes** - Baixa hashes já quebrados com senhas em texto claro (para referência/análise)
- **(6) Upload Hashfile and Create Job** - Envia um novo hashfile e cria um job de quebra
- **(99) Back to Main Menu** - Retorna ao menu principal

**Importante: Download Found vs Download Left**
- **Download Left Hashes (4)**: Baixa hashes não quebrados que precisam ser quebrados. Mescla automaticamente com quaisquer hashes encontrados, se disponíveis, e solicita a troca para este hashfile para quebra.
- **Download Found Hashes (5)**: Baixa hashes já quebrados no formato hash:cleartext. Estes são para referência e não podem ser quebrados novamente. Nenhum prompt de troca é exibido.

#### Interface de Linha de Comando

As operações do Hashview também podem ser realizadas via linha de comando:

Enviar hashes quebrados:
```bash
hate_crack.py --hashview upload-cracked --file <output_file>.out --hash-type 1000
```

Carregue uma wordlist:
```bash
hate_crack.py --hashview upload-wordlist --file <wordlist>.txt --name "My Wordlist"
```

Baixe um arquivo de regras (salvo descompactado, pronto para `hashcat -r`):
```bash
hate_crack.py --hashview download-rules --rules-id 4 --output best64.rule
```

Baixar hashes restantes (hashes não quebrados para quebra):
```bash
hate_crack.py --hashview download-left --customer-id 1 --hashfile-id 123
```

Baixar hashes encontrados (hashes já quebrados com texto claro):
```bash
hate_crack.py --hashview download-found --customer-id 1 --hashfile-id 123
```

Carregue o arquivo de hash e crie o job:
```bash
hate_crack.py --hashview upload-hashfile-job --file hashes.txt --customer-id 1 \
  --hash-type 1000 --job-name "NTLM Crack Job" --hashfile-name "Domain Hashes"
```

#### Configuração

Defina as credenciais do Hashview no `.env` (são configurações de integração, portanto não ficam no `config.json`):
```
HASHVIEW_URL=https://hashview.example.com
HASHVIEW_API_KEY=your-api-key-here
HASHVIEW_VERIFY_TLS=true
```

`HASHVIEW_VERIFY_TLS` tem como padrão `true`: o hate_crack verifica o certificado TLS do servidor Hashview, e a conexão a um Hashview com um certificado autoassinado ou de CA interna falhará até que esse certificado seja confiável (adicione-o ao armazenamento de confiança do seu sistema, ou use um certificado emitido por uma CA na qual seu sistema já confia). Se isso não for possível, defina `HASHVIEW_VERIFY_TLS=false` -- o hate_crack imprimirá um aviso de uma linha nomeando o host a cada início de processo quando a verificação estiver desativada, já que desativá-la remove a proteção contra um servidor falsificado ou um atacante no caminho interceptando a conexão.

#### Configuração do LLM

O LLM Attack (opção 12) e o Rosetta Mask Attack (opção 23) geram seus candidatos com um modelo local. Configure o modelo, a janela de contexto e o tempo limite de requisição no `.env`:

```
LLM_BACKEND=ollama
OLLAMA_MODEL=qwen3:4b-instruct
OLLAMA_NUM_CTX=8192
OLLAMA_TIMEOUT=300
```

**As chaves `OLLAMA_*` abaixo aplicam-se a todos os backends, não apenas ao Ollama.** Elas mantêm esse prefixo porque `OLLAMA_HOST` é a mesma variável que a própria CLI do Ollama lê, e renomeá-las quebraria todos os `.env` existentes sem ganho funcional — um servidor vLLM ou compatível com OpenAI quer o mesmo host, modelo, timeout, contexto e parâmetros de amostragem sob os mesmos nomes. `LLM_BACKEND` apenas seleciona como a requisição é moldada.

- **`OLLAMA_MODEL`** — O modelo Ollama usado para geração de candidatos (padrão: `qwen3:4b-instruct`). O ataque LLM usa saída estruturada (JSON), então escolha um modelo com bom suporte a ferramentas/JSON.
- **`OLLAMA_NUM_CTX`** — Tamanho da janela de contexto do modelo (padrão: `8192`). Era `2048` antes das estatísticas de corpus serem introduzidas, o que era pequeno demais para conter o prompt que estava sendo fornecido: 500 plaintexts amostrados ocupam aproximadamente 2.000–3.500 tokens antes do system prompt e da resposta, então o Ollama truncava silenciosamente parte da amostra que o amostrador havia cuidadosamente distribuído pelo arquivo.
- **`OLLAMA_TIMEOUT`** — Segundos para aguardar uma resposta de geração antes de desistir (padrão: `300`). Aumente isso se um modelo grande ainda estiver carregando na VRAM na primeira requisição, o que pode exceder o timeout; o hate_crack imprime o timeout decorrido e o nome desta configuração quando ele dispara.
- **`OLLAMA_MAX_SAMPLE_LINES`** — O limiar abaixo do qual os modos LLM também colam os plaintexts literais no prompt (padrão: `500`). Valores ≤ 0 são tratados como 500.

  Modos derivados de corpus (**Wordlist**, **Cracked passwords**, **Pattern rules**) sempre descrevem o corpus *inteiro* estatisticamente — proporções de basewords, máscaras, capitalização, comprimentos, dígitos e símbolos finais, anos — em vez de colar uma fatia dele. A agregação é limitada, então um dump de 120.000 senhas custa aproximadamente o mesmo espaço de prompt que um de 500 linhas. Quando o corpus inteiro cabe abaixo deste limiar, os plaintexts brutos também são incluídos, já que nada se ganha escondendo um corpus pequeno do modelo.

  Isso substitui o comportamento anterior de colar uma amostra uniformemente espaçada de até `ollamaMaxSampleLines` senhas. Uma amostra de um dump grande não transmitia nenhuma informação de frequência: o modelo não conseguia distinguir uma baseword usada por 8% da organização de uma usada por uma única pessoa, que é precisamente o sinal que torna um palpite digno de ser executado.
- **`OLLAMA_NO_CLOUD`** — Quando `true`, recusa enviar qualquer coisa para fora deste host, para qualquer um dos três backends LLM (Ollama, vLLM ou um servidor genérico compatível com OpenAI). Duas verificações são controladas por esta única configuração: o Ollama faz proxy de um modelo com tag `-cloud` (`gpt-oss:120b-cloud`, `deepseek-v3.1:671b-cloud`) para ollama.com através do mesmo endpoint local que um modelo local usa, então nada na requisição parece diferente — isso é recusado pelo nome do modelo. A URL do backend configurado também é verificada: um destino que não seja loopback, privado ou link-local (e que não seja `localhost` ou um nome `.local`/`.internal`/`.lan`/`.localdomain`) é recusado pelo destino, e um hostname que esta verificação não consegue resolver também é recusado, fail-closed, em vez de deixar passar um destino não verificável. Os prompts do hate_crack carregam plaintexts recuperados, estatísticas de corpus e o nome, setor e localização do cliente, então qualquer uma das verificações disparando significa que a requisição é recusada antes de ser construída. Padrão `false`, então um modelo em nuvem ou servidor remoto deliberadamente configurado continua funcionando; ative para engajamentos onde os dados do cliente não devem sair do host.
- **`OLLAMA_AUTO_RESEARCH`** — Quando `true` (padrão), o modo **Target info** pede ao modelo local para sugerir o setor, localização e empresa controladora / histórico de aquisições assim que você digita o nome da empresa, e os oferece como padrões editáveis do prompt. Defina como `false` para sempre obter prompts em branco (útil com um modelo lento, já que a pesquisa custa uma ida e volta extra antes do ataque começar).
- **`OLLAMA_HOST`** — Onde o backend configurado está escutando. Aceita um `host:port` simples (`theplague.lan:11434`) ou uma URL completa com esquema (`https://ollama.example.com`); de qualquer forma a URL base é normalizada antes do uso. Padrão `localhost:11434`, que é a porta do Ollama — um servidor vLLM ou compatível com OpenAI precisa que isso seja definido para a sua própria (o vLLM comumente escuta em `:8000`). Defina no `.env`, ou exporte como uma variável de ambiente real para sobrescrever isso em uma única execução — é o mesmo nome de variável que a própria CLI do Ollama lê.
- **`LLM_BACKEND`** — Com qual servidor compatível com OpenAI conversar: `ollama` (padrão), `vllm` ou `openai` para um genérico. Todo backend fala a mesma API de chat-completions `/v1`, então isso seleciona apenas os dois detalhes de moldagem de requisição em que eles diferem: `ollama` recebe `options.num_ctx`, e `vllm` recebe `chat_template_kwargs={"thinking": false}` — sem o qual um servidor vLLM executando um parser de raciocínio roteia toda a resposta estruturada para `message.reasoning`, deixa `message.content` vazio e quebra o parsing de JSON. `openai` não envia nenhum dos dois, já que `num_ctx` não tem equivalente lá. Isso **não** altera de onde vêm o host, modelo, timeout, contexto ou configurações de amostragem — essas são as chaves `OLLAMA_*` acima para todos os três.
- **`LLM_API_KEY`** — A credencial enviada ao backend configurado. Padrão para o literal `ollama`, o placeholder que o próprio servidor do Ollama ignora, então as requisições de uma instalação existente permanecem inalteradas; um valor vazio recai nesse mesmo placeholder porque o SDK da OpenAI recusa `api_key=""`. Defina para o valor real se o servidor exigir um — um servidor vLLM iniciado com `--api-key` retorna 401 caso contrário.
- Certifique-se de que o Ollama está em execução e o modelo foi baixado (`ollama pull qwen3:4b-instruct`) antes de usar o LLM Attack — o hate_crack não baixa mais modelos ausentes automaticamente.

O ataque oferece três modos de geração:

1. **Target info** — empresa / setor / localização / empresa controladora; o modelo deriva candidatos a partir desses detalhes.

   Depois que você digita o nome da empresa, o hate_crack pergunta ao mesmo modelo local o que ele já sabe sobre essa organização e pré-preenche os prompts **Industry**, **Location** e **Parent Company** com as respostas, mostradas entre parênteses:

   ```
   Company name: Acme Rail Services

   [!] The values in parentheses below are the local model's GUESSES, not verified OSINT.
       Press Enter to accept, or type your own value to override.
   Industry (freight rail maintenance):
   Location (Omaha, Nebraska):
   Parent company / acquired by:
   ```

   Pressione Enter para aceitar uma sugestão ou digite por cima dela. Esses valores são a recordação do modelo, **não OSINT** — trate-os como um ponto de partida, não como inteligência sobre o cliente. A consulta usa apenas o servidor Ollama local, portanto o nome do cliente nunca sai do host; não há chamadas à web ou a APIs de terceiros. Se o modelo não reconhecer a organização (o caso comum para clientes pequenos), ele não retorna nada e você obtém prompts em branco simples:

   ```
   Company name: Acme Rail Services
   Industry:
   Location:
   Parent company / acquired by:
   ```

   Uma falha de pesquisa — timeout, Ollama não está em execução, resposta vazia — nunca bloqueia o ataque; apenas recorre a prompts em branco. Defina `ollamaAutoResearch` como `false` para ignorar completamente a pesquisa.
2. **Wordlist** — deriva basewords a partir de uma wordlist de amostra.
3. **Cracked passwords** — alimenta os plaintexts já recuperados nesta sessão (`<hashfile>.out`) de volta ao modelo para que este possa inferir as convenções de passwords da própria organização alvo (basewords, estações, anos, sufixos, leetspeak) e gerar *novos* candidatos no mesmo estilo. Esta opção só é listada depois de pelo menos um hash ter sido crackado; o ficheiro inteiro é analisado estatisticamente exatamente como no modo Wordlist (ver `ollamaMaxSampleLines` acima).

#### Configuração do PCFG

O PCFG Attack (opção 20) e o PRINCE-LING Attack (opção 21) usam o submódulo `pcfg_cracker`. Configure-os em `config.json`:

```json
{
  "pcfgRuleset": "DEFAULT",
  "pcfgMaxCandidates": 50000000,
  "pcfgPrinceLingMaxCandidates": 10000000
}
```

- **`pcfgRuleset`** — Nome da gramática treinada a usar (padrão: `DEFAULT`), resolvido para `pcfg_cracker/Rules/<name>/`. Treine a sua própria com o `trainer.py` do pcfg_cracker e defina isto como o nome do conjunto de regras.
- **`pcfgMaxCandidates`** — Número máximo de candidatos que o `pcfg_guesser.py` emite para o ataque PCFG (padrão: `50000000`).
- **`pcfgPrinceLingMaxCandidates`** — Número máximo de palavras base que o `prince_ling.py` escreve na lista de palavras base PRINCE em cache (padrão: `10000000`).

### Kernels otimizados (`optimizedKernelAttacks`)

A flag `-O` do hashcat seleciona kernels otimizados, que são substancialmente mais rápidos
mas limitam o comprimento dos candidatos (cerca de 31 caracteres, menos para alguns modos) e
ignoram silenciosamente tudo o que seja mais longo. `optimizedKernelAttacks` em `config.json` lista
os ataques que correm com `-O`; omita um ataque da lista para o executar com
kernels de comprimento total. A lista em `config.json.example` corresponde à predefinição
incorporada que se aplica quando não existe nenhum `config.json`.

Quatro ataques respeitam a definição mas **não** são otimizados por predefinição, porque
fornecem candidatos que podem exceder o limite de `-O` — adicione-os à lista para
aderir:

- `hcatNgramX`, `hcatOllama`, `hcatOmen`, `hcatLMtoNT`

Para desativar `-O` em todo o lado numa única execução sem editar a configuração, passe
`--no-optimized-kernel` (forma curta `--no-optimize`). Isto substitui a lista para
todos os ataques e também remove um `-O` escrito em `hcatTuning`, que de outra forma
chegaria ao hashcat independentemente da lista.

Os nomes são correspondidos exatamente, e uma entrada não reconhecida é reportada no arranque
em vez de ignorada. Note que os ataques que delegam noutro ataque são
controlados pelo ataque no qual delegam, não pelo seu próprio nome: PRINCE-LING
segue `hcatPrince`, enquanto Spoonman, Rosetta e os modos de regras de padrão LLM
seguem `hcatQuickDictionary`.

### Rastreamento de cobertura de ataques (`coverage_enabled`)

Ao longo de um engagement longo, o mesmo ficheiro de hashes é atacado em muitas sessões com
um conjunto rotativo de listas de palavras, ficheiros de regras e listas de máscaras, e é fácil queimar
horas a repetir terreno que já cobriu — especialmente porque a mesma linha de regra
existe em mais do que um ficheiro de regras. O hate_crack regista o que já
executou contra cada ficheiro de hashes e oferece-se para saltar a sobreposição.

A cobertura é registada **por entrada, não por ficheiro**: linhas de regras individuais e
linhas individuais de `.hcmask`, cada uma emparelhada com a lista de palavras contra a qual foi executada. É
isso que lhe permite reconhecer que um ficheiro de regras personalizado que executa hoje repete 40 das
regras que o `best64.rule` já cobriu na semana passada, e é também por isso que uma regra só
está "coberta" para a lista de palavras específica com que foi tentada — as mesmas regras sobre
um corpus diferente tentam candidatos completamente diferentes.

O ficheiro de hashes é identificado por um sha256 do seu conteúdo, pelo que a cobertura sobrevive
à renomeação ou movimentação entre sessões. As listas de palavras são identificadas da mesma forma,
com o digest memorizado em função do tamanho e da mtime, para que um corpus de vários gigabytes seja
hashed uma vez em vez de em cada ataque.

Só é solicitado quando há genuinamente algo a saltar:

```
[*] Coverage: 40 of 45 rules in this Dictionary have already been run against this hash file.
[?] Skip them and run only the 5 new rules? [Y/n]:
```

Responda `Y` e o hate_crack cria um arquivo de regras temporário contendo apenas as entradas não testadas; responda `n` para executar tudo mesmo assim. Se *todas* as entradas forem repetidas, você será questionado se deseja pular o ataque por completo, então reexecutar deliberadamente uma área já coberta nunca exige reiniciar a ferramenta.

Ataques que nunca são filtrados ainda são registrados como executados, o que permite responder "eu já executei o PRINCE contra este alvo?".

Um ataque que seleciona vários arquivos de regras ao mesmo tempo (Quick Crack, Loopback) faz a pergunta de pular **uma vez para todo o lote, antecipadamente**, antes de qualquer invocação do hashcat. Essa pergunta é deliberadamente barata — ela não lê nem calcula hash de nenhum dos arquivos de regras selecionados, já que um lote YOLO pode chegar a milhões de linhas e você não deveria esperar por isso para responder um sim/não. Ela pergunta ao armazenamento apenas se este ataque já foi executado contra este arquivo de hash **com uma destas wordlists**; o diff por entrada ainda acontece de forma preguiçosa, um arquivo de regras por vez, e decide o que realmente será pulado. Assim, um corpus novo nunca é sinalizado, mesmo quando as regras sobre ele já foram todas executadas contra um diferente.

Três limites deliberados:

- **A cobertura só é registrada quando o hashcat esgota o keyspace** (exit 1). Um ctrl-C ou um erro não registra nada, e exit 0 também não — isso significa que todos os hashes foram quebrados, o que o hashcat reporta *sem* terminar o keyspace, e no caso degenerado de "todos os hashes encontrados como entradas do potfile" sem tentar um único candidato. O sub-registro custa apenas uma execução redundante depois.
- **Geradores dinâmicos de candidatos nunca são filtrados.** PRINCE, PCFG, OMEN, força bruta de Markov e os modos LLM não têm um conjunto fixo para comparar, então são registrados como executados e, fora isso, deixados em paz. Arquivos de regras encadeados (`-r a -r b`) são rastreados como uma única unidade em vez de por entrada, porque o hashcat aplica o *produto cartesiano* dos dois arquivos e descartar uma linha individual removeria silenciosamente todas as combinações das quais ela participou.
- **Execuções com `--loopback` são registradas mas nunca filtradas.** O hashcat realimenta textos simples recém-quebrados como candidatos *extras*, então uma execução dessas tenta a wordlist e o conjunto de regras completos mais tudo o que aqueles textos simples reciclados alcançarem. Isso torna as duas direções assimétricas: registrá-la é correto, então uma execução ordinária posterior da mesma wordlist e regras é corretamente reconhecida como repetição, mas uma segunda execução de loopback tem mais quebras para reciclar e nunca é pulada.

Defina `coverage_enabled` como `false` em `config.json` para desativar isso, ou passe `--no-coverage` para uma única execução — que nem consulta nem atualiza o armazenamento.

#### Inspecionando e redefinindo a cobertura

A opção **85 — Attack Coverage** do menu principal mostra o que foi executado contra o arquivo de hash carregado, seu histórico de execuções, e pode limpá-lo. As mesmas três ações são scriptáveis:

```bash
# What has already been run against this hash file?
hate_crack coverage status --hashfile hashes.txt

# Every attack that has run against it, oldest first
hate_crack coverage history --hashfile hashes.txt

# Start over for this hash file only (prompts unless --yes)
hate_crack coverage forget --hashfile hashes.txt --yes
```

O arquivo de hash é identificado pelo conteúdo, portanto estes funcionam independentemente de onde ele tenha sido movido desde então. `forget` afeta apenas aquele alvo — o armazenamento fica em `~/.hate_crack/coverage/attack_coverage.sqlite3`, e excluir o arquivo redefine a cobertura para *todos* os alvos.

#### Execuções com script

Um ataque com script que a cobertura ignora completamente ainda sai com `0` por padrão, portanto habilitar a cobertura não pode começar a falhar um harness existente. Passe `--exit-code-on-skip` para obter o código de saída **3** em vez disso quando nada foi iniciado:

```bash
hate_crack --exit-code-on-skip hashes.txt dict
# 0 = ran, 1 = bad input, 2 = unknown command, 3 = everything was already covered
```

Exit 3 significa que *nada* foi executado. Uma passagem que foi parcialmente filtrada — algumas entradas ignoradas, algumas tentadas — ainda retorna `0`, porque o ataque de fato realizou trabalho.

### Suporte ao brain do hashcat (`brain_enabled`)

O próprio hashcat inclui um "brain" — um pequeno servidor para o qual uma instância do hashcat em execução transmite senhas candidatas, de modo que uma segunda execução contra o mesmo alvo possa pular candidatos que a primeira já tentou. O hate_crack o aciona automaticamente, sem exigir nenhum passo no menu: sempre que está prestes a lançar um ataque contra um modo de hash que o hashcat reporta como lento (bcrypt, scrypt e outros modos com suporte a KDF, onde o próprio hash é o gargalo em vez da geração de candidatos), ele inicia ou reutiliza um servidor brain local e adiciona as flags `--brain-*` à invocação do hashcat para você. Um modo rápido é deixado em paz, a menos que seu número de modo esteja listado em `brain_modes_force`, e um modo listado em `brain_modes_exclude` nunca aciona o brain, independentemente do veredito do próprio hashcat — exclude sempre vence.

**Brain não é a mesma coisa que cobertura de ataque, e os dois são complementares em vez de redundantes.** A cobertura (acima) desduplica no nível de regras inteiras, linhas de máscara e wordlists — ela decide o que lançar em primeiro lugar, antes mesmo de o hashcat ser executado. O brain desduplica no nível de senhas candidatas individuais, e o faz por meio de um servidor persistente que sobrevive a qualquer invocação individual do hashcat, de modo que captura sobreposições que a cobertura não consegue ver: um candidato alcançável por meio de duas regras diferentes ou duas wordlists diferentes dentro da mesma execução e — como demonstra a ida e volta em `tests/e2e/test_brain_e2e.py` — os mesmos candidatos reenviados em uma segunda execução separada do hashcat contra o mesmo alvo. Ambos podem ser habilitados ao mesmo tempo sem conflito.

Sete chaves em `config.json` o controlam, todas sob o prefixo `brain_*`: `brain_enabled` (chave mestra, ativada por padrão), `brain_host` (vazio significa que o hate_crack gerencia um servidor local em loopback; um valor significa conectar-se apenas a esse host — o hate_crack nunca gera um servidor que não foi instruído a gerenciar), `brain_port` (padrão `6863`), `brain_client_features` (`1` senhas com hash, `2` posições de ataque, `3` ambos — `3` desduplica mais, mas custa ao servidor aproximadamente 12 bytes de RAM por candidato visto), `brain_server_timer` (configuração do próprio hashcat para a frequência com que o servidor grava seu dump `.ldmp`/`.admp` em disco, mínimo de 60 segundos, padrão `300`) e `brain_modes_force` / `brain_modes_exclude` (números de modo de hash separados por vírgula que substituem o veredito lento/rápido do próprio hashcat, com exclude tendo prioridade).

**O servidor gerado automaticamente não tem nenhum tempo limite de inatividade.** `brain_server_timer` não controla por quanto tempo ele permanece ativo — nada controla; ele é executado durante toda a vida do processo que o gerou (ou até que `shutdown()`/`atexit` o pare) e é reutilizado em todos os ataques da sessão. No padrão de `300`, isso significa uma gravação de dump em `~/.hate_crack/brain/` a cada cinco minutos enquanto o hate_crack estiver em execução.

Uma oitava chave, `BRAIN_PASSWORD`, fica em `.env` em vez de `config.json` porque é um segredo compartilhado, não porque o brain seja uma integração de terceiros — ela é usada apenas ao conectar-se a um servidor brain remoto que você já executa; o servidor local gerado automaticamente gera sua própria senha aleatória por sessão e não precisa de configuração.

**A senha do brain é visível para o `ps` durante toda a vida da execução do hashcat,** porque o hashcat só a aceita como argumento de linha de comando — não há forma de variável de ambiente. Para o servidor local gerado automaticamente, esta é uma janela pequena: a senha é aleatória e restrita a essa única sessão, então outro usuário local só pode vê-la enquanto um ataque estiver realmente em execução, e ela é inútil quando a sessão termina. A senha de um servidor brain remoto compartilhado não tem tal mitigação — é o mesmo valor em todas as invocações, visível para qualquer outro usuário local na máquina enquanto qualquer execução do hate_crack contra esse servidor estiver em andamento. Trate-a de acordo em hardware compartilhado ou multi-inquilino.

Passe `--no-brain` para desabilitar o brain em uma única execução, independentemente de `brain_enabled`, ou defina `brain_enabled` como `false` em `config.json` para desativá-lo em todos os lugares.

**O brain mantém estado em `~/.hate_crack/brain/`** — um pequeno cache `slow_modes.json` do veredito lento/rápido do próprio hashcat por versão do hashcat, além, para o servidor gerado automaticamente, de seus arquivos de dump `.ldmp`/`.admp`. Esses dumps são material derivado de candidatos: eles permitem que um servidor novo retome sabendo o que já foi tentado contra um alvo, o que, em um engajamento, significa dados derivados do cliente acumulando-se no diretório home do operador enquanto o brain tiver sido executado ali. Assim como com o armazenamento de cobertura acima, excluir o diretório reinicia o brain — um candidato anteriormente rejeitado deixa de ser lembrado, ao custo de perder a desduplicação que aquele dump representava. Se o brain parecer estar pulando trabalho que não deveria (um dump obsoleto de uma execução anterior com escopo diferente), esta é a solução.

**Excluir `~/.hate_crack/brain/` não limpa um servidor órfão.** O servidor gerado automaticamente é executado em sua própria sessão (`start_new_session=True`) para que sobreviva a um terminal fechado ou a um SIGHUP — apenas um kill explícito, ou o processo que o gerou saindo de forma limpa e executando seu manipulador `atexit`, o interrompe. Um órfão continua ocupando a porta de loopback. Com o `BRAIN_PASSWORD` vazio padrão, você notará isso como `"[!] ... no brain server could be reached; running without candidate de-duplication"` em cada ataque em modo lento: a senha do órfão era efêmera e morreu com o processo que a gerou, então o hate_crack se recusa a adotar a porta em que ele está em vez de adivinhar uma senha que não pode ser verificada. Encontre-o e pare-o com:

```bash
pgrep -f 'hashcat --brain-server'
kill <pid>
```

após o que o próximo ataque gera um novo servidor, como de costume.

### Notificações (opção de menu 82)

O hate_crack pode enviar notificações push do Pushover quando os ataques terminam e,
opcionalmente, quando hashes individuais são quebrados. Todos os controles ficam sob
a opção do menu principal `82 — Notifications`:

1. **Toggle Pushover Notifications [ON/OFF]** — interruptor principal. Persiste em `config.json` como `notify_enabled`.
2. **Toggle Per-Crack Notifications [ON/OFF]** — quando ON, um tailer em segundo plano monitora o arquivo `.out` e envia uma notificação por quebra (com agregação de rajada por tick). Persiste em `config.json` como `notify_per_crack_enabled`. Não pode ser ativado enquanto o interruptor principal estiver OFF — ative a opção 1 primeiro.
3. **Send Test Pushover Notification** — dispara um push pré-definido para que você possa confirmar que seu par token/usuário do Pushover funciona. Funciona mesmo quando o interruptor principal está OFF.

As credenciais ficam em `.env`; os demais ajustes de configuração são apenas no arquivo `config.json`:

- `NOTIFY_PUSHOVER_TOKEN`, `NOTIFY_PUSHOVER_USER` (em `.env`) — necessários para que qualquer push seja disparado. Nada no menu grava esses valores; edite o `.env` você mesmo.
- `notify_attack_allowlist` — nomes de ataques que consentem automaticamente sem o prompt `[y/N/always]`. Preenchido automaticamente quando você responde `always`.
- `notify_suppress_in_orchestrators` (padrão `true`) — silencia os ataques individuais encadeados pelo Extensive Crack, que dispara um único resumo. Defina como `false` para receber uma notificação por ataque encadeado. Outras entradas do menu que executam várias passagens (por exemplo, Quick Crack com múltiplas cadeias de regras) não são orquestradores e sempre notificam por passagem.
- `notify_max_cracks_per_burst` (padrão `5`), `notify_poll_interval_seconds` (padrão `5.0`) — ajuste do tailer por quebra. Consulte `hate_crack/notify/tailer.py` para a lógica de agregação de rajada.

### Ferramentas de Wordlist (opção de menu 80)

O submenu Wordlist Tools fornece utilitários de pré-processamento de wordlist com suporte dos binários hashcat-utils, além de downloads de wordlists do Hashmob.net e Weakpass. Acesse pela opção **80** no menu principal.

| Opção | Binário | O que faz |
|--------|--------|--------------|
| 1 | `len.bin` | Filtrar por comprimento - manter apenas palavras entre um comprimento mínimo e máximo |
| 2 | `req-include.bin` | Exigir classes de caracteres - manter apenas palavras que contenham todos os tipos de caracteres exigidos |
| 3 | `req-exclude.bin` | Excluir classes de caracteres - remover palavras que contenham qualquer tipo de caractere excluído |
| 4 | `cutb.bin` | Extrair substring - cortar um intervalo de bytes de cada palavra |
| 5 | `splitlen.bin` | Dividir por comprimento - criar arquivos separados por comprimento de palavra (arquivos nomeados `01`-`64` em um diretório de saída) |
| 6 | `rli.bin` / `rli2.bin` | Subtrair palavras - remover entradas que aparecem em um ou mais outros arquivos |
| 7 | `gate.bin` | Fragmentar - extrair cada N-ésima palavra para quebra distribuída em várias máquinas |
| 8 | - | Otimizar wordlists - deduplicar e dividir em arquivos por comprimento no diretório de wordlists otimizadas |
| 9 | - | Baixar wordlists do Hashmob.net |
| 10 | - | Baixar wordlists do Weakpass (via BitTorrent) |

**Bits de máscara de classe de caracteres** (usados pelas opções 2 e 3): `1`=minúscula, `2`=maiúscula, `4`=dígito, `8`=símbolo, `16`=outro. Some os valores: `7` = minúscula+maiúscula+dígito.

**Como o sharding deve ser usado**: o sharding divide uma wordlist em N partes iguais e não sobrepostas para que o trabalho possa ser distribuído entre várias máquinas ou GPUs. Cada parte é *intercalada* (cada N-ésima linha), então cada shard é uma amostra representativa da lista inteira em vez de um bloco contíguo de início/fim — nenhum nó fica preso quebrando apenas a cauda de baixa probabilidade.

Execute a opção 7 uma vez, forneça uma wordlist de entrada, um caminho base de saída e um número de shards (N). Ela grava todas as N partes em uma única passagem, nomeadas com números de parte preenchidos com zeros (`base.001`, `base.002`, … até `base.00N`). Copie uma parte para cada nó e aponte a execução do hashcat desse nó para ela. Em um sistema com uma única GPU, o sharding não oferece ganho de velocidade, mas uma única parte ainda é uma amostra rápida e representativa para uma passagem de triagem antes de se comprometer com a lista completa.

#### Verificações Automáticas de Atualização

O hate_crack pode verificar automaticamente no GitHub por versões mais recentes na inicialização. Esse recurso é controlado pela opção de configuração `check_for_updates`:

```json
{
  "check_for_updates": true
}
```

- **`check_for_updates`** — Ativa verificações automáticas de versão na inicialização (padrão: `true`).
- Quando ativado, o hate_crack obtém as informações da versão mais recente do GitHub e exibe um aviso se houver uma atualização disponível.
- A verificação é executada de forma assíncrona e não bloqueia a inicialização. Erros de rede são ignorados silenciosamente.

##### Canais de Atualização

| Canal | Flag | Origem | O que você obtém |
|---------|------|--------|--------------|
| Release | `--update` | `main` | A versão lançada mais recente. Este é o padrão e o que a verificação de inicialização oferece. |
| Nightly | `--nightly` | `nightly-dev` | Trabalho que passou pela CI mas ainda não foi lançado. |

As versões seguem o semver comum, com o incremento derivado do que está realmente no
lote. O segundo componente muda **apenas para funcionalidades**: um ciclo contendo
qualquer commit `feat` está caminhando para `X.(Y+1).0`, e um ciclo apenas de correções,
documentação e tarefas está caminhando para `X.Y.(Z+1)`.

`nightly-dev` marca release candidates para a versão para a qual o lote está caminhando
— `v2.20.1rc1`, `v2.20.1rc2`, … — e o merge para `main` promove esse mesmo alvo à sua versão final. Os candidatos são pré-lançamentos PEP 440 reais, então eles se ordenam corretamente em ambas as extremidades:

    2.20.0  <  2.20.1rc1  <  2.20.1rc2  <  2.20.1  <  2.21.0rc1  <  2.21.0

O alvo pode mudar no meio do ciclo: o primeiro `feat` a entrar o move de
`X.Y.(Z+1)` para `X.(Y+1).0`, e a numeração dos candidatos reinicia para o novo alvo.
O número sempre nomeia o que o lote enviaria hoje.

O componente principal nunca é incrementado automaticamente — um assunto com `!` ou um
rodapé `BREAKING CHANGE:` conta como uma funcionalidade, porque um major automático está a uma
linha de assunto digitada errada de distância de um lançamento publicado irreversível. Um major é um
ato humano explícito: marque e faça push manualmente.

A política fica em `tools/next_version.py`, compartilhada por ambos os fluxos de trabalho de marcação e
testada em unidade em `tests/test_next_version.py`.

A verificação de inicialização só oferece releases, porque builds nightly não publicam nenhum
release no GitHub e a verificação lê o endpoint "latest release" do GitHub — então
ativar `check_for_updates` nunca vai te levar para um nightly. Duas coisas mantêm
os canais separados agora: isso, e o fato de que um candidato é um pré-lançamento PEP 440 genuíno, então uma ferramenta que classifica números de versão brutos também o trata como mais antigo do que o release em que ele se torna.

Qualquer uma das flags primeiro muda seu checkout para o branch correspondente (e
se recusa a fazê-lo se você tiver alterações não commitadas). Se você estiver executando um nightly
e quiser voltar para o código lançado, `--update` te move de volta para `main`.

#### Mesclagem Automática de Hashes Encontrados (Apenas Download Left)

Ao baixar hashes left (hashes não quebrados), o hate_crack automaticamente:
1. Tenta baixar quaisquer hashes encontrados (quebrados) do Hashview como uma operação auxiliar
2. Mescla os hashes encontrados com arquivos `.out` locais (por exemplo, `left_1_123.txt.out` ou `left_1_123.nt.txt.out` para o formato pwdump)
3. Remove entradas duplicadas
4. Limpa arquivos temporários divididos após a mesclagem

Isso garante que seus resultados locais de quebra permaneçam sincronizados com o banco de dados centralizado do Hashview ao trabalhar com hashes não quebrados.

**Nota:** A opção download-found baixa hashes já quebrados separadamente para fins de referência e não realiza nenhuma mesclagem nem solicita quebra.

O <hash_type> é obtido executando `hashcat --help`

Exemplos de Hashes: http://hashcat.net/wiki/doku.php?id=example_hashes


```
$ hashcat --help |grep -i ntlm
   5500 | NetNTLMv1                                        | Network protocols
   5500 | NetNTLMv1 + ESS                                  | Network protocols
   5600 | NetNTLMv2                                        | Network protocols
   1000 | NTLM                                             | Operating-Systems
```

```
$ ./hate_crack.py <hash file> 1000

  ___ ___         __             _________                       __
 /   |   \_____ _/  |_  ____     \_   ___ \____________    ____ |  | __
/    ~    \__  \\   __\/ __ \    /    \  \/\_  __ \__  \ _/ ___\|  |/ /
\    Y    // __ \|  | \  ___/    \     \____|  | \// __ \\  \___|    <
 \___|_  /(____  /__|  \___  >____\______  /|__|  (____  /\___  >__|_ \
       \/      \/          \/_____/      \/            \/     \/     \/
                          Version 2.0
```

## Testes

A suíte de testes é majoritariamente offline e utiliza mocks/fixtures. Verificações de rede ao vivo e verificações de dependências do sistema são opcionais via variáveis de ambiente.

### Executando Testes Localmente

```bash
# Run all tests
uv run pytest -v

# Run specific test
uv run pytest tests/test_hashview.py -v
```

Você também pode executar a suíte completa com `make test`.

### Testes ao Vivo (Opt-In)

Defina qualquer um dos seguintes para habilitar verificações ao vivo:

- `HASHMOB_TEST_REAL=1` — verificação de conectividade/menu CLI do Hashmob ao vivo
- `HASHVIEW_TEST_REAL=1` — verificação do menu CLI do Hashview ao vivo
- `WEAKPASS_TEST_REAL=1` — verificação do menu CLI do Weakpass ao vivo
- `HATE_CRACK_REQUIRE_DEPS=1` — falha se `7z`, `transmission-daemon` ou `transmission-remote` estiverem ausentes

### Teste de Upload do Hashview ao Vivo

O teste de upload do Hashview ao vivo é ignorado por padrão. Para executá-lo, defina a
variável de ambiente e forneça credenciais válidas em `.env`:

```bash
HATE_CRACK_RUN_LIVE_TESTS=1 uv run pytest tests/test_upload_cracked_hashes.py -v
```

### Testes Live do Hashview Contra uma Stack Docker Local

Em vez de apontar os testes live para um servidor Hashview remoto, você pode fazer
a suíte iniciar uma stack Docker local do [Hashview](https://github.com/hashview/hashview),
populá-la, executar os testes live contra ela e desmontá-la. Defina
`HASHVIEW_TEST_LOCAL=1` e aponte `HASHVIEW_REPO` para um checkout do Hashview:

```bash
HASHVIEW_TEST_LOCAL=1 HASHVIEW_REPO=~/projects/hashview \
  HATE_CRACK_SKIP_INIT=1 uv run pytest tests/test_hashview_cli_subcommands_subprocess.py -v
```

Isso inicia o `docker compose` no repositório Hashview, semeia uma chave de API de administrador,
um cliente, um hashfile e dados de "tarefa efetiva" quebrados, depois exporta as
variáveis de ambiente `HASHVIEW_*` que os testes leem. Variáveis de ambiente úteis:

- `HASHVIEW_TEST_LOCAL=1` — habilita a stack local (no-op caso contrário)
- `HASHVIEW_REPO=<path>` — checkout do Hashview (padrão `~/projects/hashview`)
- `HASHVIEW_KEEP=1` — deixa os containers em execução após a sessão (re-execuções mais rápidas)
- `HASHVIEW_LOCAL_PORT=5000` — porta do host na qual a aplicação é publicada

A CLI hate_crack respeita as variáveis de ambiente `HASHVIEW_URL` / `HASHVIEW_API_KEY`
(sobrescrevendo o `.env` onde essas duas chaves residem), o que permite que a
suíte aponte a CLI para a stack local sem editar sua configuração persistida.

### Testes de Instalação End-to-End (Local + Docker)

Instalação local da ferramenta uv + execução de script (usa um HOME temporário):

```bash
HATE_CRACK_RUN_E2E=1 uv run pytest tests/test_e2e_local_install.py -v
```

Instalação/execução ponta a ponta baseada em Docker (em cache via `Dockerfile.test`):

```bash
HATE_CRACK_RUN_DOCKER_TESTS=1 uv run pytest tests/test_docker_script_install.py -v
```

O teste E2E do Docker também baixa um pequeno subconjunto do rockyou e executa um crack básico com hashcat para validar a integração com ferramentas externas.

Teste ponta a ponta da VM Lima (apenas macOS):

Pré-requisitos: [Lima](https://lima-vm.io/) e `rsync` devem estar instalados.

```bash
brew install lima
```

A VM de teste é provisionada automaticamente com todas as dependências Linux (hashcat, build-essential, curl, git, gzip, p7zip-full, transmission-daemon, ocl-icd-libopencl1, pocl-opencl-icd, uv).

```bash
HATE_CRACK_RUN_LIMA_TESTS=1 uv run pytest tests/test_lima_vm_install.py -v
```

Este teste valida a instalação e a execução dentro de uma VM Linux leve no macOS.

### Estrutura de Testes

- **tests/test_hashview.py**: Suíte de testes abrangente para a classe HashviewAPI com respostas de API simuladas, incluindo:
  - Listagem de clientes e validação de dados
  - Testes de autenticação e autorização
  - Funcionalidade de upload de arquivo de hash
  - Fluxo de trabalho completo de criação de job

Todos os testes usam chamadas de API simuladas, portanto podem ser executados sem conectividade com um servidor Hashview.

-------------------------------------------------------------------

  (1) Quebra Rápida
  (2) Quebra Extensiva pela Metodologia Pure_Hate
  (3) Ataque de Força Bruta
  (4) Ataque de Máscara Top
  (5) Ataque de Impressão Digital
  (6) Ataques Combinadores
  (7) Ataque Híbrido
  (8) Quebra por Força Bruta com Máscara Pathwell Top 100
  (9) Ataque PRINCE
  (10) Metodologia Bandrel
  (11) Ataque Loopback
  (12) Ataque LLM
  (13) Ataque OMEN
  (14) Ataque de Máscara Ad-hoc
  (15) Ataque de Força Bruta Markov
  (16) Ataque N-gram
  (17) Ataque de Permutação
  (18) Ataque de Regras Aleatórias
  (19) Ataque de Passphrase Combipow
  (20) Ataque PCFG
  (21) Ataque PRINCE-LING
  (22) Ataque Spoonman
  (23) Ataque Rosetta
  (24) Força Bruta com Máscaras Corporativas
  (25) Ataque de Máscara Inteligente

  (80) Ferramentas de Wordlist
  (81) Ferramentas de Arquivo de Regras
  (82) Notificações
  (83) Ferramentas de Máscara

  (93) Regenerar .out a partir do arquivo POT
  (94) API Hashview
  (95) Analisar hashes com Pipal
  (96) Exportar Saída para Formato Excel
  (97) Exibir Hashes Quebrados
  (98) Exibir README
  (99) Sair

Selecione uma tarefa:
```

Option `94 — Hashview API` is only listed when `HASHVIEW_API_KEY` is set in `.env`.

The YOLO, Middle, and Thorough Combinator attacks were previously at keys 10-12. They now live in the Combinator Attacks submenu (option 6) along with Combinator3 and CombinatorX.
-------------------------------------------------------------------
#### Quick Crack
Runs a dictionary attack against wordlists in your `hcatOptimizedWordlists` directory (falls back to `hcatWordlists` if not configured) and optionally applies rules. Multiple rules can be selected by comma-separated list, and chains can be created with the '+' symbol. Pressing Enter at the wordlist prompt uses the configured optimized wordlists directory as the default.

Selecting a directory — including that default — expands to the wordlists
directly inside it before hashcat runs. Subdirectories are not searched,
matching hashcat's own behaviour for a directory in the dictionary position, and
dot-files and `.7z`/`.torrent`/`.out` files are skipped, which hashcat would
otherwise try to read. The candidates are the same either way; the expansion is
what lets attack coverage track each wordlist separately, since a directory has
no content fingerprint to key on. If the expansion finds nothing — an empty
directory, or one holding only subdirectories or archives — the attack aborts
rather than launching hashcat with no wordlist, which would put it in stdin
mode and leave it reading the terminal.

```
Quais regra(s) você gostaria de executar?
(1) best64.rule
(2) d3ad0ne.rule
(3) T0XlC.rule
(4) dive.rule
(99) YOLO...executar todas as regras
Digite a lista de regras separadas por vírgula que você gostaria de executar. Para executar regras encadeadas use o símbolo +.
Por exemplo, 1+1 executará best64.rule encadeada duas vezes e 1,2 executará best64.rule e depois d3ad0ne.rule sequencialmente.
Escolha com sabedoria:
```




#### Extensive Pure_Hate Methodology Crack
Runs several attack methods provided by Martin Bos (formerly known as pure_hate):
  * Brute Force Attack (7 characters)
  * Dictionary Attack
    * All wordlists in `hcatWordlists` with `best64.rule`
    * `rockyou.txt` with `d3ad0ne.rule`
    * `rockyou.txt` with `T0XlC.rule`
  * Top Mask Attack (Target Time = 4 Hours)
  * Fingerprint Attack
  * Smart Mask Attack
  * Combinator Attack
  * Hybrid Attack
  * Extra - Just For Good Measure
    - Runs a dictionary attack using `rockyou.txt` with chained `combinator.rule` and `InsidePro-PasswordsPro.rule` rules

#### Brute Force Attack
Brute forces all characters with the choice of a minimum and maximum password length.

#### Top Mask Attack
Uses StatsGen and MaskGen from PACK (https://thesprawl.org/projects/pack/) to perform a top mask attack using passwords already cracked for the current session.
Presents the user a choice of target cracking time to spend (default 4 hours).

#### Fingerprint Attack
https://hashcat.net/wiki/doku.php?id=fingerprint_attack

Runs a fingerprint attack using passwords already cracked for the current session. Expander substring length escalates automatically (7, 14, 21, ... up to the chosen ceiling), and an optional wordlist can be combined against the expanded fragments in addition to self-combination. Set `hcatFingerprintWordlist` in `config.json` to a default wordlist path so the prompt offers it instead of asking for a path every time; leave it as `""` to always ask (or skip).

#### Smart Mask Attack
Looks for literal "skeleton" patterns shared by 3+ already-cracked passwords for the current session -- e.g. a fixed stem like `CrawlingHorse` followed by a run of digits, or `ChangeMe2day` followed by digits and symbols drawn from a consistent charset. Every qualifying pattern runs against the full remaining hash list, so other accounts sharing a stem get swept up even though brute-forcing the stem itself was never tried.

Patterns with a fixed run at either end -- nearly all of them -- are grouped by mask and run as hybrid attacks (`-a 6` when the mask trails the stem, `-a 7` when it leads), with every pattern's literal stem a line in that group's wordlist. Dozens of patterns that vary the same way therefore become one hashcat pass over one wordlist rather than one mask line each. Whatever cannot be grouped that way -- variation at *both* ends, which leaves no fixed run to seed a wordlist with -- falls back to a single `-a 3` mask file, and has its charsets widened (up to `?a`) to compensate, as far as the guardrail below allows.

Prompts once, before the attack starts, for an optional per-pattern candidate-count guardrail (default 50,000,000,000; 0 disables it) that excludes any individual pattern whose keyspace is too large without blocking the rest.

#### Combinator Attack
https://hashcat.net/wiki/doku.php?id=combinator_attack

Runs a combinator attack using the "rockyou.txt" wordlist.

#### Hybrid Attack
https://hashcat.net/wiki/doku.php?id=hybrid_attack

* Runs sixteen hybrid passes per wordlist, cheapest first. Each mask length
  from 1 to 4 is tried appended and then prepended, first over `?s?d` and then
  over `?a`, and a single ctrl-C abandons the whole attack rather than only the
  current pass.
  - Hybrid Wordlist + Mask - ?s?d wordlists/rockyou.txt ?1
  - Hybrid Mask + Wordlist - ?s?d ?1 wordlists/rockyou.txt
  - ... the same for ?1?1, ?1?1?1 and ?1?1?1?1
  - Hybrid Wordlist + Mask - wordlists/rockyou.txt ?a
  - Hybrid Mask + Wordlist - ?a wordlists/rockyou.txt
  - ... the same for ?a?a, ?a?a?a and ?a?a?a?a

  `?a` is every printable character, so the second group is a superset of the
  first plus letters and roughly 24x the work at the longest mask — over
  rockyou.txt those passes alone are ~1.2e15 candidates, about ten hours for
  NTLM on hardware doing 32 GH/s. That is why the cheap `?s?d` group runs first
  and why the attack as a whole is time-bounded:

  - `hcatHybridMaxRuntime` in `config.json`, in seconds, default `3600`, is the
    time the **whole attack** may spend — not the time one pass may spend. All
    sixteen passes share one deadline, and each is handed whatever is left of it
    as hashcat's `--runtime`. Any pass the budget does not reach is reported
    rather than skipped quietly. Set it to `0` for no limit, which runs every
    pass to exhaustion.

  Within each group the order is by mask length across every wordlist rather
  than all lengths of one wordlist and then the next, so a budget that runs out
  has still given every wordlist its cheap passes.

  Each pass declares what it covers to the attack-coverage store, so a repeat
  hybrid against the same hash file offers to skip the passes already run. A
  pass that runs out of budget is not recorded, so it will be retried.
  Wordlist entries may be glob patterns or directories; both are expanded
  before hashcat runs, a directory into the wordlists directly inside it.
  Subdirectories are not searched, matching hashcat's own behaviour, and
  dot-files and `.7z`/`.torrent`/`.out` files are skipped — a Weakpass
  download leaves archives in the wordlists directory and hashcat would
  otherwise try to read them.

#### Pathwell Top 100 Mask Brute Force Crack
Runs a brute force attack using the top 100 masks from KoreLogic:
https://blog.korelogic.com/blog/2014/04/04/pathwell_topologies

#### PRINCE Attack
https://hashcat.net/events/p14-trondheim/prince-attack.pdf

Runs a PRINCE attack using wordlists/rockyou.txt

#### YOLO Combinator Attack
Runs a continuous combinator attack using random wordlists from the configured wordlists directory for the left and right sides.

#### Middle Combinator Attack
https://jeffh.net/2018/04/26/combinator_methods/

Runs a modified combinator attack adding a middle character mask:
wordlists/rockyou.txt + masks + worklists/rockyou.txt

Where the masks are some of the most commonly used separator characters:
2 4 <space> - _ , + . &

#### Thorough Combinator Attack
https://jeffh.net/2018/04/26/combinator_methods/

* Runs many rounds of different combinator attacks with the rockyou list.
  - Standard Combinator attack: rockyou.txt + rockyou.txt
  - Middle Combinator attack: rockyou.txt + ?n + rockyou.txt
  - Middle Combinator attack: rockyou.txt + ?s + rockyou.txt
  - End Combinator attack: rockyou.txt + rockyou.txt + ?n
  - End Combinator attack: rockyou.txt + rockyou.txt + ?s
  - Hybrid middle/end attack: rockyou.txt + ?n + rockyou.txt + ?n
  - Hybrid middle/end attack: rockyou.txt + ?s + rockyou.txt + ?s


#### Bandrel Methodology

Prompts for comma-separated names and creates a pseudo hybrid attack by capitalizing the first letter and adding up to six additional characters at the end. Each word is limited to a total of five minutes.

  - Built-in common words (seasons, months) included as a customizable `config.json` entry (`bandrel_common_basedwords`)
  - The default five-minute time limit is customizable via `bandrelmaxruntime` in `config.json`

#### Loopback Attack
https://hashcat.net/wiki/doku.php?id=loopback_attack

Uses hashcat's loopback mode to feed cracked passwords from the current session back into the attack pipeline with rules applied. This generates new password candidates based on variations of already-cracked passwords, which is particularly effective for finding related passwords that follow similar patterns.

* Prompts for rule selection to apply to the loopback candidates
* Uses an empty wordlist with the --loopback flag to process previously cracked passwords
* Automatically downloads Hashmob rules if no rules are available locally

#### LLM Attack
Uses a local LLM — Ollama by default, or a vLLM / OpenAI-compatible server via `LLM_BACKEND` — to generate password candidates for a capture-the-flag scenario. Prompts for the fake company name, industry, location, and parent company / acquisition history, then sends these details to the configured LLM model to produce likely password candidates using industry terms and company name permutations. The generated candidates are fed into a hashcat wordlist+rules attack.

* Requires a running server at `OLLAMA_HOST` (default: `http://localhost:11434`, Ollama's port; override in `.env` or the environment) already serving the model — hate_crack does not auto-pull
* Candidate generation uses structured (JSON) output via Atomic Agents, so pick a model with good schema adherence (default: `qwen3:4b-instruct`)
* Configurable backend, model, context window, request timeout, and sample size via `.env` (see [LLM Configuration](#llm-configuration))
* Prompts for target company name, industry, location, and parent company / acquisition history. The industry, location, and parent company prompts are pre-filled with the local model's guesses about the named organization (editable, and clearly labelled as guesses rather than verified OSINT); disable with `ollamaAutoResearch: false`
* Alternatively derives basewords from a sample **wordlist**, or from the **cracked passwords** of the current session (`<hashfile>.out`) so the model mirrors the target organization's own password conventions and produces new candidates in that style (only offered once something has been cracked)
* A live spinner with an elapsed-seconds counter runs during generation, and requests are bounded by `ollamaTimeout` so a model stuck loading into VRAM reports a timeout instead of hanging

**Pattern rules mode** (option 4 in the LLM submenu) takes the same shape as the [Spoonman Attack](#spoonman-attack) — a baseword list run through a rule file, both derived from one corpus — but infers each side with the model instead of extracting it. Spoonman is exact and therefore bounded: its basewords all appear in the corpus and its rules only reproduce transformations the corpus already shows. This asks the model to generalize on both axes, so it can name the *word families* behind a sample (the company and its products, site names, local sports teams, seasons, mascots) and write decorations the corpus does not contain.

* Pattern source is either the current session's cracked passwords (offered first, and only once something has been cracked, since those reveal the target's real conventions) or a sample wordlist
* **You are not asked to pick a rule file.** The model writes one, from the same corpus statistics — a stock rule file encodes the internet's habits, and the point of spending a model round trip is to encode *this* organization's
* Basewords are normalized to lowercase letters only, discarding anything under 3 characters, so the generated rules supply case, digits, and punctuation exactly once
* Generated rules are validated before hashcat sees them, and anything using an op hashcat does not have, a position argument outside `0-9A-Z`, more than 31 functions, or a stray comment or non-ASCII character is discarded. hashcat drops an invalid rule *silently* when valid rules share the file, so an unscreened line would become missing coverage rather than an error. The op table was established by testing hashcat itself, not from its rule documentation, which lists ops hashcat will not actually run
* Local-model yield varies a lot run to run, so a thin answer is asked again once and the two rounds are merged — a handful of rules would waste the pass they are spent on
* If no rule survives validation the basewords still run, unmutated, rather than throwing away the expensive half of the run
* Output lands in `<hashfile>.llm_patterns/` as `basewords.txt` and `rules.rule` — per-run scratch, laid out like `.spoonman/` and removed on exit

#### OMEN Attack
Uses the Ordered Markov ENumerator (OMEN) to train a statistical password model from a wordlist and generate password candidates. This attack learns patterns from known passwords and generates new candidates based on those patterns.

* Requires OMEN binaries (createNG and enumNG) to be built from the omen submodule
* Interactive menu: use existing model, train new model, or cancel
* Training wordlist picker shows available wordlists from configured directory or accepts a custom path
* Validates all 5 required model files (createConfig, CP/IP/EP/LN.level) before running
* Captures and reports enumNG errors instead of failing silently
* Generates up to a specified number of password candidates (configurable via `omenMaxCandidates`)
* Pipes generated candidates directly into hashcat for cracking
* Model files and metadata are stored in `~/.hate_crack/omen/` for persistence across sessions

#### Combinator Attacks Submenu
Opens an interactive submenu with six combinator attack variants (formerly at menu keys 10-12). Consolidates related attacks for cleaner menu organization:
- Combinator Attack - combines two wordlists
- YOLO Combinator Attack - combines all permutations of multiple wordlists
- Middle Combinator Attack - combines wordlists with an extra word in the middle
- Thorough Combinator Attack - comprehensive combination of wordlists with rules
- Combinator3 Attack - combines exactly 3 wordlists using `combinator3.bin`, generating all `word1+word2+word3` combinations piped to hashcat
- CombinatorX Attack - combines 2-8 wordlists using `combinatorX.bin` with optional `--sepFill` separator character between word segments

#### Ad-hoc Mask Attack
Runs hashcat mask attack (mode 3) with a user-specified custom mask string. Allows fine-grained control over character-set brute forcing.

* Opens with a choice between typing a mask and selecting a mask file
* Prompts for a hashcat mask (e.g., `?u?l?l?l?d?d` for uppercase + lowercase + lowercase + lowercase + digit + digit)
* Supports custom character sets for specialized character combinations: `-1` through `-4` on any hashcat, plus `-5` through `-8` on hashcat 7 and newer. A mask using `?5`–`?8` against an older hashcat is flagged before the run rather than failing inside it; if the version cannot be read, the mask is passed through and hashcat decides
* Only prompts for the custom slots the mask actually references — `?1?3?d` asks about `-1` and `-3` and nothing else, and a mask with no custom tokens is never asked at all. Detection is token-aware, so the escaped `??1` is a literal `?1` and prompts for nothing. A slot left blank is still skipped, with a warning that hashcat will reject a mask whose charset is undefined
* Mask files (`.hcmask`) can be selected with tab completion, defaulting to the bundled `masks/` directory; hashcat runs every mask in the file in order. Because a mask file defines its own charsets inline, the `-1` through `-4` prompts are skipped when one is chosen
* Optionally runs the mask incrementally (`--increment`), trying shorter lengths before the full mask. Answering yes prompts for an increment minimum and maximum; either can be left blank, and leaving both blank increments over the mask's full keyspace with hashcat choosing the bounds. Offered for typed masks and mask files alike
* Useful for targeted brute forcing when you know password structure patterns

#### Markov Brute Force Attack
Generates password candidates using Markov chain statistical models. Similar to OMEN but simpler and faster.

* Checks for existing `.hcstat2` Markov table from previous sessions (with option to reuse, regenerate, or cancel)
* Generates table from training source if needed:
  - Can use cracked passwords from current session (`.out` file) as training data
  - Or select any wordlist from configured directory or custom path
* Interactive menu: choose minimum and maximum password length
* Uses `--increment` flag to test lengths in sequence
* Markov table persists with hash file (filename.out.hcstat2) for fast subsequent runs
* Faster than OMEN for general-purpose brute forcing

#### N-gram Attack
Generates n-gram candidates from a corpus file using `ngramX.bin` from hashcat-utils and pipes them into hashcat.

* Prompts for a corpus file with tab completion, defaulting to the configured wordlist directory
* Prompts for an n-gram group size (default 3)
* Gzip-compressed corpus files are auto-detected and decompressed on the fly
* Useful when you have target-relevant prose (scraped site copy, leaked documents, internal wiki exports) rather than a password list

#### Permutation Attack
Generates all character permutations of each word in a targeted wordlist and pipes them to hashcat via `permute.bin` from hashcat-utils.

* Prompts for a single wordlist file (not a directory)
* Effective against short targeted wordlists where the character set is known but the order is not (company abbreviations, name fragments, known tokens)
* WARNING: Scales as N! per word - an 8-character word produces 40,320 permutations. Only practical for words up to ~8 characters.
* Uses `permute.bin < wordlist | hashcat` pipeline pattern

#### Random Rules Attack
Generates a set of random hashcat mutation rules using `generate-rules.bin`, writes them to a temporary file, then runs hashcat against a chosen wordlist with those rules.

* Prompts for rule count (default 65536)
* Prompts for wordlist path with tab-completion and numbered selection
* Temporary rules file is cleaned up after the run regardless of outcome
* Useful when known rule sets are exhausted - explores random rule-space for additional cracks

#### Combipow Passphrase Attack
Generates all unique non-empty subset combinations from a short wordlist using `combipow.bin` and pipes them into hashcat. Designed for passphrase cracking when you know the pool of words a password was built from.

* Prompts for a wordlist file (max 63 lines - combipow generates up to 2^n-1 combinations)
* Optional space separator (`-s` flag) to insert spaces between words in each combination
* Warns if the wordlist exceeds 20 lines (output volume may be large)
* Aborts with a clear message if the wordlist exceeds 63 lines (hard limit)
* Candidates are piped directly to hashcat stdin

#### PCFG Attack
Uses [pcfg_cracker](https://github.com/lakiw/pcfg_cracker) to generate candidates from a Probabilistic Context-Free Grammar, piping `pcfg_guesser.py` output directly into hashcat's stdin mode. A PCFG models password *structure* (baseword + digits + symbol, capitalization habits, keyboard walks) with learned probabilities, so candidates come out roughly in descending likelihood order.

* Requires the `pcfg_cracker` submodule. Presence is checked at startup and reported non-fatally: if it is missing, the PCFG attacks are simply unavailable. Run `make` to fetch it.
* Uses the trained grammar named by `pcfgRuleset` in `config.json` (default `DEFAULT`), read from `pcfg_cracker/Rules/<name>/`
* Candidate count is capped by `pcfgMaxCandidates` (default 50,000,000)
* hate_crack does not wrap grammar training. To build a grammar from a target-specific password set, run pcfg_cracker's own `trainer.py` and point `pcfgRuleset` at the resulting ruleset name

#### PRINCE-LING Attack
Uses pcfg_cracker's `prince_ling.py` to derive an optimized PRINCE base wordlist from a trained grammar, then hands it to the existing PRINCE attack. PRINCE-LING picks base words the grammar says are actually productive, so the PRINCE combination space is far less wasteful than pointing PRINCE at a generic wordlist.

* Requires the `pcfg_cracker` submodule and a trained ruleset directory, same as the PCFG attack
* The generated wordlist is cached at `<hcatOptimizedWordlists>/pcfg_prince_ling_<ruleset>.txt` and reused across sessions
* Regenerates only when the ruleset directory is newer than the cached wordlist, so retraining a grammar invalidates the cache automatically
* Generation is written to a temporary file and atomically moved into place; a failed or interrupted run cleans up its partial file and leaves any existing cache intact
* Base wordlist size is capped by `pcfgPrinceLingMaxCandidates` (default 10,000,000)

#### Spoonman Attack
Derives a baseword list and a hashcat rule file from a corpus of known plaintext passwords — a previous engagement's cracked output, a leak dump, or any password list — such that the baseword x rule cross product reconstructs the corpus exactly (see the memory bound below for the one case where it does not). Contributed as issue #169 by @Spoonman1091.

Each password is split into its letters-only lowercased core (the baseword) plus a rule that rebuilds the original from it, using `l`/`u`/`c` for casing, `T{p}` toggles, `${x}`/`^{x}` for trailing and leading characters, and `i{p}{x}` for interior ones.

* When the current session already has cracked plaintexts (`<hash file>.out` exists and is non-empty), a picker offers those as the corpus ahead of a free-form path — the target's own recovered passwords derive rules describing that target's actual conventions, which is exactly what you want to fire back at the remaining uncracked hashes. Deriving from `.out` and then cracking the same hash file appends new plaintexts to that same file, growing the corpus for the next run; that is the intended feedback loop, not corruption. Sessions with no cracked output yet see no picker at all — just today's path prompt
* Prompts for the corpus, then for how much of the rule file to run: top 50% coverage (listed first and recommended), top 75%, top 95%, top 99%, or the full set
* Rules are sorted by how many passwords each one rebuilds, so a truncated file keeps the most productive rules. Coverage is extremely long-tailed: on a 98.2M-password sample, 50% coverage needed 4,120 rules while 95% needed 16,119,661 and 100% needed 21,029,696 — the last few percent typically costs orders of magnitude more rules than the first half, which is why the smallest tier is listed first and is usually the right choice
* Output is written beside the hash file in `<hash file>.spoonman/`, alongside the other ephemeral wordlists: `basewords.txt`, `rules.full.rule`, the capped rule files, and `coverage.txt` with per-milestone rule counts. Derivation is skipped on later runs of the same hash file unless the corpus has been modified since, and the directory is removed on exit by the temp-file cleanup
* Derivation is bounded in memory. Both counters would otherwise grow for the whole read with nothing written until the end, so a corpus large enough to exhaust RAM lost the entire pass to an OOM kill and produced no output; a measured run against a 31 GB corpus reached 14.1 GB resident at 11% of the file and was still accelerating. Each counter is now capped at 20 million distinct keys (about 1.6 GB apiece), and the lowest-frequency keys are discarded once it is exceeded. If that happens, the run says so on the console and in `coverage.txt`, the output reconstructs the retained keys rather than 100% of the corpus, and the coverage percentages are relative to those. Corpora below the cap are unaffected
* Passwords that cannot be expressed as a rule are written verbatim as their own baseword with a `:` no-op, so coverage stays complete. This covers two hashcat limits: rule positions cannot address past index 35, and hashcat rejects any rule with more than 31 functions — silently, when valid rules share the file
* A password carrying a literal CR or LF (which arrives hex-wrapped, as `$HEX[...0a]`) cannot go in a baseword at all, because a wordlist line has no escape syntax for one. The break is lifted out into an insert op instead, spelled `\x0a`/`\x0d` in the rule, which hashcat decodes to the byte. When the break sits past addressable index 35 the rule reverses the word first, inserts from the other end, and reverses back. One frame has to hold every break in the password, so what is still skipped is a password with one break outside the first 36 characters *and* another outside the last 36, or one needing more inserts than the 31-function cap leaves room for. Those are counted as `unwritable basewords` in `coverage.txt` and reported, never dropped silently
* The derivation self-checks every password by reconstructing it in-process, and reports any failures rather than reporting success
* Corpus lines may carry a hash in front of the password, as cracked output does. A leading field is dropped only when it has the shape of a hash (a hex digest at a known length, or a crypt-style `$id$` string), so `hash:salt:plain` is handled while a plaintext or wordlist entry containing a colon survives intact. `$HEX[...]` plaintexts are decoded. If most lines look like an uncracked dump rather than cracked output, `coverage.txt` records the count and the attack warns — the derived basewords and rules would otherwise be meaningless without any error being raised

#### Rosetta Attack
Mines hashcat `--debug-mode 5` logs for the basewords and rules that already cracked something, then runs their full cross product. Powered by [HashcatRosetta](https://github.com/bandrel/HashcatRosetta), the same library behind [Analyze Hashcat Rules](#analyze-hashcat-rules-rule-file-tools-option-5).

No setup is needed to feed it: `_add_debug_mode_for_rules` appends `--debug-mode 5 --debug-file` to every rule-based hashcat invocation hate_crack makes, so the logs accumulate in `hcatDebugLogPath` (`~/.hate_crack/hashcat_debug` by default, one file per session) as a side effect of normal use. A mode 5 log records only candidates that cracked a hash, in the form `baseword:rule:candidate:wordlist`, which is what makes both halves known-productive against this target population; the trailing wordlist field also shows which list is earning its keep on a multi-wordlist run. HashcatRosetta parses mode 4 and mode 5 alike, so logs written before the switch are still read.

The value is in the cross product rather than the recorded pairs. A pair present in a log has already cracked its hash and will not crack another, but a rule that worked on one baseword has usually never been tried against the others — so N basewords and M rules yield close to N x M untried candidates.

The menu first asks how to rank rules — choices 1-3 below, plus a fourth, unrelated mode:

* Rules can be ranked by application frequency, by how many distinct basewords each one worked on, or by how many unique candidates each one generated. Frequency is the default; baseword spread is the better choice when the goal is a rule set that generalizes past the specific words it was learned from
* Only after one of those three is picked does hate_crack list the logs found in `hcatDebugLogPath` newest-first with their sizes; pick one, pick all of them (up to 20), or type a path to a log from elsewhere
* Prompts for how many top rules to keep and how many top basewords. Both default to all — a blank answer keeps every winning rule the logs contain, and zero means the same thing. Enter a number to cap either. The keyspace is the product of the two and is printed before hashcat starts
* Output is written beside the hash file in `<hash file>.rosetta/` as `basewords.txt` and `rules.rule`, alongside the other ephemeral wordlists, and the directory is removed on exit by the temp-file cleanup
* Reading stops at 1,000,000 debug lines, since the analyzer needs the whole batch in memory at once. Truncation is reported on the console rather than assumed harmless — logs from a long run routinely exceed this, in which case the newest log is the one worth selecting
* **LLM Mask Attack** (4) - a different mode entirely, and the only one that needs no debug logs. Prompts for a natural-language description of the passwords you expect (length, character patterns, symbols, etc.), sends it to the locally configured Ollama model, writes the returned masks to `<hash file>.hcmask`, and runs a `-a 3` hashcat mask attack against them

#### Corporate Masks Brute Force
Statistical masks (8-14 characters) derived from analysis of 3.2M NTLM hashes cracked on real engagements. Powered by [Corporate_Masks](https://github.com/golem445/Corporate_Masks), these masks encode realistic password patterns from successful penetration tests.

* Prompts for minimum and maximum mask length (default 8-10)
* Longer lengths cost exponentially more keyspace—start with 8-10 for speed, or 8-12 for thoroughness
* Each mask file is run as a separate hashcat invocation in ascending length order
* Gracefully handles missing mask files (skips them) and absent submodule (prints warning and returns)
* Supports optimized kernels (`-O` flag) for faster cracking
* Ctrl-C during one length aborts remaining lengths

#### Wordlist Tools (option 80)
A submenu of wordlist preprocessing utilities using hashcat-utils binaries. All tools read from and write to files on disk. All file and directory path prompts support tab completion.

| Key | Tool | Description |
|-----|------|-------------|
| 1 | Filter by Length | Keep only words between a min and max length (`len.bin`) |
| 2 | Require Char Classes | Keep words that include all char classes in mask (`req-include.bin`). Mask: 1=lower, 2=upper, 4=digit, 8=symbol (additive) |
| 3 | Exclude Char Classes | Remove words containing any char class in mask (`req-exclude.bin`). Same mask encoding |
| 4 | Extract Substring | Cut bytes from each word at a given offset and optional length (`cutb.bin`) |
| 5 | Split by Length | Create per-length files in an output directory (`splitlen.bin`) |
| 6 | Subtract Wordlist | Remove lines from a wordlist that appear in one or more remove files. Mode 1 uses `rli2.bin` (single file); mode 2 uses `rli.bin` (multiple files) |
| 7 | Shard Wordlist | Split a wordlist into N equal, interleaved parts in one run, written as `base.001`…`base.00N` for distributed cracking (`gate.bin`) |
| 8 | Optimize Wordlists | Dedupe and split the selected wordlists into per-length files under an output directory |
| 9 | Download from Hashmob.net | Browse and download wordlists from Hashmob.net into the configured wordlist directory |
| 10 | Download from Weakpass | Browse and download Weakpass wordlist torrents, with automatic extraction |
| 11 | Hashmob Downloads | Access a submenu for downloading Hashmob archives (yearly full-found corpora) and combined-left lists (per-mode uncracked hashes) |

All binaries are in `hate_crack/hashcat-utils/bin/`.

#### Rule File Tools (option 81)
Preprocesses hashcat rule files using `cleanup-rules.bin` and `rules_optimize.bin` from hashcat-utils, and downloads rule files from Hashmob.net.

* **Clean** (1) - removes invalid syntax and duplicate rules using `cleanup-rules.bin`. Useful after combining rule files or downloading rules from external sources.
* **Optimize** (2) - consolidates redundant operations using `rules_optimize.bin`. Reduces rule file size and improves cracking speed.
* **Clean and optimize** (3) - runs both operations in sequence via a temporary file, then writes the final result.
* **Download rules from Hashmob.net** (4) - fetches rule files into the configured `rulesDirectory`.
* **Analyze Hashcat rules** (5) - opcode frequency analysis of a rule file, powered by HashcatRosetta.

The three preprocessing operations read from an input file and write to a separate output file (original is never modified).

#### Download Rules from Hashmob.net (Rule File Tools option 4)
Downloads the latest rule files from Hashmob.net's rule repository. These rules are curated and optimized for password cracking and can be used with the Quick Crack and Loopback Attack modes.

* Downloads rule sets in parallel using a thread pool (up to 4 concurrent downloads)
* Skips rules already downloaded locally
* Reports download summary with success/failure counts
* Stores rules in the configured rules directory

#### Analyze Hashcat Rules (Rule File Tools option 5)
Powered by HashcatRosetta (https://github.com/bandrel/HashcatRosetta), this feature analyzes hashcat rule files to provide detailed insights into rule composition and complexity.

* Prompts for a rule file path
* Displays frequency analysis of rule opcodes (operations)
* Helps understand what transformations a rule set performs
* Useful for rule debugging and optimization

#### Mask Tools (option 83)
Downloads mask files from Hashmob.net. This is a minimal submenu today — masks
have no local file-tooling counterpart to the rule/wordlist cleanup and
optimization utilities, only a download capability.

* **Download masks from Hashmob.net** (1) - fetches mask files into the hate_crack masks directory.

#### Download Masks from Hashmob.net (Mask Tools option 1)
Downloads mask files from Hashmob.net's mask repository into the hate_crack masks directory for use with mask-based attacks.

* Downloads mask sets in parallel using a thread pool (up to 4 concurrent downloads)
* Skips masks already downloaded locally
* Reports download summary with success/failure counts
* Stores masks in the configured masks directory used by the Ad-hoc Mask Attack
* Supports interactive listing, range selection, and browsing of available mask files

#### Download Wordlists from Hashmob.net (Wordlist Tools option 9)
Downloads wordlists from Hashmob.net's collection of cracked passwords and commonly used wordlists.

* Interactive menu for browsing available wordlists
* Progress tracking for large downloads
* Stores wordlists in configured wordlist directory

#### Weakpass Wordlist Menu (Wordlist Tools option 10)
Interactive menu for downloading and managing wordlists from Weakpass.com via BitTorrent, pulling the listing from Weakpass's public REST API.

* Browse available Weakpass wordlists, showing tier (S-F) and crack rate (%)
* Filter by tier using the `--rank` flag (7=S, 6=A, 5=B, 4=C, 3=D, 2=E, 1=F; -1 defaults to S/A/B)
* Download specific wordlists by selection
* Automatic extraction of compressed archives
* Progress tracking for torrent downloads

#### Hashmob Downloads (Wordlist Tools option 11)
Access a submenu for downloading large-scale password corpora and specialized wordlists from Hashmob.net.

**Archives** - Downloads yearly full-found password corpora (multi-GB archives containing all cracked passwords from a given year)
* Requires confirmation before downloading -- these archives are large (the listing may show "(unknown size)" since Hashmob's API doesn't currently report a file size per archive)
* Lists all available archives across every year as one globally-numbered list to browse and pick from by index, rather than a per-year picker
* Accepts `a` (or `all`) at the selection prompt to download every listed archive, one at a time. A single confirmation naming the archive count and the summed size covers the whole batch; an archive already on disk at its listed size is skipped, one whose size does not match is re-downloaded, and a failure is counted rather than aborting the rest
* Stores archives in the configured wordlist directory for extraction and use

**Combined Left Lists** - Downloads per-hashcat-mode combined lists of uncracked ("left") hashes from Hashmob.net
* Each list is a set of hashes, not plaintexts, still awaiting a crack for that hashcat mode
* Useful for spotting overlap between your own hash list and hashes the community hasn't cracked yet
* Supports mode selection from the listed hash counts per algorithm

-------------------------------------------------------------------
### Version History

The full, per-release changelog now lives in [CHANGELOG.md](https://github.com/trustedsec/hate_crack/blob/main/CHANGELOG.md).
Baixar ferramenta