Quebrador De Senhas Em C

Introdução

Para quem leu o post:

https://daemoniolabs.wordpress.com/2011/08/22/simular-autenticacao-do-sudo-em-c/

percebeu que é fácil criar um quebrador/cracker de senhas em ambiente linux.

Nesse post irei mostrar um simples cracker de senhas usando a linguagem C.

Como quebrar as senhas

A lógica mais usual que um cracker de senhas usa é a seguinte:

  1. Ler uma lista de palavras, conhecida como wordlist.
  2. Para cada palavra da wordlist, cria-se um hash dela usando o mesmo algoritmo e salt utilizados para gerar o hash que queremos quebrar.
  3. Compara-se os hashes. Se são iguais, então a senha foi quebrada.

Para mais detalhes, veja o link no início do post e suas referências.

O programa

O programa se chama qcrack.c e seu código se encontra no fim deste post. Para compilá-lo, digite:

$ gcc -o qcrack qcrack.c -lcrypt

Para executá-lo você precisará de dois arquivos: O primeiro é o arquivo de senhas encriptadas, ou seja, o arquivo /etc/shadow. O segundo é uma wordlist, que nada mais é que uma lista de palavras. Wordlists podem ser encontradas facilmente na internet, mas se você deseja gerar uma usando permutações, veja o script na referência [1].

Exemplo de uso real

Para testar o programa criei um usuário em meu sistema cuja senha era uma data qualquer. Senhas em formato de data são muito utilizadas e em geral são facilmente quebradas.

Com isso criei uma wordlist usando o brutus.sh [1]:

$ ./brutus.sh -d -r 4 | sed 's/$/88/' > wordlist.txt

O conteúdo da wordlist é da forma: XXXX88 que inclui todos os dias do ano de 88 (e mais alguns números como 000088 que não são datas válidas).

Criada a wordlist, agora vamos executar o programa:

$ sudo su #(precisamos de root para ler o /etc/shadow)
# ./qcrack /etc/shadow wordlist.txt
Usuario   : daemon9
Algoritmo : SHA-512
Salt      : Y0R8yeD/
Hash      : OyzjYU8Nfl9A7xXCOZwX1DfejOMBIAoTq7Gbw20juhZu0O8aWrudGaw/ZRVL0efa9O3z0S.T79cdJsUwBFu6I0
SENHA     : 121188

Depois de algum tempo o programa retornou a senha 121188 que é a senha do usuário daemon9.

O código

/*
 * [Autor]
 * Marcos Paulo Ferreira (Daemonio)
 * undefinido gmail com
 * https://daemoniolabs.wordpress.com
 *
 * [qcrack.c]
 * Programa simples que quebra senhas encriptadas
 * pela função crypt().
 * O arquivo de senhas, na maioria das vezes o
 * arquivo /etc/shadow, DEVE seguir esse formato:
 *
 * <usuario>:$id$salt$encrypt (veja: man crypt)
 * Ex:
 * daemonio:$6$eqwsadsf$c2FpIGRha2kK
 *
 * [Como compilar]
 * $ gcc -o qcrack qcrack.c -lcrypt
 *
 * [Como usar]
 * $ ./qcrack <shadow> <wordlist>
 *
 * Em que:
 * <shadow>   : arquivo shadow
 * <wordlist> : wordlist
 *
 * Versão 1.0
 * Ter Ago 23 23:01:11 BRT 2011
 * Qua Ago 24 16:39:27 BRT 2011
 *
 * Versão 1.1
 * Mon May 14 19:27:38 BRT 2012
 */

/* Necessário para crypt() (veja: $ man crypt)*/
#define _XOPEN_SOURCE 700

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>

/* Tamanhos máximos de alguns campos
 * do arquivo shadow. */
#define LOGIN_LEN 51
#define ID_LEN 6
#define SALT_LEN 101
#define HASH_LEN 1025

#define FALSE 0
#define TRUE 1

/* Estrutura que contém alguns
 * campos do arquivo shadow. */
struct st_shadow {
    char login[LOGIN_LEN] ;
    char id[ID_LEN] ;
    char salt[SALT_LEN] ;
    char hash[HASH_LEN] ;
} ;

/* Armazena os campos do shadow em uma struct.
 * Os campos são extraídos usando strtok() e
 * armazenados em posições específicas
 * partindo do ponteiro da struct.
 */
char get_info_shadow(char *linha, struct st_shadow *st) {
    char qtd = 0 ;
    char *token ;
    int i ;
    /* tamanho máximo de cada campo */
    int lengths[] = {LOGIN_LEN, ID_LEN, SALT_LEN, HASH_LEN} ;
    /* p aponta para o campo atual */
    char *p = (char *)st ;

    i = 0;
    while((token=strtok(linha, ":$"))&&(qtd<4)) {
        /* copia o campo para p */
        strncpy(p, token, lengths[i]) ;
        /* contador de campos lidos */
        qtd++ ;
        p+=lengths[i] ;
        /* Na segunda chamada de strtok,
         * linha deve ser NULL. */
        linha = NULL ;
        i++ ;
    }

    /* Formato não suportado do shadow. */
    if ( qtd != 4 ) {
        return FALSE ;
    }

    return TRUE;
}

/* Mostra algumas informações. */
void show_info(struct st_shadow *st) {
    puts("************************") ;
    printf("Usuario   : %s\n", st->login) ;

    printf("Algoritmo : ") ;
    if ( !strcmp(st->id, "1") ){
        printf("MD5\n") ;
    } else if ( !strcmp(st->id, "2a") ) {
        printf("Blowfish\n") ;
    } else if ( !strcmp(st->id, "5") ) {
        printf("SHA-256\n") ;
    } else if ( !strcmp(st->id, "6") ) {
        printf("SHA-512\n") ;
    } else {
        printf("Desconhecido...\n") ;
    }

    printf("Salt      : %s\n", st->salt) ;
    printf("Hash      : %s\n", st->hash) ;
    printf("SENHA     : ") ;
    fflush(stdout) ;
}

/* Função que quebra a senha. Ela basicamente compara
 * o hash gerado para cada senha da wordlist com o
 * hash do shadow. Se os hashes são iguais, então a
 * senha foi quebrada. */
void quebrar_senha(struct st_shadow *st, FILE *wordlist) {
    char senha[BUFSIZ], idsaltsenha[BUFSIZ] ;
    char *crypthash ;

    show_info(st) ;

    /* Vá para o início do arquivo. */
    rewind(wordlist) ;

    /* Obtém cada senha da wordlist */
    while(fgets(senha, BUFSIZ, wordlist)) {
        if ( senha[strlen(senha)-1] == '\n' ) {
            senha[strlen(senha)-1] = 0 ;
        }
        /* $id$salt$encrypt*/
        sprintf(idsaltsenha, "$%s$%s$%s", st->id, st->salt, st->hash) ;

        /* gera o hash de `senha' */
        crypthash = (char *)crypt(senha, idsaltsenha) ;

        /* Jackpot!! Quebramos a senha */
        if ( crypthash != NULL ) {
            if ( !strcmp(crypthash, idsaltsenha) ) {
                printf("%s\n", senha) ;
                return ;
            }
            /* Algo errado em crypt(). */
        } else {
            printf("\n>> Erro em crypt(). Impossível criar hash. <<\n") ;
            return ;
        }
    }

    /* Senha não quebrada. */
    printf("<senha nao quebrada>\n") ;
}

int main(int argc, char **argv) {
    FILE *shadow, *wordlist ;
    char linhashadow[BUFSIZ] ;
    struct st_shadow stshadow ;

    if ( argc < 3 ) {
        printf("qcrack - by Daemonio\n") ;
        printf("[uso] %s <shadow> <wordlist>\n", argv[0]) ;
        return -1 ;
    }
    /* arquivo shadow */
    if( (shadow=fopen(argv[1], "r")) == NULL ) {
        perror(argv[1]) ;
        return -1 ;
    }

    /* wordlist */
    if( (wordlist=fopen(argv[2], "r")) == NULL ) {
        perror(argv[2]) ;
        return -1 ;
    }

    /* Para cada usuário no shadow, a wordlist
     * é lida para tentar quebrar sua senha. */
    while( fgets(linhashadow, BUFSIZ, shadow) ) {
        if ( get_info_shadow(linhashadow, &stshadow) == TRUE ) {
            /* Formato inválido do arquivo shadow. Aqui
             * só ignoramos a linha. */
            if ( !isdigit(stshadow.id[0]) ) {
                continue ;
            } else {
                quebrar_senha(&stshadow, wordlist) ;
            }
        }
    }

    return 0 ;
}

Baixe o código em:

Download qcrack.c (.docx)

Conclusão

Esse programa deve ser usado somente para propósitos educacionais, pois ele não foi criado para ser efetivamente um cracker de senhas. Caso queira um cracker mais sofisticado, procure sobre o John The Ripper.

Referências

[1] Shell Script Para Ataques Brute Force, by Daemonio (Acessado em: Agosto/2011)
https://daemoniolabs.wordpress.com/2011/07/28/shell-script-para-ataques-brute-force/

11 pensamentos sobre “Quebrador De Senhas Em C

  1. Fantastico o seu conhecimento. Estou sendo traida. Queria saber a senha de um email para imprimir alguns emails e provar a traiçao. E possivel vc me ajudar?? Pago pelo seu trabalho. Estou aguardando contato.
    Obrigada

    • Olá Renata,

      infelizmente não posso te ajudar nessa. Um motivo é porque não tenho conhecimento para tal e outro é devido a ilegalidade do ato.

      Um conselho que dou é você não procurar pessoas na Internet para realizar essa invasão, porque você pode ser facilmente enganada. Muitos se dizem “hackers”, mas não passam de aproveitadores.

      Pessoalmente, desejo-lhe sorte nessa investigação e desculpe-me por não poder ajudar.

      Abraços

  2. Sensacionifero.
    O que eu preciso saber em C para que meu executável interaja com a BIOS, por exemplo, e quebre a senha desta?
    Vale a pena frisar que a dificuldade para mim nisto é a interação, não gerar as senhas.

    • Olá Jean,

      não tenho muito conhecimento disso, mas me interessei sobre o assunto. Integrar esse programa na BIOS não será possível porque ele utiliza algoritmos de encriptação específicos. No caso da BIOS tudo deve mudar e claramente parece ser muito mais difícil. Vou dar uma pesquisada e posto alguma coisa aqui se eu achar.
      Abraços

  3. opa tudo bem impressiona-te seu código mas queria saber se e possível criar um link dele entre uma home page que precisa de senha , e rodar o algorítimo na pagina ate desbloquear

    • Sim, é possível. O conceito de ataque de dicionário pode ser estendido a várias outras situações. No caso da home page, devemos saber como é feita a autenticação nela. Cada site utiliza uma linguagem específica, cada uma com rotinas próprias. É bom saber que muitos sites protegem contra esse tipo de ataque, como o uso de captchas e até o bloqueio de seu IP.

      Fique livre em dar mais detalhes sobre sua ideia. Estou aqui caso necessite de ajuda.

      Abraços

  4. Olá, estou tendo problemas para rodar o programa, ele da erro na linha 143 do seu programa desse site, e na linha 129 desse atualizado que vc deixou nos comentarios, voce poderia me ajudar?

  5. Ola, eu queria saber que tem como criar um decodificador, por exemplo, colocar 3 palavra base e testar milhares de combinação e n so pra usuario mas pra outros meios tbm, sei que em alguns casos sao ilegais. mas tem como criar o programa que pode me dar uma lista de senhas compativeis que pode ser com tais palavras?

Deixe um comentário