Como garantir que o tempo em si não engane, se você tem milhões de dispositivos grandes e pequenos se comunicando via TCP/IP? Afinal, cada um deles possui um relógio, e o tempo deve ser preciso em todos. Não é possível contornar esse problema sem o NTP.
Vamos imaginar por um momento que em um segmento da infraestrutura de TI industrial surgiram dificuldades para sincronizar os serviços pelo tempo. Imediatamente, o stack de software empresarial começa a falhar, domínios se quebram e nós mestres e standby lutam em vão para restaurar o status quo.
Pode haver também uma situação em que um invasor tenta intencionalmente desestabilizar o tempo por meio de um ataque MiTM ou DDoS. Nessa situação, tudo pode acontecer:
- a validade das senhas das contas de usuários expirará;
- a validade dos certificados X.509 expirará;
- a autenticação de dois fatores TOTP deixará de funcionar;
- os backups se tornarão "obsoletos" e o sistema os excluirá;
- o DNSSec falhará.
É evidente que cada departamento de TI está interessado no funcionamento confiável dos serviços de sincronização de tempo, e seria bom que eles fossem seguros e confiáveis na operação industrial.
Quebrar o NTP em 25 minutos
Os protocolos de rede — os millennials têm uma característica, eles existem há muito tempo e já não servem mais, mas substituí-los não é fácil, mesmo quando há uma massa crítica de entusiastas e financiamento.
A principal crítica ao NTP clássico é a ausência de mecanismos de proteção confiáveis contra ataques de invasores. Foram feitas diversas tentativas para resolver esse problema. Para isso, inicialmente foi implementado o mecanismo de chaves pré-estabelecidas (PSK) para a troca de chaves simétricas.
Infelizmente, esse método não se mostrou eficaz devido a uma razão simples — ele não escala bem. É necessário configurar manualmente do lado do cliente, dependendo do servidor. Isso significa que não é tão simples adicionar mais um cliente. Se algo muda no servidor NTP, todos os clientes precisam ser reconfigurados.
Então, surgiu o AutoKey, mas logo foram descobertas várias vulnerabilidades significativas no próprio design do algoritmo, e foi necessário abandoná-lo. O problema é que o número inicial (seed) contém apenas 32 bits, o que é muito pouco e não oferece complexidade computacional suficiente para um ataque direto.
- ID da chave — uma chave simétrica de 32 bits;
- MAC (código de autenticação de mensagem) — soma de verificação do pacote NTP;
O Autokey é calculado da seguinte forma.
Autokey=H(Sender-IP||Receiver-IP||KeyID||Cookie)Onde H() — função de hash criptográfico.
Para calcular a soma de verificação, usa-se a mesma função para os pacotes.
MAC=H(Autokey||pacote NTP)Dessa forma, toda a integridade das verificações dos pacotes depende da autenticidade dos cookies. Se alguém conseguir controlá-los, poderá recuperar o autokey e, em seguida, falsificar o MAC. No entanto, o servidor NTP utiliza um número inicial (seed) ao gerá-los. É aqui que está o truque.
Cookie=MSB_32(H(Client IP||Server IP||0||Server Seed))A função MSB_32 corta os 32 bits mais significativos do resultado do cálculo do hash MD5. O cookie do cliente não muda enquanto os parâmetros do servidor permanecem inalterados. Depois disso, o invasor só precisa recuperar o número inicial e obter a capacidade de gerar cookies por conta própria.
Para começar, é necessário conectar-se ao servidor NTP como cliente e obter os cookies. Em seguida, através de um método de força bruta, o invasor recupera o número inicial seguindo um algoritmo simples.
Algoritmo de ataque para a recuperação do número inicial por força bruta.
for i=0:2^32 − 1 do
Ci=H(Server-IP||Client-IP||0||i)
if Ci=Cookie then
return i
end if
end forOs endereços IP são conhecidos, então só resta criar 2^32 hashes até que o cookie gerado corresponda ao que foi obtido do servidor NTP. Em uma estação doméstica comum com Intel Core i5, isso levará 25 minutos.
NTS — novo Autokey
Era impossível conviver com tais falhas de segurança do Autokey e, em 2012, surgiu o protocolo. Para evitar um nome comprometedor, foi decidido fazer um rebranding, assim o Autokey v.2 foi chamado de Network Time Security.
O protocolo NTS é uma extensão de segurança do NTP e atualmente suporta apenas o modo unicast. Ele oferece uma proteção criptográfica confiável contra manipulações de pacotes, previne rastreamento, é bem escalável, resistente à perda de pacotes e resulta em mínimas perdas de precisão ocorrendo durante a proteção da conexão.
A conexão NTS consiste em duas etapas, nas quais são utilizados protocolos de nível inferior. Na primeira etapa, o cliente e o servidor negociam vários parâmetros de conexão e trocam cookies contendo as chaves junto com todo o conjunto de dados associado. Na segunda etapa, ocorre a própria sessão NTS protegida entre o cliente e o servidor NTP.

NTS é composto por dois protocolos de baixo nível: Network Time Security Key Exchange (NTS-KE), que inicializa uma conexão segura sobre TLS, e NTPv4 — a última encarnação do protocolo NTP. Um pouco mais sobre isso abaixo.
Primeira fase — NTS KE
Nesta fase, o cliente NTP inicia uma sessão TLS 1.2/1.3 através de uma conexão TCP separada com o servidor NTS KE. Durante essa sessão, ocorre o seguinte.
- As partes determinam os parâmetros do algoritmo para a segunda fase.
- As partes determinam o segundo protocolo de baixo nível, mas no momento apenas o NTPv4 é suportado.
- As partes determinam o endereço IP e a porta do servidor NTP.
- O servidor NTS KE emite cookies sob o NTPv4.
- As partes extraem do material do cookie um par de chaves simétricas (C2S e S2C).
Essa abordagem tem uma grande vantagem, pois toda a carga de transmissão da informação secreta dos parâmetros da conexão recai sobre um protocolo TLS confiável e testado. Dessa forma, não é necessário reinventar a roda para um handshake NTP seguro.
Segunda fase — NTP protegido pelo NTS
Na segunda fase, o cliente sincroniza o tempo de forma segura com o servidor NTP. Para isso, ele transmite quatro extensões especiais (campo de extensão) na estrutura do pacote NTPv4.
- A Extensão de Identificador Único contém um nonce aleatório para prevenir ataques de repetição.
- A Extensão de Cookie NTS contém um dos cookies NTP disponíveis para o cliente. Como apenas o cliente possui as chaves simétricas AAED C2S e S2C, o servidor NTP deve extrair essas chaves do material do cookie.
- A Extensão de Placeholder de Cookie NTS é uma maneira para o cliente solicitar cookies adicionais do servidor. Esta extensão é necessária para que a resposta do servidor NTP não seja muito mais longa do que a solicitação. Isso ajuda a prevenir ataques de amplificação.
- A Extensão de Campos de Autenticador NTS e Encrypted Extension Fields contém um algoritmo de cifra AAED com a chave C2S, cabeçalho NTP, timestamps e os mencionados EF como dados auxiliares. Sem essa extensão, as timestamps podem ser forjadas.

Ao receber uma solicitação do cliente, o servidor verifica a autenticidade do pacote NTP. Para isso, ele deve descriptografar o cookie, extrair o algoritmo AAED e as chaves. Após verificar a validade do pacote NTP, o servidor responde ao cliente no seguinte formato.
- A Extensão de Identificador Único é uma cópia espelhada da solicitação do cliente, uma medida contra ataques de repetição.
- A Extensão de Cookie NTS fornece mais cookies para continuar a sessão.
- A extensão NTS Authenticator e Campos de Extensão Criptografados contém um cifrador AEAD com chave S2C.
A segunda troca de chaves pode ser repetida muitas vezes, pulando a primeira etapa, pois cada solicitação e resposta fornece ao cliente cookies adicionais. Isso oferece a vantagem de que operações TLS relativamente intensivas em recursos para cálculos e transmissão de dados PKI são divididas entre o número de solicitações repetidas. Isso é especialmente conveniente para cronômetros FPGA especializados, onde toda a funcionalidade principal pode ser empacotada em várias funções de criptografia simétrica, transferindo toda a pilha TLS para outro dispositivo.
NTPSec
Qual é a especialidade do NTP? Embora o autor do projeto, Dave Mills, tenha se esforçado para documentar seu código da melhor maneira possível, é raro que um programador consiga desvendar as complexidades dos algoritmos de sincronização de tempo com 35 anos de idade. Parte do código foi escrita antes da era POSIX, e a API do Unix na época diferia muito do que é usado atualmente. Além disso, são necessários conhecimentos em estatística para filtrar o sinal de ruídos em linhas barulhentas.
O NTS não foi a primeira tentativa de corrigir o NTP. Depois que os invasores aprenderam a explorar vulnerabilidades do NTP para amplificar ataques DDoS, ficou claro que mudanças radicais eram necessárias. Enquanto os rascunhos do NTS estavam sendo preparados e polidos, a National Science Foundation dos EUA concedeu urgentemente uma bolsa para a modernização do NTP no final de 2014.
O grupo de trabalho foi liderado por ninguém menos que — um dos fundadores e pilares da comunidade de Código Aberto e autor do livro . A princípio, Eric e seus colegas tentaram migrar o código do NTP da plataforma BitKeeper para o git, mas isso não foi possível. O líder do projeto, Harlan Stenn, se opôs a essa decisão, e as negociações chegaram a um impasse. Assim, foi decidido bifurcar o código do projeto, originando o NTPSec.
Com uma experiência sólida, incluindo trabalho no GPSD, um histórico matemático e a habilidade mágica de ler código antigo, Eric Raymond era exatamente o hacker que poderia tirar esse projeto do papel. A equipe encontrou um especialista em migração de código e, em apenas 10 semanas, o NTP no GitLab. O trabalho começou a fluir.
A equipe de Eric Raymond abordou a tarefa da mesma forma que Auguste Rodin ao trabalhar com um bloco de pedra. Removendo 175 KLOC de código antigo, eles conseguiram reduzir significativamente a superfície de ataque, fechando várias brechas de segurança.
Aqui está uma lista incompleta dos afetados:
- Refclock não documentados, obsoletos, desatualizados ou quebrados.
- Biblioteca ICS não utilizada.
- libopts/autogen.
- Código antigo para Windows.
- ntpdc.
- Autokey.
- Código C do ntpq reescrito em Python.
- Código C do sntp/ntpdig reescrito em Python.
Além da limpeza do código, o projeto teve outras tarefas. Aqui está uma lista parcial de realizações:
- A proteção do código contra estouro de buffer foi significativamente reforçada. Para evitar estouros de buffer, todas as funções de string inseguras (strcpy / strcat / strtok / sprintf / vsprintf / gets) foram substituídas por versões seguras que implementam limites de tamanho.
- Suporte adicionado para NTS.
- A precisão do passo de tempo foi aumentada em dez vezes com a vinculação de hardware físico. Isso se deve ao fato de que os relógios de computador modernos são muito mais precisos do que os disponíveis na época do surgimento do NTP. GPSDO e estações de rádio dedicadas ao tempo se beneficiaram muito disso.
- O número de linguagens de programação foi reduzido a duas. Em vez de scripts em Perl, awk e até mesmo S, agora é apenas Python. Isso proporcionou mais oportunidades de reutilização de código.
- Em vez de uma confusão de scripts, o autotools, o projeto passou a utilizar um sistema de construção de software. .
- A documentação do projeto foi atualizada e reorganizada. De uma coleção de documentos contraditórios e, em alguns casos, arcaicos, foi criada uma documentação bastante aceitável. Cada opção de linha de comando e cada entidade de configuração agora possui uma única versão da verdade. Além disso, as páginas de manual e a documentação web agora são geradas a partir dos mesmos arquivos principais.
NTPSec está disponível para várias distribuições Linux. No momento, a última versão estável é 1.1.8, e para Gentoo Linux— a penúltima.
(1:696)$ sudo emerge -av ntpsec
Esses são os pacotes que seriam mesclados, na ordem:
Calculando dependências... concluído!
[ebuild R ] net-misc/ntpsec-1.1.7-r1::gentoo USE="samba seccomp -debug -doc -early -gdb -heat -libbsd -nist -ntpviz -rclock_arbiter -rclock_generic -rclock_gpsd -rclock_hpgps -rclock_jjy -rclock_local -rclock_modem -rclock_neoclock -rclock_nmea -rclock_oncore -rclock_pps -rclock_shm -rclock_spectracom -rclock_trimble -rclock_truetime -rclock_zyfer -smear -tests" PYTHON_TARGETS="python3_6" 0 KiB
Total: 1 pacote (1 reinstalação), Tamanho dos downloads: 0 KiB
Você gostaria de mesclar esses pacotes? [Sim/Não]
Chrony
Houve mais uma tentativa de substituir o antigo NTP por um análogo mais seguro. Chrony, ao contrário do NTPSec, foi escrito do zero e é projetado para funcionar de forma confiável em uma ampla variedade de condições, incluindo conexões de rede instáveis, disponibilidade parcial ou sobrecargas de rede e variações de temperatura. Além disso, o chrony possui outras vantagens:
- O chrony pode sincronizar os relógios do sistema mais rapidamente com maior precisão;
- O chrony é menor, consome menos memória e acessa o processador apenas quando necessário. Isso é um grande plus para a economia de recursos e energia;
- O chrony suporta carimbos de tempo em nível de hardware no Linux, o que proporciona uma sincronização extremamente precisa em redes locais.
No entanto, o chrony não possui algumas funcionalidades do antigo NTP, como o cliente/servidor de difusão e multicast. Além disso, o NTP clássico suporta um maior número de sistemas operacionais e plataformas.
Para desabilitar a funcionalidade do servidor e as solicitações NTP para o processo chronyd, basta definir port 0 no arquivo chrony.conf. Isso é feito quando não há necessidade de fornecer tempo para clientes NTP ou nós peer-to-peer. A partir da versão 2.0, a porta do servidor NTP está aberta apenas quando o acesso é permitido pela diretiva allow ou pelo comando correspondente, ou quando um nó peer NTP é configurado ou a diretiva broadcast é utilizada.
O programa consiste em dois módulos.
- chronyd — um serviço que roda em segundo plano. Ele recebe informações sobre a diferença entre os relógios do sistema e um servidor de tempo externo e corrige a hora local. Também implementa o protocolo NTP e pode atuar como cliente ou servidor.
- chronyc — uma ferramenta de linha de comando para monitorar e controlar o programa. É usada para ajustar finamente vários parâmetros do serviço, por exemplo, permite adicionar ou remover servidores NTP enquanto o chronyd continua em operação.
A partir da 7ª versão do RedHat Linux o chrony atua como um serviço de sincronização de tempo. O pacote também está disponível para outras distribuições Linux. A última versão estável 3.5 está se preparando para o lançamento da v4.0.
(1:712)$ sudo emerge -av chrony
Estes são os pacotes que seriam mesclados, na ordem:
Calculando dependências... concluído!
[binary N ] net-misc/chrony-3.5-r2::gentoo USE="adns caps cmdmon ipv6 ntp phc readline refclock rtc seccomp (-html) -libedit -pps (-selinux)" 246 KiB
Total: 1 pacote (1 novo, 1 binário), Tamanho dos downloads: 246 KiB
Você gostaria de mesclar esses pacotes? [Sim/Não]
Como configurar seu próprio servidor remoto chrony na internet para sincronização de tempo em uma rede de escritório. Abaixo está um exemplo de configuração em VPS.
Exemplo de configuração do Chrony em RHEL / CentOS em VPS
Agora vamos praticar um pouco e subir nosso próprio servidor NTP em VPS. É muito simples, basta escolher o plano adequado no site RuVDS, obter um servidor pronto e digitar uma dezena de comandos simples. Para nossos objetivos, uma opção como essa é mais do que suficiente.

Vamos para a configuração do serviço e, em primeiro lugar, instalamos o pacote chrony.
[root@server ~]$ yum install chronyRHEL 8 / CentOS 8 usam um gerenciador de pacotes diferente.
[root@server ~]$ dnf install chronyApós a instalação do chrony, é necessário iniciar e ativar o serviço.
[root@server ~]$ systemctl enable chrony --nowSe desejado, você pode fazer alterações no /etc/chrony.conf, substituindo os servidores NPT pelos mais próximos para reduzir o tempo de resposta.
# Use public servers from the pool.ntp.org project.
# Please consider joining the pool (http://www.pool.ntp.org/join.html).
server 0.ru.pool.ntp.org iburst
server 1.ru.pool.ntp.org iburst
server 2.ru.pool.ntp.org iburst
server 3.ru.pool.ntp.org iburst
Em seguida, configuramos a sincronização do servidor NTP com os nós do pool especificado.
[root@server ~]$ timedatectl set-ntp true
[root@server ~]$ systemctl restart chronyd.service
É necessário também abrir a porta NTP, caso contrário, o firewall bloqueará conexões de entrada dos nós clientes.
[root@server ~]$ firewall-cmd --add-service=ntp --permanent
[root@server ~]$ firewall-cmd --reload
Do lado do cliente, basta definir corretamente o fuso horário.
[root@client ~]$ timedatectl set-timezone Europe/MoscowNo arquivo /etc/chrony.conf, adicione o IP ou o nome do host do nosso servidor VPS em que o servidor NTP chrony está em execução.
server my.vps.serverE finalmente, inicie a sincronização do tempo no cliente.
[root@client ~]$ systemctl enable --now chronyd
[root@client ~]$ timedatectl set-ntp true
Na próxima vez, falarei sobre as opções de sincronização de tempo sem internet.
Fonte: habr.com
