Assunto: [seguranca] Artigo: armazenamento de senhas no Linux
De: Elgio Schlemer
Data: Wed, 10 Oct 2007 10:46:48 -0300
Para: Seguranca de Sistemas

O Unix, do qual tem-se hoje o Linux como o mais popular,
historicamente armazenava os hashes de senha em formato
DES. Não é exatamente o modelo de conversão BLOCO para
HASH como visto em aula.

1) Hashes DES para Senha Unix (antigo):

A senha devia ser composta de 8 caracteres, não mais
do que oito. Caracteres a mais são truncados e a menos
são preenchidos com caracteres de padding.

Como a senha só pode ter caracteres ascii legíveis,
cada caractere necessariamente será maior que o 32
em decimal (espaço em branco) e menor que 126 (conforme
pode ser constatado pela tabela ASCII).

Sendo assim, dos oito bits de cada caractere, somente
SETE são realmente válidos (o oitavo bit MAIS significativo
será sempre ZERO). Assim para gerar o hash, remove-se o bit
mais significativo e fica-se com 56 bits da senha
(7 bits * 8 caracteres = 56 bits).

Estes 56 bits é que serão usados como chave para cifrar um
bloco com 64 bits em ZERO (bloco padrão, lembre-se, o
algoritmo aqui é o DES) com o salt number usado para perturbar
a encriptação. A etapa de criptar ocorre 25 vezes, sempre
usando a última saída como bloco e a senha como chave (os 56
bits, como dito).

O resultado final é convertido para base64 e armazenado.

A maneira como o salt number é usada (para perturbar
o DES) faz com que o DES original não possa ser usado
para gerar o HASH, sendo uma implementação indepedente.

Nesta versão o salt number são dois caracteres apenas.

2) Hashes MD5 para Senha Unix (depreciado):

Usar o MD5 como hash não requer nenhuma adaptação, pois
o MD5 já é um algoritmo de hash. As senhas do Windows (a
partir do NT, no formato chamado NTPassword), por exemplo,
usam um simples hash MD4 sobre a senha em formato Unicode,
SEM SALT NUMBER, logo duas senhas iguais terão o mesmo
hash. O windows armazena o hash em Hexa Decimal.
(MD5 é uma evolução do MD4)

Mas o Linux tem salt number e pode conviver com mais de um
formato de senha simultâneo.

No caso do Linux, no arquivo de hashes (/etc/shadow)
se o hash começar com $1$ indica que o hash é MD5.
Se começar com $2$ é sha1. Se não começar com $ é o
antigo DES.

No caso de $1$ (ou mesmo $2$) o caractere $ separa
os campos:

$1$ = hash MD5

Apos o $1$ vem o salt number que agora não possui limite
de míseros dois caracteres.

$1$<caracteres de salt number>$<hash da senha>

O hash da senha é armazenado em base64 e não em formato
HEXA (base64 ocupa menos espaço que o HEXA. No HEXA
se usa um caractere para cada 4 bits, em base64 se
usa um caractere para cada 6 bits).

Senhas com hashes MD5 não possuem limitação de tamanho
e nem de valores válidos (pode-se ter senhas com acento,
por exemplo, maior que 126). Alguns SO limitam o tamanho
da senha mais por conveniência de programação mas não
por limitação técnica.

O hash poderia até ser calculado na forma <SALT><SENHA>
e convertido para base64, mas não é!!

O algoritmo é mais obscuro, mas sempre usando o código
do MD5 original. Os passos são basicamente os seguintes:

- calcula-se o hash md5 da senha
- calcula-se o hash md5 do salt number
(tem-se DOIS HASHES agora)
- Depois um novo hash md5 é gerado com os valores de:
   - senha original
   - salt original
   - hash da senha original
   - hash do salt original
- estas etapas acontecem 100 vezes repetidas

Repetir várias vezes o hash não aumenta a segurança do hash em
si, mas torna mais complexo quebrar, pois torna o algoritmo
100 vezes mais lento!

** A IMPORTANCIA DO SALT NUMBER **

É lamentável que para a Microsoft não tenha "caído a ficha" e
continua armazenando hashes sem salt number. Usar os salt torna
muito mais complicado quebrar a senha por bases fixas e inviabiliza
comparar hashes.

A simples palavra "teste", com salt number de apenas 2 caracteres
de salt e se estes caracteres forem APENAS LETRAS (a-zA-Z) possui
a combinação de 2704 hashes (para salt "aa", "ab" ... "Za", "Zb"...)
Isto com apenas DOIS cars considerando que podem ser apenas letras!

Se usar míseros QUATRO caracteres de salt number e se eles forem
apenas letras (26 minusculas + 26 maiusculas) ou  números (10 digitos),
cada letra do salt pode ser uma dentre 62 possíveis combinações.
Usar QUATRO letras significa a combinação de 62 elevado na 4 que
seria 14.776.336.

Em resumo, se alguém quiser armazenar em um BD todos os possíveis
hashes que a palavra "teste" possui e suas variações de salt number
para QUATRO caracteres, teria que armazenar 14 milhões de hashes
pre-compilados. Ainda, isto com QUATRO LETRAS DE SALT!! O padrão do
Linux é usar 8 letras (62 ^ 8 = 218340105584896). Não precisa ser
muito esperto para descobrir o quanto isto aumenta a segurança!

Vamos a prática! Se cada caractere de salt number puder assumir
letras e números, (de A-Z, ou de a-z ou de 0-9) tem-se 62 combinações
de salt possíveis (sem considerar alguns simbolos, como virgulas,
ponto, etc). Ao usar OITO cacateres de salt, um banco de dados
(como o site russo que descobre milagrosamente muitos hashes)
precisa armazenar 218.340.105.584.896 hashes apenas para a palavra
"teste" (e mais a mesma quantidade para "Teste").

O site russo (http://passcracking.ru/) quebrou muito facil
o hash da palavra "teste" mas se tornou incapaz de quebrar
um simples "5teste" !!!

RESUMO DO USO DE SENHAS LINUX

1) Força bruta: 2 na 128, conforme a dificuldade do MD5
O salt number não aumenta o esforço da força bruta, pois
ele é escrito no arquivo.

2) Ataque de livro: este ataque é para acelerar a força
bruta. Nele se pre-compila milhões de hashes MD5 para palavras
fáceis e o ataque é simplesmente comparando o hash com
a base de dados. O Windows é absurdamente perecível por
este ataque (para senhas fáceis, do dicionário).

É ESTE TIPO DE ATAQUE que o salt number frustra por completo.
É este tipo de ataque que o site russo faz!

3) ataque do dicionário e senhas fáceis:
Indenfensável!
Mesmo o melhor algoritmo do mundo vai ser fraco se o idiota
do usuário colocar como senha "123", ou sua placa do carro,
ou uma data de aniversário...
Neste ataque se faz uma tentativa e erro controlada,
considerando palavras de fácil dedução. A IMENSA MAIORIA
de usuários sempre põe senhas de fácil lembrança, não
raro variaçoes de seu próprio nome (senha Elgio2007 :-D)

4) força bruta moderada:
é o que programas como john the ripper faz.
Ao inves de ir no 2^128 tentativas, ele faz tentativas,
mas tentativas dentro de um espaço menor!

Vai pela combinação do que o usuário poderia colocar como
senha. Pode ser:

- letras maiúsculas
- letras minúsculas
- números
- simbolos (virgula, arroba, etc)

Ainda, pode ter tamanho de dezenas de cars!
IMPOSSÍVEl um força bruta em todo este espaço!

Mas se restringir o força bruta para:
- Apenas números: apostando que um usuário só vai por números
como senha. Considerando 10 dígitos de senha, o teste pode
ir de 0000000000 a 9999999999. Isto é viável de ser testado
por força bruta!
- apenas letras minúsculas: usuário, sempre ele. Normalmente
um usuário não põe senhas maiores que 4 cars (pense sobre
as SUAS SENHAS). Um força bruto testando todas as combinações
de aaaa até zzzz é rápido e pense: é óbvio que pegaria MUITA COISA

O mesmo raciocínio para letras maiúsculas.

O que seria, então, uma boa senha?

Muitos caracteres (mais que OITO) e misturando vários tipos
de digitos. Jamais só letras, jamais só números! Uma combinação
de letraas MAI, letras MIN, números e simbolos é IDEAL!!!

Ex:
ayrmz: PÉSSIMO. mesmo sendo ALEATÓRIO, são apenas CINCO letras
e todas minúsculas.

aY9rm.z: MUITO MELHOR. Parecida com a anterior, mas possui letras
MAI, MIN, número e um ponto! PERFEITO.


-- ++++++++++ Elgio Schlemer - Mestre em Ciencia da Computacao +++ Prof. Adj. ULBRA: http://gravatai.ulbra.tche.br/~elgio ........................................................... GnuPG fingerprints: ++++ 1885 DDDD 0834 634D 99C6 96A9 A723 59CD 8841 CE0E ++++ ++++ FA4F 42EE 3E0C 4AF0 6FDE B98C D35E 397B 3C92 F43E ++++