Lab de Processos
Em um Sistema Operacional, por razões de segurança, as senhas dos usuários não são armazenadas em texto simples, mas sim como um hash. Quando um usuário tenta fazer login a senha digitada é criptografada (gerado um hash) para ser comparado com o hash armazenado. Dessa forma, não há necessidade de armazenar sua senha real.
Caso o usuário tenha utilizado letras maiúsculas e minúsculas, caracteres especiais e numeros é praticamente impossível restaurar a senha a partir do hash. No entanto, se a senha for simples, e estivermos dispostos a gastar algum tempo de CPU, é possível tentar todas as combinações de caracteres possíveis em uma senha (ataque de força bruta) até gerar um hash igual ao hash armazenado.
Neste lab você deve implementar o programa cracker_insper.c que recupera as senhas perdidas de usuários, a partir de uma parte conhecida da senha. Para tanto, utilizaremos a ferramenta hashcat que gera o hash de uma senha (o nome da ferramenta é uma brincadeira com o comando cat do Linux com préfixo hash). A ferramenta tem como entrada um hash da senha original, a parte conhecida da senha e uma string (semente), com pelo menos dois caracteres, usada no algoritmo de criptografia para iniciar o gerador de hash.
O programa hashcat quebra o hash utilizando um algoritmo de criptografia, que gera várias combinações de caracteres, começando com a parte conhecida da senha. Caso a ferramenta tenha sucesso, a senha é impressa no terminal. Abaixo um exemplo de chamada e saída do executável hashcat:
$ ./hashcat xxhx0AsVpMTMU sysx???? aa
./hashcat: recuperando a senha para o hash [xxhx0AsVpMTMU].
./hashcat: senha [sysxpert] recuperada.
No exemplo acima é informado o hash "xxhx0AsVpMTMU", associado a uma senha, e a parte conhecida da senha "sysx", seguida de caracteres de interrogação (?), representando os caracteres desconhecidos, e por fim a string "aa" que representa a semente para o inicializar algoritmo de criptografia. Para entrada do exemplo acima o executável hashcat consegue recuperar a senha a partir da parte conhecida da senha.
Ao finalizar o executável hashcat pode retornar os seguintes valores:
-
-1: quando a quantidade ou tamanho dos argumentos está incorreta ou errada
-
0: quando consegue finalizar normalmente e quebrar a senha
-
1: quando não consegue quebrar a senha
Ultimamente o executável hashcat está um pouco instável, com falhas e travamentos inesperados, culpa talvez do último estagiário que deu manutenção no código. Essa manutenção fez com que, as vezes, a ferramenta trave indefinidamente, nem Ctrl+C o finaliza. O executável também tem um erro inexplicável de acesso à memória, finalizado pelo SO com um sinal de segmentation fault (Falha de segmentação).
O estagiário que fez a manutenção informou que quando o hashcat falhar por acesso à memória ou ficar travado indefinidamente, o usuário pode executar novamente a programa alterando a semente usada para o inicializar algoritmo de criptografia. Acreditem, essa gambiarra funciona. Veja uma sequencia desses erros:
$ ./hashcat xxqJ7cKzV3v4E zip????? aa
./hashcat: recuperando a senha para o hash [xxqJ7cKzV3v4E].
Falha de segmentação (imagem do núcleo gravada)
Para semente "ab" o programa trava indefinidamente, sendo necessário enviar um sinal de kill a partir do Shell para finalizá-lo. Para descobrir o número do processo execute ps -C hashcat e depois kill -9 <pid>.
Mas se passar a semente para "ac", o executável consegue recuperar a senha:
$./hashcat xxq5aBqiB66j2 xz???? ac
./hashcat: recuperando a senha para o hash [xxqJ7cKzV3v4E].
./hashcat: senha [xzzzzy] recuperada.
Entrega
O programa fonte cracker_insper.c já está na pasta lab/02-lab-processos em seu repositório de atividades (github), na branch principal, para entregar você só precisa fazer upload (git add . & git commit -m "fase#" & git push) do arquivo fonte no seu repositório a cada fase finalizada. Não precisa criar tag.
Lembre-se de se atentar ao prazo de entrega definido aqui!.
Avaliação
O programa será avaliado de forma manual pelo professor da disciplina, utilizando rubricas que descreve as funcionalidades implementadas. Quanto maior o número de funcionalidades implementadas, maior será a nota.
Caso necessário, para validação das fases, poderá ser realizada uma entrevista sobre a implementação desse laboratório.
Restrições
Esta atividade tem com objetivo avaliar dos conceitos vistos na disciplina. Portanto, algumas restrições serão aplicadas ao código:
-
Todo o trabalho com arquivos deverá ser realizado utilizando as APIs POSIX vistas em aula. Não é permitido o uso de funções da
Standard I/Opara manipulação de arquivos, como, por exemplo,fopen(),fdopen(),fread()efclose(). -
As impressões no terminal da sua implementação devem seguir rigorosamente os exemplos apresentados nas fases.
-
Caso você utilize algum trecho de código da documentação (ou de outra fonte), inclua a devida atribuição em um comentário no código.
-
É proibido o uso de ferramentas de geração automática de código por IA, como, por exemplo, o ChatGPT.
O não cumprimento dessas restrições resultará na atribuição de nota zero para este laboratório.
Fase 0
-
O programa
- O programa não implementa algum dos requisitos da rubrica da Fase 1.cracker_insper.cnão compila ou compila com warnings. Para compilar use:
NOTA desta fase: 0.0
Fase 1
-
O programa
cracker_insper.ccompila SEM warnings. -
Não preencheu o arquivo
README.md -
O programa roda na linha de comando como abaixo, recebendo os argumentos para o executável conforme abaixo, informando o nome do usuário, o hash da senha e parte da senha conhecida.
-
Para recuperar a senha do usuário
fabioo seu programacracker_insper.cdeve realizar uma chamada ao executávelhashcatutilizando a funçãoexecvpconforme visto em aula. Você não pode, por exemplo, usar a chamada da função system. -
Caso seja informado o número de parâmetros incorreto no seu programa, este deve finalizar com uma mensagem de orientação.
-
As chamadas do executável
hashcatvocê deve começar a stringaacomo a primeira semente para o algoritmo de criptografia. -
Caso o
hashcattenha sucesso, ou seja, ohashcatretornou 0, o seu programa, você deverá mostrar, após a mensagem do executávelhashcata mensagem abaixo:$ ./cracker_insper fabio xxhx0AsVpMTMU sysx???? ./hashcat: recuperando a senha para o hash [xxhx0AsVpMTMU]. ./hashcat: senha [sysxpert] recuperada. ./cracker_insper: senha do usuario {fabio} recuperada.Se a recuperação falhar por acesso à memória ou não for possível recuperar a senha o seu programa deverá mostrar uma mensagem informando o usuário e qual foi a falha ocorrida, por exemplo:
$ ./cracker_insper paulo xxHUf9zUctXNA miss???? ./hashcat: recuperando a senha para o hash [xxHUf9zUctXNA]. ./cracker_insper: falha de memoria na recuperacao da senha do usuario {paulo}.Ou quando não é possível recuperar a senha, como o retornou igual 1 do executário
hashcat. -
Caso o seu programa
cracker_insperfique travado devido à execução dohashcat, finalize-o comCtrl+Ce encerre o processohashcatcom o comandokillno Shell, a fim de evitar sobrecarga no sistema operacional. -
Para essa e as outras fases, o programa
cracker_insper.cdeve imprimir exclusivamente as mensagens especificadas nos exemplos. Mensagens de depuração ou quaisquer saídas adicionais devem ser removidas antes da entrega.
NOTA desta fase: 2.0
Fase 2
-
A partir desta fase, e para todas as fases seguintes, você deverá entregar o arquivo
README.mdcontendo as seguintes informações:- Seu nome e uma descrição das fases do laboratório que conseguiu completar;
- Relato de quaisquer bugs ou erros identificados no seu programa;
- Alguma decisão de design relevante que você gostaria de compartilhar.
- Inclua também o link de um vídeo explicativo, com áudio e captura de tela visível, apresentando a execução da sua implementação.
-
Nesta fase, você deve melhorar a versão implementada na fase anterior. Agora caso a ferramenta
hashcatfalhe por acesso à memória (segmentation fault), o seu programa deverá realizar uma nova tentativa, modificando a semente do algoritmo de criptografia. Por exemplo: se a execução inicial utilizar a stringaa, na próxima tentativa você pode utilizarab. Em geral, a senha já é recuperada na segunda tentativa. Ao conseguir recuperar a senha, informe a semente utilizada. Veja o exemplo de execução a seguir:$ ./cracker_insper paulo xxHUf9zUctXNA miss???? ./hashcat: recuperando a senha para o hash [xxHUf9zUctXNA]. ./cracker_insper: falha de memoria na recuperacao da senha do usuario {paulo}. ./hashcat: recuperando a senha para o hash [xxHUf9zUctXNA]. ./hashcat: senha [missudad] recuperada. ./cracker_insper: senha do usuario {paulo} recuperada com a semente {ab}. -
Nesta fase você também deverá tratar o travamento indefinido da ferramenta
hashcat. O seu programacracker_insper.cdeve aguardar alguns segundos (por exemplo, 5 segundos) pela finalização do processo filho (hashcat). Caso esse tempo seja excedido (timeout), o programa deve encerrá-lo utilizando o sinalSIGKILL, por meio da funçãokill()da bibliotecasignal.h, em seguida, realizar uma nova tentativa com uma semente diferente. Dica de implementação: para que o seu programa aguarde a finalização do processo filho de forma não bloqueante, pesquise a utilização da funçãowaitpid(-1,...)e leia atentamente o manual dessa função (man waitpid). -
Programa
cracker_insper.croda sem erros no valgrind. Para testar use:
NOTA desta fase: 5.0
Fase 3
-
Nesta fase, além das funcionalidades da Fase 2, que devem ser mantidas na Fase 3, o programa
cracker_insper.ctem a opção de receber uma flag-fseguida pelo nome de um arquivo de senhas, informado por linha de comando. Seu programa deverá ler o arquivo e recuperar as senhas dos usuários armazenados dentro do arquivo, exemplo: -
Cada linha do arquivo deve ser tratado como um processo independente, e a recuperação das senhas pode ser realizada de forma sequencial, assim seu programa pode ler uma linha do arquivo de entrada, chamar o executável
hashcat, receber a resposta e imprimir no terminal. Cada linha do arquivo conterá:- Nome de usuário (de 1 a 8 caracteres)
- Hash de senha (13 caracteres)
- Parte conhecida da senha (mais interrogações que representam caracteres desconhecidos), contém de 0 a 8 letras minúsculas seguidas de 0 a 8 pontos de interrogação. Importante: a soma da parte conhecida + os pontos de interrogação terão no máximo 8 caracteres.
-
Esses três campos são separados por um único espaço. Todas as informações que fornecemos estão garantidas neste formato. Não se preocupe com nomes de usuário duplicados ou prefixos duplicados. Exemplo de arquivo de entrada (
senhas1.in): -
A partir desta fase você deverá utilizar o executável
hashcatem modo silencioso, no qual não há saída no terminal. Para isso, basta colocar no final da chamada o argumento-f, que fará com que ohashcatgere um arquivo com a senha encontrada. O nome do arquivo será o hash informado com extensão.txt, veja um exemplo de execução dohashcatcom esse argumento. -
Abaixo há um exemplo da chamada do seu programa com o flag
-fcom o arquivosenhas1.in, juntamente com a respectiva saída no terminal. Observe que cada linha do arquivo é processada sequencialmente. Em cada tentativa de execução dohashcat, deve ser informado a linha do arquivo, o nome do usuário e semente. Caso a senha seja recuperada com sucesso, o programa deve informar o usuário e a senha correspondente. Os casos de falha do executávelhashcatdevem ser reportados conforme exemplo a seguir:- Importante: Como na Fase 2$ ./cracker_insper -f senhas1.in linha 1: recuperando senha de {fabio} com semente {aa}. linha 1: senha do usuario {fabio} recuperada {sysxpert}. linha 2: recuperando senha de {paulo} com semente {aa}. linha 2: falha de memoria na recuperacao da senha do usuario {paulo}. linha 2: recuperando senha de {paulo} com semente {ab}. linha 2: senha do usuario {paulo} recuperada {missudad}. linha 3: recuperando senha de {andre} com semente {aa}. linha 3: nao eh possivel recuperar a senha do usuario {andre}. linha 4: recuperando senha de {jose} com semente {aa}. linha 4: timeout de espera para senha de {jose}. linha 4: recuperando senha de {jose} com semente {ab}. linha 4: senha do usuario {jose} recuperada {helloaac}.
NOTA desta fase: 7.5
Fase 4
-
Nesta fase, você deve paralelizar a solução da Fase 3. O arquivo de senhas deve ser processado em paralelo, e não mais sequencial. No início da execução, o programa
cracker_insper.cdeverá carregar todas as linhas do arquivo de entrada e, para cada linha, disparar a execução dohashcat, e depois aguardar a finalização de todas as execuções e apresentar as saídas correspondentes. -
Abaixo um exemplo de execução do programa com o arquivo
senhas1.in, juntamente com uma possível saída. Note que deve ser informado a linha que foi processada, bem como os casos em que ocorreu falha na recuperação da senha.$ ./cracker_insper -f senhas1.in linha 1: recuperando senha de {fabio} com semente {aa}. linha 2: recuperando senha de {paulo} com semente {aa}. linha 3: recuperando senha de {andre} com semente {aa}. linha 4: recuperando senha de {jose} com semente {aa}. linha 1: senha do usuario {fabio} recuperada {sysxpert}. linha 2: falha de memoria na recuperacao da senha do usuario {paulo}. linha 2: recuperando senha de {paulo} com semente {ab}. linha 2: senha do usuario {paulo} recuperada {missudad}. linha 4: timeout de espera para senha de {jose}. linha 3: nao eh possivel recuperar a senha do usuario {andre}. linha 4: recuperando senha de {jose} com semente {ab}. linha 4: senha do usuario {jose} recuperada {helloaac}. -
Lembre-se que o programa
cracker_insper.cdeve imprimir exclusivamente as mensagens apresentadas nos exemplos. Mensagens de depuração ou quaisquer saídas adicionais devem ser removidas antes da entrega. -
Por fim, ao pressionar
Ctrl+Cno terminal, o programacracker_insper.cdeve encerrar todos os processos dohashcatque ainda estão executando ou travados, e remove todos os arquivos de senhas gerados.
NOTA desta fase: 10.0
IMPORTANTE: Considere as fases como cumulativas, ou seja, cada versão deve manter as funcionalidades da fase anterior e acrescentar novas. Por exemplo, a versão da Fase 2, você deveria passar nos testes do valgrind, isso passa valer para todas as seguintes da Fase 2. E em caso de dúvida consulte o professor. Caso você não implemente alguma funcionalidade de uma determinada fase a nota atribuída será a da fase anterior.