Introduction of CVSS v4.0
This is How you Secure the Network Time Protocol
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 synchronise its system time with one or more servers. We demonstrate such an attack, show what measures can be taken to protect the system time and explain the Network Time Security protocol, an extension of the NTP protocol to protect against such attacks.
An attack requires attackers to be in a position to eavesdrop and manipulate the network traffic of client and server. This can be done in the form of an MITM attack. For the following example, there are the actors:
Mallory will launch an attack on Bob and try to manipulate his system time. Before the attack, Bob has a synchronised system time and uses the software 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
timedatectl shows that everything is in order on the system.
To demonstrate an attack, the script by Davide Bove can be used. The script still had to be tweaked and is available as a fork. When the script is started, an ARP spoofing attack is automatically launched and then the system time of all transmitted NTP packets between 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 the Mallory system and as soon as a time was synchronised, the packets were manipulated. The attack was successful, which is evident in the message from chrony that the system time is wrong by 486805679 seconds and has been 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 the system Bob had accepted a new system time in the future.
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 too large respectively abrupt time jumps in the configuration of chrony. The FAQ section of chrony describes how the 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 launched again.
systemd: Started NTP client/server. chronyd: Selected source 220.127.116.11 (1.ch.pool.ntp.org) chronyd: Adjustment of 486753299.993 seconds exceeds the allowed maximum of 100.000 seconds (exiting) chronyd: chronyd exiting systemd: chronyd.service: Main process exited, code=exited, status=1/FAILURE systemd: 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 synchronisation is still unprotected. Moreover, attackers can still manipulate the time, simply with smaller steps.
The Network Time Security (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 synchronisation.
During initial setup, the NTP client connects to an NTS-KE server via the NTS TCP port, usually 4460/tcp, and it 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, 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 synchronisation, the NTP client then sends a packet that contains several extension fields, including the cookie and an authentication tag generated from the key material from the NTS-KE handshake. 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.
The NTP client Chrony supports 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 synchronisation 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 ideally has the value
377. This value indicates that the last 8 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
[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. Attackers still have the possibility to affect the time synchronisation because the NTP client no longer receives valid responses.
The introduction of NTS allows to defend 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 still takes 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 the time servers in the company infrastructure should therefore be planned and implemented in the near future.
Our experts will get in contact with you!
Our experts will get in contact with you!
Further articles available here