Como você quer fazer isso em um shell script, algumas contribuições em Como verificar senha com o Linux? (em Unix.SE , sugerido pelo AB ) são especialmente relevantes :
-
rozcietrzewiacz 's responder ao gerar um hash de senha que corresponde a uma entrada em
/etc/shadow
fornece parte da solução. -
Daniel Alder 's comentário explica a sintaxe diferente do
mkpasswd
comando presente no Debian (e no Ubuntu).
Para verificar manualmente se uma string é realmente a senha de algum usuário, você deve usar o mesmo algoritmo de hash da entrada de sombra do usuário, com a mesma salt como na entrada de sombra do usuário. Então pode ser comparado com o hash de senha armazenado lá.
Eu escrevi um script completo e funcional demonstrando como fazer isso.
- Se você nomear
chkpass
, poderá executarchkpass user
e ele lerá uma linha da entrada padrão e verificará se ela é a senha deuser
. - Instale o whois pacote para obter o utilitário
mkpasswd
do qual esse script depende. - Este script deve ser executado como root para ter sucesso.
- Antes de usar este script ou qualquer parte dele para fazer um trabalho real, consulte Notas de segurança abaixo.
#!/usr/bin/env bash
xcorrect=0 xwrong=1 enouser=2 enodata=3 esyntax=4 ehash=5 IFS=$
die() {
printf '%s: %s\n' "set -f; ent=($(getent shadow "" | awk -F: '{print }')); set +f
" "" >&2
exit
}
report() {
if (( == xcorrect))
then echo 'Correct password.'
else echo 'Wrong password.'
fi
exit
}
(($# == 1)) || die $esyntax "Usage: $(basename "if [[ "${ent[*]}" = "$(mkpasswd -sm $hashtype -S "${ent[2]}" <<<"$pass")" ]]
") <username>"
case "$(getent passwd "" | awk -F: '{print }')" in
x) ;;
'') die $enouser "error: user '' not found";;
*) die $enodata "error: 's password appears unshadowed!";;
esac
if [ -t 0 ]; then
IFS= read -rsp "[$(basename "%pre%")] password for : " pass
printf '\n'
else
IFS= read -r pass
fi
set -f; ent=($(getent shadow "" | awk -F: '{print }')); set +f
case "${ent[1]}" in
1) hashtype=md5;; 5) hashtype=sha-256;; 6) hashtype=sha-512;;
'') case "${ent[0]}" in
\*|!) report $xwrong;;
'') die $enodata "error: no shadow entry (are you root?)";;
*) die $enodata 'error: failure parsing shadow entry';;
esac;;
*) die $ehash "error: password hash type is unsupported";;
esac
if [[ "${ent[*]}" = "$(mkpasswd -sm $hashtype -S "${ent[2]}" <<<"$pass")" ]]
then report $xcorrect
else report $xwrong
fi
Notas de segurança
Pode não ser a abordagem correta.
Se uma abordagem como essa deve ou não ser considerada segura e apropriada depende de detalhes sobre o caso de uso que você não forneceu (até o momento).
Não foi auditado.
Embora eu tenha tentado tomar cuidado ao escrever este script, ele não foi devidamente auditado para vulnerabilidades de segurança . Ele é uma demonstração e seria um software "alfa" se lançado como parte de um projeto. Além disso ...
Outro usuário que está "assistindo" pode descobrir o sal do usuário.
Devido a limitações em como mkpasswd
aceita dados de salt, este script contém uma falha de segurança conhecida , que você pode ou não considerar aceitável dependendo do caso de uso. Por padrão, os usuários no Ubuntu e na maioria dos outros sistemas GNU / Linux podem visualizar informações sobre processos executados por outros usuários (incluindo root), incluindo seus argumentos de linha de comando. Nem a entrada do usuário nem o hash da senha armazenada são passados como um argumento de linha de comando para qualquer utilitário externo. Mas o salt , extraído do banco de dados shadow
, é dado como um argumento de linha de comando para mkpasswd
, já que esta é a única maneira que o utilitário aceita um sal como entrada.
Se
- outro usuário no sistema, ou
- qualquer pessoa que tenha a capacidade de criar uma conta de usuário (por exemplo,
www-data
) execute o código, ou - qualquer pessoa que, de outra forma, possa visualizar informações sobre processos em execução (incluindo inspecionar manualmente as entradas em
/proc
)
é capaz de verificar os argumentos da linha de comando para mkpasswd
enquanto é executado por este script, então eles podem obter uma cópia do salt do usuário do banco de dados shadow
. Eles podem ter que ser capazes de adivinhar quando esse comando é executado, mas isso às vezes é possível.
Um atacante com seu sal não é tão ruim quanto um atacante com seu sal e hash , mas não é o ideal. O sal não fornece informações suficientes para que alguém descubra sua senha. Mas permite que alguém gere tabelas de arco-íris ou hashes de dicionário pré-computados específicos desse usuário nesse sistema. Isto é inicialmente inútil, mas se a sua segurança for comprometida mais tarde e o hash completo for obtido, então poderá ser cracked mais rapidamente para obter a senha do usuário antes que eles tenham a chance de alterá-la.
Assim, esta falha de segurança é um fator exacerbante em um cenário de ataque mais complexo do que uma vulnerabilidade totalmente explorável. E você pode considerar a situação acima forçada. Mas estou relutante em recomendar qualquer método para uso geral no mundo real que vaze qualquer dados não públicos de /etc/shadow
para um usuário não-root.
Você pode evitar esse problema completamente:
- escrevendo parte do seu script em Perl ou em algum outro idioma que permita chamar funções em C, como mostrado na resposta de Gilles para a questão Unix.SE relacionada , ou
- escrevendo todo o seu script / programa em tal linguagem, ao invés de usar o bash. (Com base na maneira como você marcou a pergunta, parece que você prefere usar o bash.)
Cuidado como você chama esse script.
Se você permitir que um usuário não confiável execute esse script como root ou execute qualquer processo como root que chame esse script, tenha cuidado . Alterando o ambiente, eles podem fazer este script - ou qualquer script que é executado como root - qualquer coisa . A menos que você possa evitar que isso ocorra, você não deve permitir privilégios elevados aos usuários para executar scripts de shell.
Veja 10.4. Linguagens de script Shell (derivadas sh e csh) em Programação segura para Linux e Unix HOWTO para mais informações sobre isso. Embora sua apresentação se concentre em scripts setuid, outros mecanismos podem ser afetados por alguns dos mesmos problemas se não limparem corretamente o ambiente.
Outras Notas
Ele suporta a leitura de hashes apenas do banco de dados shadow
.
As senhas devem ser sombreadas para que esse script funcione (ou seja, seus hashes devem estar em um arquivo /etc/shadow
separado que somente o root possa ler, não em /etc/passwd
).
Este sempre deve ser o caso no Ubuntu. Em qualquer caso, se necessário, o script pode ser trivialmente estendido para ler os hashes de senha de passwd
, bem como shadow
.
Tenha em mente IFS
ao modificar este script.
Eu defino IFS=$
no começo, já que os três dados no campo hash de uma entrada de sombra são separados por $
.
- Eles também têm um
$
líder, e é por isso que o tipo de hash e o sal são"${ent[1]}"
e"${ent[2]}"
, em vez de"${ent[0]}"
e"${ent[1]}"
, respectivamente.
Os únicos locais nesse script em que $IFS
determina como o do shell é dividido ou combina palavras são
-
quando esses dados são divididos em uma matriz, inicializando-os a partir da substituição do comando
%pre%$(
)
sem aspas em: -
quando a matriz é reconstituída em uma string para comparar com o campo completo de
%pre%shadow
, a expressão"${ent[*]}"
em:
Se você modificar o script e fazer com que ele execute a divisão de palavras (ou a junção de palavras) em outras situações, será necessário definir IFS
para valores diferentes para comandos diferentes ou partes diferentes do script.
Se você não tiver isso em mente e assumir que $IFS
está definido para o espaço em branco normal ( $' \t\n'
), você pode acabar fazendo com que seu script se comporte de maneiras bem estranhas.