CVE-2016-7428
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.
NTP 4.2.8p6
http://www.ntp.org/
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
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:
The packet poll value is out of bounds for the broadcast association, i.e.
pkt->ppoll < peer->minpoll || pkt->ppoll > peer->maxpoll
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
.
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:
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.
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
).
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
2016-09-12 - Vendor Disclosure
2016-11-21 - Public Release
Discovered by Matthew Van Gundy of Cisco ASIG.