The Network Time Protocol (NTP) is one of the oldest Internet protocols that is still widely used. The protocol has no security mechanisms, communication is unencrypted, and there is no authentication between client and server or safeguards against manipulation of network packets. Attacks against NTP can have a serious impact because other protocols are dependent on the accuracy of the system time, such as DNSSEC, Kerberos, and TLS.
Most attacks are based on a machine-in-the-middle (MITM) attack. Once attackers are in this privileged position, they can manipulate server responses to provide a false time, delay or completely drop server responses to prevent the client from continuing to synchronize its system time with one or more servers. This post will demonstrate such an attack, show what measures can be taken to protect the system time and explain the Network Time Security (NTS) protocol, an extension of the NTP protocol to protect against such attacks.
Key points
This is how you secure NTP:
• NTP is an old protocol without security capabilities.
• Protocols like DNSSEC, Kerberos and TLS depend on a correct system time.
• MITM attacks can be used to manipulate NTP responses and thus the system time.
• The system time can be protected against abrupt time jumps by applying hardening measures.
• NTS adds authentication and encryption to NTP and protects against MITM attacks.
Attacks against NTP
An attack requires attackers to be in a position to eavesdrop and manipulate the network traffic of the client and server. This can be done in the form of a MITM attack. For the following example, here are the actors:
- Bob – 192.168.144.130
- Mallory – 192.168.144.129
- Gateway – 192.168.244.2
Mallory will launch an attack on Bob and try to manipulate his system time. Before the attack, Bob synchronizes system time using Chrony and four ‘time servers’ of the NTP Pool Project:
[user@bob ~]$ timedatectl Local time: Tue 2022-08-16 17:08:12 CEST Universal time: Tue 2022-08-16 15:08:12 UTC RTC time: Tue 2022-08-16 15:08:12 Time zone: Europe/Zurich (CEST, +0200) System clock synchronized: yes NTP service: active RTC in local TZ: no
The command timedatectl
shows that everything is in order on this system.
To demonstrate an attack, a script by Davide Bove can be used. The script has to be tweaked and is available as a fork. When the script is started, an Address Resolution Protocol (ARP) spoofing attack is automatically launched and then the system time of all transmitted NTP packets between the server and client is manipulated:
[user@mallory ~]$ sudo python3 ntpspoof.py 192.168.244.130 eth0 Running ARP spoofing for target: 192.168.244.130 using the router: 192.168.244.2 [*] waiting for NTP packages Received package for: 192.168.244.130 -> Modified! Received package for: 192.168.244.130 -> Modified! Received package for: 192.168.244.130 -> Modified!
The script was started on Mallory’s system and as soon as a time was synchronized, the packets were manipulated. The attack was successful, which is evident in the message from Chrony that the system time is wrong by 486,805,679 seconds, and was corrected.
[user@bob ~]$ sudo chronyd -q "server 0.ch.pool.ntp.org iburst" 2022-08-16T15:11:20Z chronyd version 4.2 starting (+CMDMON +NTP +REFCLOCK +RTC +PRIVDROP +SCFILTER +SIGND +ASYNCDNS +NTS +SECHASH +IPV6 +DEBUG) 2022-08-16T15:11:20Z Initial frequency -9.183 ppm 2022-08-16T15:11:24Z System clock wrong by 486805679.997304 seconds (step) 2038-01-18T22:59:24Z chronyd exiting [user@bob ~]$ timedatectl Local time: Mon 2038-01-18 23:59:31 CET Universal time: Mon 2038-01-18 22:59:31 UTC RTC time: Tue 2022-08-16 15:11:31 Time zone: Europe/Zurich (CET, +0100) System clock synchronized: no NTP service: inactive RTC in local TZ: no
The system time output also shows that the attack was successful and that Bob had accepted a new system time in the future.
Protecting system time
Because the transmission of NTP packets is neither encrypted nor signed, no mitigation against such attacks can be implemented at the protocol level. However, it is possible to protect the system time from time jumps that are too large and abrupt in Chrony’s configuration. Chrony’s FAQ section describes how system time can be protected. The setting maxchange
, for example, specifies that the largest possible time jump cannot exceed 100 seconds, otherwise an error occurs and the Chrony daemon terminates:
minsources 3 maxchange 100 0 0 makestep 0.001 1 maxdrift 100 maxslewrate 100 driftfile /var/lib/chrony/drift rtcsync
The configuration of Chrony was enhanced with the above settings and the attack was relaunched.
systemd[1]: Started NTP client/server. chronyd[3072]: Selected source 31.3.135.232 (1.ch.pool.ntp.org) chronyd[3072]: Adjustment of 486753299.993 seconds exceeds the allowed maximum of 100.000 seconds (exiting) chronyd[3072]: chronyd exiting systemd[1]: chronyd.service: Main process exited, code=exited, status=1/FAILURE systemd[1]: chronyd.service: Failed with result 'exit-code'.
The Chrony logs now show that the time deviation in the manipulated NTP packets was above the permitted 100 seconds and Chrony, therefore, terminated itself. Although it was not possible to manipulate the system, the time synchronization is still unprotected. Moreover, attackers can still manipulate the time, simply with smaller steps.
NTS
The NTS mechanism was specified in RFC 8915 and uses Transport Layer Security (TLS) and Authenticated Encryption with Associated Data (AEAD) to secure the client-server mode of NTP. NTS includes the sub-protocols NTS Key Establishment (NTS-KE), which handles initial authentication and key establishment over TLS, and NTS Extension Fields for NTPv4, which controls the encryption and authentication of extension fields in NTP packets during time synchronization.
During initial setup, the NTP client connects to an NTS-KE server via the NTS TCP port, usually 4460/TCP, and performs a TLS handshake. Additional parameters are then negotiated via the TLS channel and the server sends cookies to the client along with the NTP server to be used. In addition, the key material is exchanged via TLS Key Export, defined in RFC 5705. After this, the NTS-KE phase is completed and the NTP client does not need to establish any further connection with the NTS-KE server in the future.
During time synchronization, the NTP client then sends a packet that contains several extension fields, including the cookie, and an authentication tag generated from the NTS-KE handshake’s key material. The NTP server uses the cookie to access the key material on the server side and finally sends back an authenticated response. In addition to the time information, this response also includes a new cookie that is used in the client’s next request.
NTP client configuration
NTP client, Chrony, has supported NTS since version 4. In the configuration of Chrony, the option NTS can be added to each time server — if the time server supports NTS. In addition, the option ntsdumpdir /var/lib/chrony
should be included in the configuration file so that the NTS keys and cookies are stored, and the NTS-KE handshake does not have to be performed after each restart of the service. A collection of time servers with NTS is available in the GitHub Gist time servers with NTS support.
A list of servers is added to the /etc/chrony.conf
file accordingly. It is not recommended to mix time servers without NTS and those with NTS support.
server time.cloudflare.com iburst nts maxdelay 0.1 server ntp.trifence.ch iburst nts maxdelay 0.1 server ntp.zeitgitter.net iburst nts maxdelay 0.1 server ntp.3eck.net iburst nts maxdelay 0.1 server nts.netnod.se iburst nts maxdelay 0.1 server ptbtime1.ptb.de iburst nts maxdelay 0.1 server ptbtime2.ptb.de iburst nts maxdelay 0.1 server ptbtime3.ptb.de iburst nts maxdelay 0.1
Afterwards, the command chronyc -N authdata
can be used to check whether the NTS-KE handshake was successful.
[user@bob ~]$ sudo chronyc -N authdata Name/IP address Mode KeyID Type KLen Last Atmp NAK Cook CLen ========================================================================= time.cloudflare.com NTS 1 15 256 188m 0 0 8 100 ntp.trifence.ch NTS 2 15 256 191m 0 0 8 100 ntp.zeitgitter.net NTS 2 15 256 191m 0 0 8 100 ntp.3eck.net NTS 2 15 256 191m 0 0 8 100 ptbtime1.ptb.de NTS 2 15 256 191m 0 0 8 100 ptbtime2.ptb.de NTS 2 15 256 191m 0 0 8 100 ptbtime3.ptb.de NTS 2 15 256 191m 0 0 8 100
The fields KeyID, Type, and KLen should not be 0. A possible source of error would be that the firewall blocks the outgoing connection on port 4460/TCP. The status of the time synchronization can be verified using the command chronyc -N sources
.
[user@bob ~]$ chronyc -N sources MS Name/IP address Stratum Poll Reach LastRx Last sample =============================================================================== ^+ time.cloudflare.com 3 10 377 124 +532us[ +532us] +/- 18ms ^+ ntp.trifence.ch 2 10 377 828 -617us[ -437us] +/- 12ms ^+ ntp.zeitgitter.net 3 10 377 356 +81us[ +81us] +/- 11ms ^* ntp.3eck.net 2 10 377 439 +330us[ +515us] +/- 6230us ^- ptbtime1.ptb.de 1 10 377 105 +494us[ +494us] +/- 18ms ^- ptbtime2.ptb.de 1 10 377 373 +218us[ +218us] +/- 19ms ^- ptbtime3.ptb.de 1 10 377 613 +745us[ +928us] +/- 18ms
The Reach column should ideally have the value 377
. This value indicates that the last eight queries resulted in a valid response, including the NTS validation. If the MITM attack is performed again, Chrony discards the responses and the value in the Reach column remains 0
.
[user@bob ~]$ chronyc -N sources MS Name/IP address Stratum Poll Reach LastRx Last sample =============================================================================== ^? time.cloudflare.com 0 7 0 - +0ns[ +0ns] +/- 0ns ^? ntp.trifence.ch 0 7 0 - +0ns[ +0ns] +/- 0ns ^? ntp.zeitgitter.net 0 7 0 - +0ns[ +0ns] +/- 0ns ^? ntp.3eck.net 0 7 0 - +0ns[ +0ns] +/- 0ns ^? ptbtime1.ptb.de 0 7 0 - +0ns[ +0ns] +/- 0ns ^? ptbtime2.ptb.de 0 7 0 - +0ns[ +0ns] +/- 0ns ^? ptbtime3.ptb.de 0 7 0 - +0ns[ +0ns] +/- 0ns
By using NTS, the manipulation of NTP packets by a MITM attack can be prevented. However, attackers are still able to affect the time synchronization because the NTP client no longer receives valid responses.
Conclusion
The introduction of NTS allows defending against known attacks against NTP. NTS is not yet supported in all NTP clients and not all Linux distributions have the updated versions of clients that have implemented NTS. In addition, as of August 2022, only a few servers with NTS support exist. For Windows, there is no support for NTS yet. So, it will take some time for NTS to become widespread.
Since a correct system time is essential for many other protocols, the introduction of a safeguard for the NTP protocol is an important and necessary step. The use of NTS on time servers in a company’s infrastructure should therefore be planned and implemented in the near future.
Michael Schneider (Twitter, Mastodon) is an information security expert focused on penetration testing, hardening, and the detection of vulnerabilities in operating systems. He is well-known for a variety of tools written in PowerShell to find, exploit, and mitigate weaknesses.
This post is adapted from the original at SCIP Labs blog.
The views expressed by the authors of this blog are their own and do not necessarily reflect the views of APNIC. Please note a Code of Conduct applies to this blog.