Obter impressão digital da chave do servidor SSH

82

Existe uma maneira de obter programaticamente uma impressão digital de chave do servidor SSH sem autenticar nela?

Estou tentando ssh -v user@host false 2>&1 | grep "Server host key", mas isso trava aguardando uma senha se a autenticação baseada em chave não estiver configurada.

goncalopp
fonte

Respostas:

71

Você pode fazer isso combinando ssh-keyscane ssh-keygen:

$ file=$(mktemp)
$ ssh-keyscan host > $file 2> /dev/null
$ ssh-keygen -l -f $file
521 de:ad:be:ef:de:ad:be:ef:de:ad:be:ef:de:ad:be:ef host (ECDSA)
4096 8b:ad:f0:0d:8b:ad:f0:0d:8b:ad:f0:0d:8b:ad:f0:0d host (RSA)
$ rm $file

(infelizmente, o mais simples ssh-keyscan host | ssh-keygen -l -f /dev/stdinnão funciona)

Andreas Wiese
fonte
1
Talvez ssh-keygen -l -f - <(ssh-keyscan host)sim?
um CVn
21
O OpenSSH> = 7.2 ssh-keyscan é capaz de ler a partir de stdin:ssh-keyscan host | ssh-keygen -lf -
mykhal 4/16/16
1
Apenas faça:ssh-keygen -l -f <(ssh-keyscan host)
Christopher
1
Essa é uma expressão bastante ruim para scripts de shell, pois depende de um shell que o suporta, o que o shell POSIX não suporta.
Andreas Wiese
2
ssh-keygen -l -f -funciona da forma esperada no ssh-keygen 7.2 e superior. Ele produz algumas linhas de comentário para STDERR que podem ser filtradas, conforme mencionado na resposta de Anthony Geoghegan oussh-keyscan host 2>/dev/null | ssh-keygen -l -f -
Cedric Knight
56

Recentemente, eu mesmo fiz isso, então pensei em adicionar uma resposta que mostra como isso pode ser feito (com versões do OpenSSH 7.2 ou mais recente ) em uma linha usando a substituição de processo:

ssh-keygen -lf <(ssh-keyscan hostname 2>/dev/null)

O texto a seguir explica como esses comandos funcionam e destaca algumas das diferenças de comportamento entre versões mais antigas e mais recentes dos utilitários OpenSSH.

Buscar chaves de host público

O ssh-keyscancomando foi desenvolvido para que os usuários possam obter chaves de host públicas sem precisar se autenticar no servidor SSH. Na sua página de manual:

ssh-keyscané um utilitário para reunir as chaves públicas do host ssh de vários hosts. Foi desenvolvido para auxiliar na construção e verificação de ssh_known_hostsarquivos.

Tipo de chave

O tipo de chave a ser buscada é especificado usando a -topção

  • rsa1 (Protocolo SSH obsoleto versão 1)
  • rsa
  • dsa
  • ecdsa (versões recentes do OpenSSH)
  • ed25519 (versões recentes do OpenSSH)

Nas versões modernas do OpenSSH, os tipos de chave padrão a serem buscados são rsa (desde a versão 5.1), ecdsa(desde a versão 6.0) e ed25519(desde a versão 6.7).

Com versões mais antigas de ssh-keyscan(antes OpenSSH versão 5.1), o padrão tipo de chave foi o datada-out rsa1(SSH Protocolo 1) para os principais tipos precisaria ser explicitamente especificadas:

ssh-keyscan -t rsa,dsa hostname

Obter hashes de impressão digital das chaves Base64

ssh-keyscanimprime a chave do host do servidor SSH no formato codificado em Base64 . Para converter isso em um hash de impressão digital, o ssh-keygenutilitário pode ser usado com a -lopção de imprimir a impressão digital da chave pública especificada.

Se você estiver usando o Bash, o Zsh (ou o shell Korn), a substituição do processo pode ser usada para uma única linha:

ssh-keygen -lf <(ssh-keyscan hostname 2>/dev/null)

Nota : Nas versões do OpenSSH anteriores à 7.2, as funções usadas ssh-keygenpara ler arquivos não processavam muito bem os pipes nomeados (FIFOs), portanto esse método não funcionava, exigindo o uso de arquivos temporários.

Algoritmos de hash

Versões recentes dos hashes de ssh-keygenimpressão digital SHA256 das teclas. Para obter hashes MD5 das impressões digitais da chave do servidor (o comportamento antigo), a -E opção pode ser usada para especificar o algoritmo de hash:

ssh-keygen -E md5 -lf <(ssh-keyscan hostname 2>/dev/null)

Usando um pipeline

Se estiver usando um shell POSIX (como dash) que não possui substituição de processo, as outras soluções que usam arquivos temporários funcionarão. No entanto, com as versões mais recentes do OpenSSH (desde 7.2), um pipeline simples pode ser usado, pois ssh-keygenaceita -como um nome de arquivo para o fluxo de entrada padrão, permitindo um comando de pipeline de uma linha.

ssh-keyscan hostname 2>/dev/null | ssh-keygen -E md5 -lf -
Anthony Geoghegan
fonte
Resposta agradável e completa, isso é certamente melhor do que ter um arquivo temporário! Posso sugerir que você forneça um TL; DR no início com a versão de substituição de processo, para fazer com que pessoas impacientes o encontrem mais rapidamente? :)
goncalopp
3
Não parece funcionar no Ubuntu 14.04 LTS; Recebo um erro "/ dev / fd / 63 não é um arquivo de chave pública". O subprocesso funciona.
quer
@elleb Encontrei a mesma coisa em um sistema 12.04 ao qual tenho acesso. Eu suspeito que, ssh-keygennas versões mais antigas do OpenSSH, tenha um problema ao ler o FIFO / pipe nomeado. Vou analisar isso (e atualizar minha resposta) quando tiver algum tempo livre.
Anthony Geoghegan
3
@melleb Depois de passar muito tempo baixando várias versões de código-fonte e inserindo printfinstruções de depuração na do_fingerprint()função, descobri que nas versões do OpenSSH anteriores à 7.2, as funções usadas ssh-keygenpara ler arquivos, não tratavam muito bem os pipes nomeados (FIFOs), então o método de substituição do processo não funcionaria.
Anthony Geoghegan
Isso funciona, mas se você usá-lo para verificar uma impressão digital, os usuários devem estar cientes de que há uma condição de corrida: a impressão digital que você está verificando com este comando não é necessariamente a da chave que você busca, a menos que você a solte antes de chamar ssh- keygen nele.
CodeGnome 31/08
20

nmapfornece essa capacidade usando o ssh-hostkeyscript

Para retornar a impressão digital hexadecimal da chave:

$ nmap [SERVER] --script ssh-hostkey

Para retornar o conteúdo da chave:

$ nmap [SERVER] --script ssh-hostkey --script-args ssh_hostkey=full

Para retornar o balão visual da chave

$ nmap [SERVER] --script ssh-hostkey --script-args ssh_hostkey='visual bubble'

Para retornar todas as opções acima:

$ nmap [SERVER] --script ssh-hostkey --script-args ssh_hostkey=all

Fonte: nmap docs

Riacho
fonte
3
Esses exemplos pressupõem que o SSH esteja sempre em execução na porta 22? E se o ssh escutar em uma porta não padrão?
Martin Vegter 01/12/14
3
@MartinVegter (parafraseando Guarin42, que não podia comentar :) O nmap tem a -popção que pode especificar uma porta, por exemplo -p 22000. Também é possível usar a -vvopção de aumentar a verbosidade (quantidade de informação dada)
goncalopp
2

O filezilla exibe chaves com hash com md5 no formato hexadecimal .

Para encontrar isso na sua máquina Linux Linux , use este comando:

ssh-keygen -l -E md5 -f <(ssh-keyscan localhost 2>/dev/null)

nota: substitua "localhost" pelo ip da máquina que você deseja verificar.

Cameron
fonte
1

Aqui está um script de shell (principalmente shell Bourne, mas usando a localpalavra-chave, disponível na maioria dos modernos /bin/sh) que escrevi para fazer isso. Use-o como ssh-hostkey hostname. Ele mostrará as impressões digitais nos formatos sha256 e md5 para todas as chaves do host para o nome do host ou endereço IP fornecido. Você também pode especificar manualmente " md5" ou " sha256" como o segundo argumento para mostrar apenas esse formato específico.

Ele usa um arquivo temporário em vez de canalizar para torná-lo compatível com pacotes OpenSSH mais antigos (conforme descrito em outras respostas). O arquivo temporário usa /dev/shm(memória compartilhada), se disponível.

#!/bin/sh
usage () {
  printf '%s\n' "Usage: ssh-hostkey HOSTNAME [FPRINTHASH]"
}

ssh_hostkey () {
  local host="$1"
  local fprinthash="$2"
  local tmp=

  case "$host" in
    -h|--help|'')
      usage >&2
      return 1
      ;;
  esac

  case "$fprinthash" in
    md5|sha256|'') true;;
    *)
      usage >&2
      printf '%s\n' "Fingerprint hash may be 'md5' or 'sha256'" >&2
      return 2
      ;;
  esac

  if test -d /dev/shm
  then tmp="$(mktemp -d -p /dev/shm)"
  else tmp="$(mktemp -d)"
  fi

  trap 'trap - INT TERM EXIT; rm -rf "$tmp"' INT TERM EXIT
  ssh-keyscan "$host" > "$tmp/f" 2> /dev/null
  case "$fprinthash" in
    sha256|'') ssh-keygen -l -f "$tmp/f" 2> /dev/null;;
  esac
  case "$fprinthash" in
    md5|'') ssh-keygen -l -E md5 -f "$tmp/f" 2> /dev/null;;
  esac

  trap - INT TERM EXIT
  rm -rf "$tmp" > /dev/null 2>&1
}

ssh_hostkey "$@"
ejm
fonte