Talos Vulnerability Report

TALOS-2016-0130

Network Time Protocol Broadcast Mode Poll Interval Enforcement Denial of Service Vulnerability

November 21, 2016

Report ID

CVE-2016-7428

Summary

An exploitable denial of service vulnerability exists in the broadcast mode poll interval enforcement functionality of ntpd. To limit abuse, ntpd restricts the rate at which each broadcast association will process incoming packets. ntpd will reject broadcast mode packets that arrive before the poll interval specified in the preceding broadcast packet expires. A vulnerability exists which allows remote unauthenticated attackers to send specially crafted broadcast mode NTP packets which will cause ntpd to reject all broadcast mode packets from legitimate NTP broadcast servers.

Tested Versions

NTP 4.2.8p6

Product URLs

http://www.ntp.org/

CVSS Scores

CVSSv2: 5.0 - (AV:N/AC:L/Au:N/C:N/I:N/A:P)
CVSSv3: 5.3 - CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L

Details

In response to the NTP Deja Vu vulnerability (CVE-2015-7973), ntp-4.2.8p6 introduced several new integrity checks on incoming broadcast mode packets. Upon receipt of a broadcast mode packet, before authentication is enforced, ntpd will reject the packet if any of the following conditions hold:

  1. The packet poll value is out of bounds for the broadcast association, i.e.

     pkt->ppoll < peer->minpoll || pkt->ppoll > peer->maxpoll
    
  2. The packet was received before a full poll interval has elapsed since the last broadcast packet was received from the packet’s sender. i.e. A server cannot ingress packets more frequently than peer->minpoll.

  3. The packet transmit timestamp is less than the last seen broadcast packet transmit timestamp from the packet’s sender. i.e. Broadcast packet transmit timestamps must be monotonically increasing.

The following logic is used to ensure constraint 2, which ensures that broadcast associations will process only one incoming packet per poll interval:

/* ntp-4.2.8p6 ntpd/ntp_proto.c */
1305  if (MODE_BROADCAST == hismode) {
...
1341      if (  (current_time - peer->timelastrec)
1342          < (1 << pkt->ppoll)) {
1343          msyslog(LOG_INFO, "receive: broadcast packet from %s arrived after %ld, not %d seconds!",
1344              stoa(&rbufp->recv_srcadr),
1345              (current_time - peer->timelastrec),
1346              (1 << pkt->ppoll)
1347              );
1348          ++bail;
1349      }
...
1361
1362      peer->bxmt = p_xmt;
1363
1364      if (bail) {
1365          peer->timelastrec = current_time;
1366          sys_declined++;
1367          return;
1368      }
1369  }

If the time elapsed since the last broadcast packet was received from this peer is less than the poll interval declared by the sender ((current_time - peer->timelastrec) < (1 << pkt->ppoll)), the packet will be discarded. (A previous check ensures that pkt->ppoll is within acceptable bounds.)

Unfortunately, line 1341 compares the current time against the last time any broadcast mode packet was received with a source IP address of the peer (peer->timelastrec). In contrast to peer->timereceived, which is updated only when a clean (correctly authenticated and passing integrity checks) packet is received, peer->timelastrec is updated by all incoming broadcast packets including spoofed and replayed packets.

This leads to a trivial denial of service attack. The attacker:

  1. Discovers the IP address of the victim’s broadcast server. e.g. Send the victim a client mode NTP packet and discover the broadcast server from the refid field of the victim’s reply.

  2. At least once per poll period, send the victim a spoofed broadcast mode packet from the broadcast server. This will set peer->timelastrec = current_time such that, when a legitimate packet is received, it will appear to have been received too early ((current_time - peer->timelastrec) < (1 << pkt->ppoll)) and will be discarded.

    • The attacker does not need to be on the same subnet as the victim. The attacker can address the spoofed broadcast NTP packet directly to the victim’s IP address.

    • The attacker can choose any reasonably small estimate for the poll period. Because the peer->timelastrec update happens even when a packet fails the poll period check, there is no penalty for sending packets too frequently.

To prevent this vulnerability, ntpd should only discard packets broadcast packets when less than one poll interval has elapsed since the last legitimate packet has been received (peer->timereceived).

Mitigation

There is no workaround for this issue. Because the vulnerable logic is executed before authentication is enforced, authentication and the restrict notrust ntpd.conf directive have no effect. An attacker can bypass notrust restrictions by sending incorrectly authenticated packets.

In order to succeed in an attack, the attacker must send at least one spoofed packet per poll period. Therefore observing more than one NTP broadcast packet from the same sender address per poll period indicates a possible attack.

The following patch can be used to fix this vulnerability:

From 8522882496d3df2bd764de6d8f7afac4a8d84006 Mon Sep 17 00:00:00 2001
From: Matthew Van Gundy <mvangund@cisco.com>
Date: Fri, 5 Feb 2016 17:38:32 -0500
Subject: [PATCH] Fix unauthenticated broadcast mode denial of service (peer->timelastrec)

Drop packets if they arrive less than one poll interval since the last
**clean** packet received on an association.  If we compare against the
last time that *any* packet was received, even one that will be dropped
for failing integrity checks, an attacker can DoS the association by
sending incorrectly authenticated packets or replaying old packets to
keep bumping the peer->timelastrec timer forward.
---
 include/ntp.h    |  4 +++-
 ntpd/ntp_proto.c | 13 +++++++++++--
 2 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/include/ntp.h b/include/ntp.h
index 6a4e9aa..cbf6cec 100644
--- a/include/ntp.h
+++ b/include/ntp.h
@@ -383,7 +383,9 @@ struct peer {
   * Statistic counters
   */
  u_long  timereset;  /* time stat counters were reset */
- u_long  timelastrec;  /* last packet received time */
+ u_long  timelastrec;  /* last packet received time (may
+                                 * include spoofed, replayed, or other
+                                 * invalid packets) */
  u_long  timereceived; /* last (clean) packet received time */
  u_long  timereachable;  /* last reachable/unreachable time */

diff --git a/ntpd/ntp_proto.c b/ntpd/ntp_proto.c
index ad45409..1ea5cee 100644
--- a/ntpd/ntp_proto.c
+++ b/ntpd/ntp_proto.c
@@ -1338,11 +1338,20 @@ receive(
        ++bail;
      }

-     if (  (current_time - peer->timelastrec)
+     /*
+      * Ensure that at least one poll interval has
+      * elapsed since the last **clean** packet was
+      * received.  We limit the check to **clean**
+      * packets to prevent replayed packets and
+      * incorrectly authenticated packets, which
+      * we'll discard, from being used to create a
+      * denial of service condition.
+      */
+     if (  (current_time - peer->timereceived)
          < (1 << pkt->ppoll)) {
        msyslog(LOG_INFO, "receive: broadcast packet from %s arrived after %ld, not %d seconds!",
          stoa(&rbufp->recv_srcadr),
-         (current_time - peer->timelastrec),
+         (current_time - peer->timereceived),
          (1 << pkt->ppoll)
          );
        ++bail;
--
2.5.2

Credit

Discovered by Matthew Van Gundy of Cisco ASIG.

Timeline

2016-09-12 - Vendor Disclosure
2016-11-21 - Public Release