From f0c48680fe57b964e148dce75545852802a37c49 Mon Sep 17 00:00:00 2001 From: Miroslav Lichvar Date: Thu, 5 Mar 2015 12:44:30 +0100 Subject: [PATCH 1/4] ntp: protect authenticated symmetric associations against DoS attacks An attacker knowing that NTP hosts A and B are peering with each other (symmetric association) can send a packet with random timestamps to host A with source address of B which will set the NTP state variables on A to the values sent by the attacker. Host A will then send on its next poll to B a packet with originate timestamp that doesn't match the transmit timestamp of B and the packet will be dropped. If the attacker does this periodically for both hosts, they won't be able to synchronize to each other. It is a denial-of-service attack. According to [1], NTP authentication is supposed to protect symmetric associations against this attack, but in the NTPv3 (RFC 1305) and NTPv4 (RFC 5905) specifications the state variables are updated before the authentication check is performed, which means the association is vulnerable to the attack even when authentication is enabled. To fix this problem in chrony, save the originate and local timestamps only when the authentication check (test5) passed. [1] https://www.eecis.udel.edu/~mills/onwire.html --- ntp_core.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/ntp_core.c b/ntp_core.c index ebb6a7c..e654c88 100644 --- a/ntp_core.c +++ b/ntp_core.c @@ -1005,9 +1005,6 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins /* ==================== */ - /* Save local receive timestamp */ - inst->local_rx = *now; - pkt_leap = (message->lvm >> 6) & 0x3; if (pkt_leap == 0x3) { source_is_synchronized = 0; @@ -1039,14 +1036,6 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins test2 = 1; /* Success */ } - /* Regardless of any validity checks we apply, we are required to - save this field from the packet into the ntp source - instance record. See RFC1305 section 3.4.4, peer.org <- pkt.xmt - & peer.peerpoll <- pkt.poll. Note we can't do this assignment - before test1 has been carried out!! */ - - inst->remote_orig = message->transmit_ts; - /* Test 3 requires that pkt.org != 0 and pkt.rec != 0. If either of these are true it means the association is not properly 'up'. */ @@ -1219,6 +1208,14 @@ receive_packet(NTP_Packet *message, struct timeval *now, double now_err, NCR_Ins kod_rate = 1; } + /* The transmit timestamp and local receive timestamp must not be saved when + the authentication test failed to prevent denial-of-service attacks on + symmetric associations using authentication */ + if (test5) { + inst->remote_orig = message->transmit_ts; + inst->local_rx = *now; + } + valid_kod = test1 && test2 && test5; valid_data = test1 && test2 && test3 && test4 && test4a && test4b; From e18ee0bb4671ce1a2fcd7eb131d699651cedaa71 Mon Sep 17 00:00:00 2001 From: Miroslav Lichvar Date: Mon, 30 Mar 2015 14:41:37 +0200 Subject: [PATCH 2/4] addrfilt: fix access configuration with subnet size indivisible by 4 When NTP or cmdmon access was configured (from chrony.conf or via authenticated cmdmon) with a subnet size that is indivisible by 4 and an address that has nonzero bits in the 4-bit subnet remainder (e.g. 192.168.15.0/22 or f000::/3), the new setting was written to an incorrect location, possibly outside the allocated array. An attacker that has the command key and is allowed to access cmdmon (only localhost is allowed by default) could exploit this to crash chronyd or possibly execute arbitrary code with the privileges of the chronyd process. --- addrfilt.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/addrfilt.c b/addrfilt.c index 0930289..4b8879a 100644 --- a/addrfilt.c +++ b/addrfilt.c @@ -199,7 +199,10 @@ set_subnet(TableNode *start_node, /* How many subnet entries to set : 1->8, 2->4, 3->2 */ N = 1 << (NBITS-bits_to_go); - subnet = get_subnet(ip, bits_consumed); + + subnet = get_subnet(ip, bits_consumed) & ~(N - 1); + assert(subnet + N <= TABLE_SIZE); + if (!(node->extended)) { open_node(node); } From 10b2b53aa77e915346ea0ad4eaae274a5ffb730c Mon Sep 17 00:00:00 2001 From: Miroslav Lichvar Date: Mon, 30 Mar 2015 15:13:27 +0200 Subject: [PATCH 3/4] cmdmon: fix initialization of allocated reply slots When allocating memory to save unacknowledged replies to authenticated command requests, the last "next" pointer was not initialized to NULL. When all allocated reply slots were used, the next reply could be written to an invalid memory instead of allocating a new slot for it. An attacker that has the command key and is allowed to access cmdmon (only localhost is allowed by default) could exploit this to crash chronyd or possibly execute arbitrary code with the privileges of the chronyd process. --- cmdmon.c | 1 + 1 file changed, 1 insertion(+) diff --git a/cmdmon.c b/cmdmon.c index 58a6c90..343baf4 100644 --- a/cmdmon.c +++ b/cmdmon.c @@ -566,6 +566,7 @@ get_more_replies(void) for (i=1; i Date: Mon, 30 Mar 2015 15:19:12 +0200 Subject: [PATCH 4/4] doc: update NEWS --- NEWS | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/NEWS b/NEWS index b6aaf4a..5e958e5 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,13 @@ +New in version 1.31.1 +===================== + +Security fixes +-------------- +* Protect authenticated symmetric NTP associations against DoS attacks + (CVE-2015-1799) +* Fix access configuration with subnet size indivisible by 4 (CVE-2015-1821) +* Fix initialization of reply slots for authenticated commands (CVE-2015-1822) + New in version 1.31 ===================