Introdução
John the Ripper (JtR) é uma ferramenta popular e poderosa de auditoria de segurança de senhas e recuperação de senhas de código aberto. Ele pode realizar a quebra de senhas usando vários modos, como o modo "single crack", o modo "wordlist" e o modo "incremental".
Além desses modos padrão, o JtR oferece um "Modo Externo" incrivelmente flexível. Este modo permite que você use um programa ou script externo para gerar candidatos a senhas. Isso lhe dá controle total sobre a lógica de geração de senhas, permitindo que você crie padrões de senha altamente personalizados e complexos que não são possíveis com outros modos.
Neste laboratório, você aprenderá os fundamentos do Modo Externo do JtR. Você começará entendendo os conceitos básicos, depois escreverá, compilará e usará seu próprio programa C personalizado para gerar senhas. Você também aprenderá técnicas básicas de depuração e aplicará seu conhecimento a um cenário mais prático.
Compreender os Conceitos Básicos do Modo Externo
Nesta etapa, você aprenderá os conceitos fundamentais do Modo Externo do John the Ripper. Este modo funciona executando um programa externo que você define. O John the Ripper lê a saída padrão deste programa, tratando cada linha como um candidato a senha potencial.
Estes modos externos são definidos no arquivo de configuração john.conf, geralmente localizado em /etc/john/john.conf. Cada modo externo é definido dentro de uma seção como [List.External:NomeDoModo].
Vamos inspecionar uma definição de modo externo existente no arquivo de configuração padrão para ver como ela é estruturada. Procuraremos o modo Keyboard, que simula candidatos a senhas com base em padrões de caminhada no teclado.
Execute o seguinte comando para visualizar a configuração do modo Keyboard:
grep -A 10 "\[List.External:Keyboard\]" /etc/john/john.conf
Você verá um bloco de código semelhante a C. A função mais importante é generate(), que é responsável por produzir os candidatos a senhas.
Para ver um modo externo em ação, você pode executar john com o sinalizador --stdout. Isso diz ao John para imprimir os candidatos gerados na tela em vez de tentar quebrar um hash. Vamos testar o modo Keyboard.
john --stdout --external=Keyboard | head -n 5
Este comando seleciona o modo externo Keyboard e redireciona sua saída para head, que mostra os primeiros 5 candidatos a senhas gerados. A saída será uma sequência de caracteres representando padrões de teclado.
q
w
e
r
t
Isso demonstra o princípio básico: o John the Ripper executa a lógica definida no modo externo e usa sua saída como fonte de senhas. Nas próximas etapas, criaremos nosso próprio programa para atuar como a fonte.
Escrever um Script Simples de Modo Externo
Nesta etapa, você escreverá e compilará seu primeiro script simples de modo externo usando a linguagem de programação C. Nosso objetivo é criar um programa que gere uma lista fixa de senhas e, em seguida, configurar o John the Ripper para usá-lo.
Primeiro, vamos criar um arquivo fonte C chamado simple_gen.c usando o editor nano.
nano simple_gen.c
Agora, copie e cole o seguinte código C no editor nano. Este programa simplesmente imprimirá três senhas diferentes na saída padrão, cada uma em uma nova linha.
#include <stdio.h>
int main() {
printf("pass1\n");
printf("pass2\n");
printf("pass3\n");
return 0;
}
Pressione Ctrl+X, depois Y e Enter para salvar o arquivo e sair do nano.
Em seguida, compile este código C em um arquivo executável chamado simple_gen usando o compilador gcc.
gcc -o simple_gen simple_gen.c
Agora que temos nosso executável, precisamos dizer ao John the Ripper como usá-lo. Faremos isso criando uma cópia local do arquivo de configuração em nosso diretório de projeto e adicionando uma nova definição de modo externo.
cp /etc/john/john.conf ./my_john.conf
Abra o novo arquivo my_john.conf com o nano.
nano my_john.conf
Role até o final do arquivo e adicione o seguinte bloco de configuração. Isso define um novo modo externo chamado MySimple que executa nosso programa simple_gen.
[List.External:MySimple]
void generate()
{
exec("./simple_gen");
}
Salve e saia do nano (Ctrl+X, Y, Enter).
Finalmente, vamos testar nosso novo modo externo. Usaremos o sinalizador --stdout novamente para ver a saída e o sinalizador --config para apontar o John para nosso arquivo de configuração personalizado.
john --stdout --external=MySimple --config=./my_john.conf
Você deverá ver a saída exata do nosso programa C, confirmando que o John the Ripper está executando com sucesso nosso script personalizado.
pass1
pass2
pass3
Implementar Lógica de Geração de Senhas Personalizada
Nesta etapa, você aprimorará seu script para implementar uma lógica de geração de senhas mais dinâmica. Em vez de uma lista fixa, geraremos senhas com base em um padrão: uma palavra base seguida por uma sequência de números. Este é um padrão comum para senhas fracas.
Vamos modificar nosso programa C para gerar senhas como labex0, labex1, labex2 e assim por diante.
Abra o arquivo simple_gen.c novamente com o nano.
nano simple_gen.c
Substitua o código existente pelo seguinte. Esta nova versão usa um loop for para anexar números de 0 a 199 à palavra base "labex".
#include <stdio.h>
int main() {
char *base_word = "labex";
for (int i = 0; i < 200; i++) {
printf("%s%d\n", base_word, i);
}
return 0;
}
Salve e saia do nano. Agora, recompile o programa com gcc para aplicar as alterações.
gcc -o simple_gen simple_gen.c
Vamos testar o gerador atualizado com o sinalizador --stdout para ver uma amostra da nova saída.
john --stdout --external=MySimple --config=./my_john.conf | head -n 5
A saída agora deve mostrar o novo padrão.
labex0
labex1
labex2
labex3
labex4
Agora para o teste real. Usaremos nosso modo externo personalizado para quebrar o hash de senha que preparamos durante a configuração. A senha para o testuser é labex123. Nosso script gera este candidato, então ele deve encontrar uma correspondência.
Execute o seguinte comando para iniciar o processo de quebra. Observe que removemos --stdout e adicionamos o caminho para nosso arquivo de hash, hashes.txt.
john --external=MySimple --config=./my_john.conf ./hashes.txt
O John executará seu script, gerará candidatos e os testará contra o hash. Ele deve encontrar a senha rapidamente. A saída será algo parecido com isto:
Using default input encoding: UTF-8
Loaded 1 password hash (sha512crypt, $6$ [SHA512 256/256 AVX2 4x])
Cost 1 (iteration count) is 5000 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
labex123 (testuser)
1g 0:00:00:00 DONE (2024-05-20 08:30) 100.0g/s 12300p/s 12300c/s 12300C/s labex123..labex130
Use the "--show" option to display all of the cracked passwords reliably
Session completed
Para confirmar a senha quebrada, use a opção --show.
john --show ./hashes.txt
Isso exibirá a senha quebrada ao lado do nome de usuário.
testuser:labex123:1001:1001::/home/testuser:/bin/sh
1 password hash cracked, 0 left
Depurar Scripts de Modo Externo
Nesta etapa, você aprenderá algumas técnicas básicas para depurar seus scripts de modo externo. Quando um script não funciona como esperado, pode ser complicado diagnosticá-lo porque ele está sendo executado por outro programa (John the Ripper).
Um método de depuração comum e eficaz é escrever mensagens de log do seu script em um arquivo separado. Isso permite rastrear seu fluxo de execução e inspecionar valores de variáveis.
Vamos modificar nosso programa C para escrever em um arquivo de log chamado debug.log. Abra simple_gen.c com o nano.
nano simple_gen.c
Substitua o código pela seguinte versão. Este código abre debug.log para escrita e, em seguida, usa fprintf para escrever mensagens de status nele durante a execução.
#include <stdio.h>
#include <stdlib.h>
int main() {
FILE *log_file = fopen("debug.log", "w");
if (log_file == NULL) {
// Cannot open log file, exit
return 1;
}
fprintf(log_file, "Debug: Script started.\n");
char *base_word = "labex";
for (int i = 0; i < 200; i++) {
printf("%s%d\n", base_word, i);
fprintf(log_file, "Debug: Generated candidate %s%d\n", base_word, i);
}
fprintf(log_file, "Debug: Script finished.\n");
fclose(log_file);
return 0;
}
Salve e saia do nano, em seguida, recompile o programa.
gcc -o simple_gen simple_gen.c
Agora, execute o John the Ripper novamente. Não precisamos ver os candidatos a senha, então podemos redirecionar a saída padrão para /dev/null. A parte importante é que nosso script será executado e criará o arquivo de log.
john --stdout --external=MySimple --config=./my_john.conf > /dev/null
O comando será executado por um momento e terminará. Agora, um arquivo debug.log deve existir em seu diretório de projeto. Vamos visualizar seu conteúdo.
cat debug.log | head -n 5
Você deverá ver as mensagens de depuração que adicionamos ao nosso programa.
Debug: Script started.
Debug: Generated candidate labex0
Debug: Generated candidate labex1
Debug: Generated candidate labex2
Debug: Generated candidate labex3
Essa técnica é inestimável para encontrar problemas em sua lógica, como loops incorretos, valores de variáveis errados ou erros de acesso a arquivos, sem a interferência da própria saída do John the Ripper.
Aplicar Modo Externo a Cenários Específicos
Nesta etapa, você aplicará seu conhecimento a um cenário mais prático. Em vez de usar uma palavra base codificada, seu script lerá uma lista de palavras base de um arquivo e gerará variações para cada uma. Esta é uma abordagem muito mais poderosa e realista.
Primeiro, vamos criar um arquivo simples de lista de palavras chamado words.txt contendo algumas palavras base potenciais.
echo "admin" > words.txt
echo "user" >> words.txt
echo "guest" >> words.txt
Em seguida, modificaremos nosso programa C para ler este arquivo. O programa precisará aceitar o nome do arquivo da lista de palavras como um argumento de linha de comando. Abra simple_gen.c com o nano.
nano simple_gen.c
Substitua o código pelo seguinte. Esta versão lê um nome de arquivo da linha de comando, abre esse arquivo e, para cada palavra que lê, gera três candidatos a senha: a própria palavra, a palavra seguida por "123" e a palavra seguida por "2024".
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
if (argc < 2) {
fprintf(stderr, "Usage: %s <wordlist_file>\n", argv[0]);
return 1;
}
FILE *file = fopen(argv[1], "r");
if (file == NULL) {
perror("Error opening file");
return 1;
}
char line[256];
while (fgets(line, sizeof(line), file)) {
// Remove newline character from the end of the line
line[strcspn(line, "\n")] = 0;
// Generate variations for the word
printf("%s\n", line);
printf("%s123\n", line);
printf("%s2024\n", line);
}
fclose(file);
return 0;
}
Salve, saia e recompile o programa.
gcc -o simple_gen simple_gen.c
Agora, devemos atualizar nosso arquivo my_john.conf para passar o nome do arquivo words.txt como um argumento para nosso script. Vamos criar um novo modo externo chamado MyAdvanced para isso. Abra my_john.conf com o nano.
nano my_john.conf
Role até o final do arquivo e adicione esta nova seção. Observe como "words.txt" é passado como um segundo parâmetro para a função exec.
[List.External:MyAdvanced]
void generate()
{
exec("./simple_gen", "words.txt");
}
Salve e saia do nano. Finalmente, teste seu novo modo externo avançado.
john --stdout --external=MyAdvanced --config=./my_john.conf
A saída agora deve ser uma lista de candidatos a senha gerados a partir das palavras em seu arquivo words.txt, com as variações especificadas aplicadas a cada uma.
admin
admin123
admin2024
user
user123
user2024
guest
guest123
guest2024
Você criou com sucesso um gerador de senhas flexível e baseado em arquivo para o John the Ripper.
Resumo
Parabéns por completar este laboratório! Você explorou com sucesso o poderoso Modo Externo do John the Ripper.
Neste laboratório, você aprendeu:
- O conceito básico do Modo Externo do John the Ripper e como ele usa programas externos para gerar candidatos a senha.
- Como escrever, compilar e usar um programa C simples como gerador de senhas.
- Como configurar um modo externo personalizado no arquivo
john.conf. - Como implementar lógica de geração de senhas dinâmica baseada em padrões.
- Como usar seu modo personalizado para quebrar com sucesso um hash de senha.
- Uma técnica básica, mas eficaz, para depurar seus scripts externos registrando em um arquivo.
- Como criar um script mais avançado e prático que lê palavras base de um arquivo.
As habilidades que você adquiriu fornecem uma base para criar regras de quebra de senha altamente especializadas, adaptadas a alvos e cenários específicos. Você pode explorar ainda mais este tópico usando outras linguagens de script como Python ou Perl, ou implementando lógica de mutação e geração de senhas ainda mais complexa.


