[ntp:security] Critical vulnerabilities in ntpd

Stephen Röttger sroettger at google.com
Mon Sep 8 19:00:58 UTC 2014


Hi,

I identified a few security vulnerabilities in the latest stable version of
ntpd (v4.2.6p5), including a critical buffer overflow that leads to remote
code execution on common configurations.

I attached a detailed description to this message which will help you
confirm and address the vulnerabilities. Please let me know if anything is
unclear or needs further explanation.

Please confirm at your earliest convenience that you have received this
vulnerability report. We will gladly work with you so you can successfully
confirm and reproduce this issue.

Note that we consider this a critical vulnerability, and per our
Vulnerability Disclosure process we may help protect customers by publicly
disclosing some information on the vulnerability within 90 days of this
report.

Once you have reproduced the issue, we’d appreciate to learn your expected
timeline for a security update to be released. With any fix, please give
credit for identifying the vulnerability to “Stephen Röttger” of the Google
Security Team.

Don’t hesitate to let us know if you have any questions!
========= Vulnerability details =========

A description of the identified vulnerabilities follows below. The buffer
overflow in <ctl_putdata> leads to remote code execution on common
configurations.
To exploit this you need to be authenticated with a controlkey. However,
ntpd will create a default 4 byte requestkey with keyid 65535 in
<config_auth>, for which the random number generator was seeded with a 32
bit seed.
Random values leak in normal time responses through the receive timestamp
and can be used to brute force the seed offline and acquire the key. If
ntpd was just restarted, I was able to brute force the correct seed with a
naive single core implementation in ~30 minutes on my laptop.
The requestkey can then be used to add the keyid 65535 as a controlkey
through a private mode packet. Note that common configurations set
restrictions to allow these packets only from localhost but this can be
bypassed by spoofing an IPv6 packet with source ::1, which will be let
through by Linux and OS X (IPv4 packets with source 127.0.0.1 are dropped
on the other hand).

ntpd/ntp_crypto.c:792 <crypto_recv> (buffer overflow)

if (vallen == (u_int)EVP_PKEY_size(host_pkey)) {

if (RSA_private_decrypt(vallen,
    (u_char *)ep->pkt,
    (u_char *)&temp32,
    host_pkey->pkey.rsa,
    RSA_PKCS1_OAEP_PADDING) <= 0) {

This code is part of the NTP autokey protocol. The client sends a RSA
public key to the server, which encrypts a 32bit token and sends it back.
This code handles the server response on the client side and decrypts the
token into the 32 bit integer temp32. However, the decrypted cleartext can
be up to (keysize/8)-42 in size (e.g. 214 bytes for a 2048 bit key).

Two things make this less bad: 1) you need to have autokey enabled
explicitly by generating a key with ntp-keygen and adding something like:

crypto pw serverpassword
keysdir /etc/ntp

to your config. And 2) by default ntp-keygen generates 512 bit keys which
results in an 18 byte overwrite and, at least on the ubuntu ntp package,
this doesn’t seem to overwrite anything valuable on the stack.


ntpd/ntp_control.c:1027 <ctl_putdata> (buffer overflow, needs privileges)
 if (dlen + overhead + datapt > dataend) {
 /*
  * Not enough room in this one, flush it out.
  */
 ctl_flushpkt(CTL_MORE);
 }
 memmove((char *)datapt, dp, (unsigned)dlen);

Overflow if dlen is bigger than datapt. This happens e.g. when it is called
from <configure+69> with a big error message, which can be triggered by
chaining multiple error messages after each other. Through  the
<configure+69> codepath, code execution is unlikely since you have limited
control over the data that is written but it can be used as an information
leak.

Another code path is through <read_variables> after setting a big variable
with a setvar config line. This will lead to an information leak and code
execution as described before.

ntpd/ntp_control.c:2095 <ctl_getitem> (possible infoleak)

*data = buf;

This function passes a pointer to a local buffer back to the calling
function. If another function is called before the data is used, the
contents can be overwritten and it might result in an information leak.

ntpd/ntp_control.c:2495 <configure> (buffer overflow, needs privileges)

data_count = reqend - reqpt;
memcpy(remote_config.buffer, reqpt, data_count);

A buffer overflow from the user-provided packet into a global variable. For
this code path you need to be able to send authenticated configuration
packets.

ntpd/ntp_proto.c:946 <receive> (missing return on error)

if (is_authentic == AUTH_ERROR) {
 fast_xmit(rbufp, MODE_ACTIVE, 0,
 restrict_mask);
 sys_restricted++;
}

A new connection from a symmetric active peer with a broken signature will
send an error reply to the client but then use the codepath of a valid
packet afterwards, which includes adding him as a peer. Not sure if this is
an issue though, since I couldn’t find a codepath in which the peer isn’t
removed again from the list.

util/ntp-keygen.c:724 <gen_md5> (keys without entropy)

ntp_srandom((u_long)epoch);

The symmetric MD5 keys generated by ntp-keygen have no entropy at all. They
are generated with a custom random number generator that is only seeded
with the number of seconds since 1970. Even if we can’t estimate the
creation time of the keys this leaves us with 2^30 for brute forcing.

ntpd/ntp_config.c:1689 <config_auth> (weak default key)

int rankey;
rankey = ntp_random();
req_keytype = NID_md5;
req_hashlen = 16;
MD5auth_setkey(req_keyid, req_keytype,
    (u_char *)&rankey, sizeof(rankey));
authtrust(req_keyid, 1);

If no auth key is set in the config, ntpd will generate a random key on the
fly. There are two problems with this: 1) the generated key is 31 bit in
size, 2) it uses the weak ntp_random function, which is seeded with a 32
bit value and can only provide 32 bit of entropy.

Missing validation of vallen that leads to various info leaks

ntpd/ntp_crypto.c:571 <crypto_recv> (buffer overread)

memcpy(peer->subject, ep->pkt, vallen);

ntpd/ntp_crypto.c:1162 <crypto_xmit> (buffer overread, non-exploitable)

memcpy(certname, ep->pkt, vallen);

vallen might be greater than the size of the packet. In the first case,
peer->subject might be sent back to the client until the first null byte
through a CTL_OP_READVAR control packet (if this is allowed on the
interface) leading to an information leak. The second case doesn’t leak
anything though, since certname is just compared against the name of the
server’s cert.

ntpd/ntp_crypto.c:1559 <crypto_encrypt> (possible infoleak)

len = ntohl(ep->vallen);
ptr = (u_char *)ep->pkt;
pkey = d2i_PublicKey(EVP_PKEY_RSA, NULL, &ptr, len);

ntpd/ntp_crypto.c:2959 <cert_sign> (possible infoleak)

ptr = (u_char *)ep->pkt;
if ((req = d2i_X509(NULL, &ptr, ntohl(ep->vallen))) == NULL) {

The cert is created with a length greater than the packet in both cases,
possible information leak.

ntpd/ntp_crypto.c:2117 <crypto_bob> (possible infoleak)

len = ntohl(ep->vallen);
if ((r = BN_bin2bn((u_char *)ep->pkt, len, NULL)) == NULL) {

Same with a bignum, possible information leak.

ntpd/ntp_crypto.c:1461 <crypto_verify> (integer overflow, probably
non-exploitable)

i = (vallen + 3) / 4;
siglen = ntohl(ep->pkt[i++]);
if (len < VALUE_LEN + ((vallen + 3) / 4) * 4 + ((siglen + 3) /

4) * 4)

A vallen of UINT_MAX-2 will result in i==0 and pass the length check. As
far as I can tell, this doesn’t lead to any memory corruption and bypassing
the cryptography is not severe since the autokey protocol was already shown
to be broken.

As mentioned before, if anything is unclear please let me know.

Best regards,

Stephen Röttger
Google Security Team
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.ntp.org/private/security/attachments/20140908/6cbd1a94/attachment-0001.html>


More information about the security mailing list