Quebrando A Senha De Arquivos Zip Por Brute Force

Introdução

Frequentemente obtemos arquivos zip com senha e nem fazemos idéia de qual senha foi usada para encriptar esse arquivo. Recuperar o arquivo original sem a devida senha exige métodos complexos de ataque, pois o objetivo desses ataques é direcionado para o algoritmo de encriptação em si, que em muitos casos é muito seguro, como o AES. O que sobra então é o velho método da força bruta em que testamos exaustivamente todas as senhas de uma lista de palavras esperando que uma delas seja igual a senha do arquivo.

Nesse post iremos desenvolver um shell script que realiza ataques de força bruta em arquivos zipados com senha. Em seguida iremos melhorar o desempenho desse script por meio da paralelização com o xargs [3].

O programa unzip

Basicamente, usaremos o programa unzip para realizar nosso ataque. Então, antes de tudo, certifique-se de o unzip de sua distribuição é compatível com o que eu estou usando.

As opções usadas aqui serão a -P (ou –password), -t, e -q.

$ man unzip
....
   -P password
       use  password  to  decrypt encrypted zipfile entries (if any).  THIS IS INSECURE!
....
$ zip --help
....
-t  test compressed archive data
....
-q  quiet mode (-qq => quieter)
....

A versão que estou usando é a:

$ unzip -v
UnZip 6.00 of 20 April 2009, by Info-ZIP.  Maintained by C. Spieler.
.....
Compiled with gcc 4.6.0 20110205 (Red Hat 4.6.0-0.6) for Unix (Linux ELF) on Feb  8 2011.
.....

O método

O método de descobrir a senha por força bruta não é nada complexo e usaremos o próprio programa unzip para isso.

Vamos elaborar o método aos poucos, fazendo testes em alguns arquivos zip. Primeiro criamos um zip com senha de nome arquivozipcomsenha.zip:

# Criamos o arquivo arquivozipcomsenha.zip que compacta um arquivo qualquer (ex: /etc/passwd).
# A senha do zip é `minhasenha123'
$ zip -P minhasenha123 /etc/passwd arquivozipcomsenha.zip
adding: etc/passwd (deflated 61%)

Vamos tentar unzipar esse arquivo com uma senha inválida:

$ unzip -P senhaerrada arquivozipcomsenha.zip
Archive:  arquivozipcomsenha.zip
   skipping: etc/passwd              incorrect password

agora com a senha correta:

$ unzip -P minhasenha123 arquivozipcomsenha.zip
Archive:  arquivozipcomsenha.zip
  inflating: etc/passwd

Pelas duas saídas anteriores obtemos um padrão para diferenciar quando uma senha está correta ou não: Se a saída contém a string “incorrect password”, a senha passada está incorreta. Caso contrário a senha está correta. Embora esse padrão seja bom ele não é muito rápido, pois o unzip pode tentar extrair um arquivo mesmo a senha estando errada (mais detalhes disso em [1]). Isso então me motivou a procurar um modo mais rápido para essa verificação e acabei encontrando na man page[1] do programa as opções -t e -q. Veja:

$ man unzip
  To test letters.zip, printing only a summary message indicating
  whether the archive is OK or not:
     unzip -tq letters

O que a opção -t faz é testar a integridade do arquivo zip sem a necessidade de extrair seu conteúdo. Vejamos:

# Senha inválida
$ unzip -tq -P senhainvalida arquivozipcomsenha.zip
Caution:  zero files tested in arquivozipcomsenha.zip.
1 file skipped because of incorrect password.

# Senha correta
$ unzip -tq -P minhasenha123 arquivozipcomsenha.zip
No errors detected in compressed data of arquivozipcomsenha.zip.

Com esse novo método mais rápido de se testar a validade de uma senha, podemos elaborar um método geral para o ataque de força bruta:

1) Se há palavras no dicionário para ler:
   Leia uma palavra do dicionário de palavras para a variável senhateste.
2) Execute: unzip -tq -P senhateste arquivozipcomsenha.zip.
3) Verifique se a saída contém a string "No errors detected in comprressed data of".
   Se sim: a senha do arquivo é senhateste e finalize o processo.
4) Volte para o passo 1.

Esse procedimento pode ser implementado em qualquer linguagem de programação, só que aqui montaremos um shell script.

O script: quebrazip.sh

Esse script recebe o arquivo zipado no primeiro parâmetro e o dicionário de palavras no segundo.

#!/bin/bash
# [quebrazip.sh]
# Quebra senha de arquivos zip pelo método
# da força bruta.
#
# [Autor]
# Marcos Paulo Ferreira (Daemonio)
# undefinido gmail com
# https://daemoniolabs.wordpress.com
#
# [Uso]
# $ ./quebrazip.sh arquivozipcomsenha.zip wordlist.txt
# ....
# ....
# Senha: "senha"
#
# Versão 1.0, by daemonio @ Sun May 27 11:35:02 BRT 2012
#

# Arquivo zip com senha
ARQUIVOZIP=

# Dicionário de senhas
WORDLIST=

# Recebe cada senha do dicionário
senhateste=

# Função de ajuda.
function show_help {
echo 'quebrazip.sh - by daemonio'
echo '[uso] $ ./quebrazip.sh arquivozipcomsenha.zip wordlist.txt'
exit 1
}

# Função chamada quando se interrompe
# o script com um ctrl+c. Essa função mostra
# a senha usada no momento da interrupção.
function pegarctrlc {
echo "[+] Processo abortado. Senha atual: $senhateste"
exit 1
}

# Instala um signal handler pro ctrl+c
trap pegarctrlc SIGINT

# Obtém os parâmetros.
ARQUIVOZIP="$1"
WORDLIST="$2"

# Flag. Tem valor 1 se a senha foi quebrada e
# 0 caso contrário.
SENHAQUEBRADA=0

# Testa os parâmetros.
[ -e "$ARQUIVOZIP" ] && [ -e "$WORDLIST" ] || show_help

# Processo de quebragem.
echo '[+] Espere. Quebrando a senha...'
while read senhateste
do
    SAIDA=$(unzip -tq -P "$senhateste" "$ARQUIVOZIP" 2>&1)
    [[ "$SAIDA" =~ 'No errors detected in compressed data of' ]] && SENHAQUEBRADA=1 && break
done < "$WORDLIST"

# Informa se a senha foi quebrada ou não.
if [ "$SENHAQUEBRADA" = '1' ]
then
    echo '[+] Senha quebrada: '$senhateste
else
    echo '[+] Senha NAO quebrada. Tente outra lista de palavras.'
fi

#EOF

A seguir um pequeno teste:

# Senha: 45312
$ zip -P 45312 arquivozipcomsenha.zip /etc/passwd

# Gera uma wordlist usando o brutus.sh. Baixe
# esse script na referência [2].
$ ./brutus.sh -c 12345 -r 5 > senhas.txt

# Executa o quebrazip.sh
$ ./quebrazip.sh arquivozipcomsenha.zip senhas.txt
[+] Espere. Quebrando a senha...
[+] Senha quebrada: 45312

Paralelizar?

Sabemos por [3] que podemos paralelizar as execuções de determinado programa usando o comando xargs. Utilizaremos dessa técnica para acelerar o processo de força bruta, e para isso teremos que modificar o script quebrazip.sh. A diferença agora é que o novo script receberá as senhas pela linha de comando e não por uma lista de palavras.

#!/bin/bash
# [xquebrazip.sh]
# Quebra senha de arquivos zip pelo método
# da força bruta.
#
# [Autor]
# Marcos Paulo Ferreira (Daemonio)
# undefinido gmail com
# https://daemoniolabs.wordpress.com
#
# [Uso]
# $ ./xquebrazip.sh arquivozipcomsenha.zip senha1, senha2, ..., senhaN
# ....
# ....
# Senha: "senha"
#
# Versão 1.0, by daemonio @ Sun May 27 12:11:02 BRT 2012
#

# Função de ajuda.
function show_help {
echo 'xquebrazip.sh - by daemonio'
echo '[uso] $ ./quebrazip.sh arquivozipcomsenha.zip senha1, senha2, ..., senhaN'
exit 1
}

# Obtém os parâmetros.
ARQUIVOZIP="$1"

# Flag. Tem valor 1 se a senha foi quebrada e
# 0 caso contrário.
SENHAQUEBRADA=0

# Testa os parâmetros.
[ -e "$ARQUIVOZIP" ] || show_help

# Desloca os parâmetros.
shift

# Lê as senhas da linha de comando.
for senhateste in $*
do
    SAIDA=$(unzip -tq -P "$senhateste" "$ARQUIVOZIP" 2>&1)
    [[ "$SAIDA" =~ 'No errors detected in compressed data of' ]] && SENHAQUEBRADA=1 && break
done

# Informa se a senha foi quebrada ou não.
if [ "$SENHAQUEBRADA" = '1' ]
then
    echo '[+] Senha quebrada: '$senhateste
    # Executando esse script no xargs precisamos matar
    # o próprio xargs (processo pai) para finalizar as
    # outras threads.
    kill $PPID
fi

#EOF

Testando:

$ cat senhas.txt | xargs -n 20 -P 10 ./xquebrazip.sh arquivozipcomsenha.zip
[+] Senha quebrada: 45312
Terminated.

O xargs criará 10 threads (parâmetro -P) e cada uma receberá 20 senhas (parâmetro -n).

Comparando os tempos de execução

Teoricamente a versão paralela do nosso cracker deve ter um tempo de execução menor do que a versão sequencial. Isso é verdade para um número razoável de senhas na wordlist, porque para entradas pequenas a diferença de tempo é muito pequena. O problema é que o tempo de execução da versão paralela depende também dos processos cat e xargs e para entradas pequenas, esse tempo é bem considerável.

Para mostrar que a versão paralela é mais rápida em alguns casos, executei esses dois scripts com uma wordlist maior, e medindo o tempo de execução com o comando time.

# Senha: 9999
$ zip -P 9999 arquivozipcomsenhazip.zip /etc/passwd 

# Wordlist com 10^5 senhas
$ ./brutus.sh -d -r 5 > senhas2txt

# Tempo para a versão sequencial
$ time ./quebrazip.sh arquivozipcomsenha.zip senhas2.txt
[+] Espere. Quebrando a senha...
[+] Senha quebrada: 99999

real    8m37.681s
user    1m27.752s
sys     5m38.155s

# Tempo para a versão paralela.
# (10 threads)
$ time cat senhas2.txt | xargs -n 20 -P 10 ./xquebrazip.sh arquivozipcomsenha.zip
[+] Senha quebrada: 99999
Terminated

real    3m57.972s
user    1m15.832s
sys     4m11.389s

Obviamente esses tempos podem mudar de sistema para sistema. O importante aqui é que a paralelização se mostrou muito eficiente na redução do tempo de execução. E outra, ajeitando o parâmetro -P do xargs para um número razoavelmente grande, de modo que não se onere o processo, o tempo de execução diminuirá mais ainda.

Conclusão

Métodos de força bruta para descobrir senhas estão disponíveis praticamente em qualquer situação. A desvantagem desses métodos é que a quantidade de tempo total gasto neles é muito grande. Nesse post vimos como realizar um simples ataque de força bruta utilizando o próprio programa unzip. Para reduzir o tempo do ataque, utilizamos opções de validação mais rápidas fornecidas pelo próprio comando e, no final, tiramos vantagem da paralelização de processos.

Outro modo de agilizar o ataque seria olhar a estrutura interna dos arquivos zip e encontrar campos específicos que estão relacionados com a verificação da senha. Desse modo abandonamos de vez a nossa dependência do programa unzip, que influencia bastante no tempo de execução. Mas isso é assunto para outro post, quem sabe mais na frente (se você tiver algum material sobre isso, poste nos comentários). :D

Referências

[1] Man page do unzip (Acessado em: Maio/2012)
$ man unzip

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

[3] Paralelismo com o xargs, by Daemonio (Acessado em: Maio/2012)
https://daemoniolabs.wordpress.com/2012/04/07/paralelismo-com-o-xargs/

2 pensamentos sobre “Quebrando A Senha De Arquivos Zip Por Brute Force

  1. Pingback: Quebrando A Senha De Arquivos Rar Por Brute Force | Daemonio Labs

  2. Pode-se retirar o UUOC e fazer:

    $ xargs -n 20 -P 10 ./xquebrazip.sh arquivozip < senhas.txt

    acredito que o tempo de execução caia ainda mais devido a diminuição do processo desnecessário.

    Outro detalhe é que se o zip estiver usando criptografia “forte” (ex: AES-256) então o unzip não irá rodar, já que ele não dá suporte. A solução é usar a suíte p7zip de modo semelhante ao que vimos aqui. Não irei abordar essa solução, então deixarei essa tarefa para o leitor;

Deixe um comentário