Network Time Protocol Daemon (ntpd) Multiple Vulnerabilities(CVE-2014-9293、CVE-2014-9294、CVE-2014-9295、CVE-2014-9295、CVE-2014-9295、CVE-2014-9296)

目录

0. 引言
1. CVE-2014-9293: Weak default key in config_auth()  
2. CVE-2014-9294: non-cryptographic random number generator with weak seed used by ntp-keygen to generate symmetric keys
3. CVE-2014-9295: Buffer overflow in crypto_recv()、Buffer overflow in ctl_putdata()、Buffer overflow in configure()
4. CVE-2014-9296: receive(): missing return on error 

 

0. 引言

NTF's NTP Project has been notified of a number of vulnerabilities from Neel Mehta and Stephen Roettger of Google's Security Team. The two most serious of these issues and four less serious issues have been resolved as of ntp-4.2.8, which was released on 18 December 2014. There are still two less significant issues to be addressed. We're expecting to fix these within the next month. 

本次Google Security Team一共报告了和NTPD有关的6个漏洞,其中2个属于缓冲区溢出导致的RCE(远程代码执行)漏洞,属于高危漏洞

Relevant Link:

http://support.ntp.org/bin/view/Main/SecurityNotice#Buffer_overflow_in_ctl_putdata
http://www.kb.cert.org/vuls/id/852879
https://rhn.redhat.com/errata/RHSA-2014-2024.html

 
1. CVE-2014-9293: Weak default key in config_auth()  

0x1: 触发条件

1. no auth key is set in the configuration file
2. All NTP4 releases before 4.2.7p11

vim /etc/ntp.conf

# Key file containing the keys and key identifiers used when operating
# with symmetric key cryptography. 
keys /etc/ntp/keys

vim /etc/ntp/keys

#
# PLEASE DO NOT USE THE DEFAULT VALUES HERE.
#
#65535  M       akey
#1      M       pass

在默认安装情况下,NTP是没有配置显式指定"auth key"的,也就是说,NTP中的这个漏洞是默认存在的

0x2: 漏洞源代码分析

\ntp-4.2.6p5\ntpd\ntp_config.c

static void config_auth(struct config_tree *ptree )
{
    ...
    u_char        digest[EVP_MAX_MD_SIZE];
    u_int        digest_len;
    /*
    typedef struct EVP_MD_CTX 
    {
        byte   macType;               // md5 or sha for now  
        Hasher hash;
    } EVP_MD_CTX;
    */
    EVP_MD_CTX    ctx;
    ...
    /* if doesn't exist, make up one at random */
    if (authhavekey(req_keyid))
    {
        req_keytype = cache_type;
#ifndef OPENSSL
        req_hashlen = 16;
#else    /* OPENSSL follows */
        EVP_DigestInit(&ctx, EVP_get_digestbynid(req_keytype));
        EVP_DigestFinal(&ctx, digest, &digest_len);
        req_hashlen = digest_len;
#endif
    } 
    else 
    {
        // when an auth key is not configured
        int    rankey;

        //这行代码是漏洞产生的关键,ntp_random()无法产生足够密文空间的密文
        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);
    }
    ...
}

我们继续跟进ntp_random()这个函数

\ntp-4.2.6p5\libntp\ntp_random.c

/*
 * random:
 *
 * If we are using the trivial TYPE_0 R.N.G., just do the old linear
 * congruential bit.  Otherwise, we do our fancy trinomial stuff, which is
 * the same in all the other cases due to all the global variables that have
 * been set up.  The basic operation is to add the number at the rear pointer
 * into the one at the front pointer.  Then both pointers are advanced to
 * the next location cyclically in the table.  The value returned is the sum
 * generated, reduced to 31 bits by throwing away the "least random" low bit.
 *
 * Note: the code takes advantage of the fact that both the front and
 * rear pointers can't wrap on the same call by not testing the rear
 * pointer if the front one has wrapped.
 *
 * Returns a 31-bit random number.
 */
long ntp_random( void )
{
    register long i;
    register long *f, *r;

    if (rand_type == TYPE_0) 
    {
        i = state[0];
        state[0] = i = (good_rand(i)) & 0x7fffffff;
    } 
    else 
    {
        /*
         * Use local variables rather than static variables for speed.
         */
        f = fptr; r = rptr;
        *f += *r;
        i = (*f >> 1) & 0x7fffffff;    /* chucking least random bit */
        if (++f >= end_ptr) {
            f = state;
            ++r;
        }
        else if (++r >= end_ptr) 
        {
            r = state;
        }

        fptr = f; rptr = r;
    }
    return(i);
}

\ntp-4.2.6p5\libntp\ntp_random.c

static inline long good_rand ( register long x )
{
#ifdef  USE_WEAK_SEEDING
/*
 * Historic implementation compatibility.
 * The random sequences do not vary much with the seed,
 * even with overflowing.
 */
    return (1103515245 * x + 12345);
#else   /* !USE_WEAK_SEEDING */
/*
 * Compute x = (7^5 * x) mod (2^31 - 1)
 * wihout overflowing 31 bits:
 *      (2^31 - 1) = 127773 * (7^5) + 2836
 * From "Random number generators: good ones are hard to find",
 * Park and Miller, Communications of the ACM, vol. 31, no. 10,
 * October 1988, p. 1195.
 */
    register long hi, lo;

    hi = x / 127773;
    lo = x % 127773;
    x = 16807 * lo - 2836 * hi;
    if (x <= 0)
        x += 0x7fffffff;
    return (x);
#endif  /* !USE_WEAK_SEEDING */
}

ntp_random产生了一个32bit的密文

0x3: 漏洞的攻击场景

这里的关键是ntp_random产生的key,是在哪里使用的,这决定了如何触发重现这个漏洞

0x4: 修复方案

Upgrade to 4.2.7p11

0x5: 攻防思考

从漏洞原理上来说,这个漏洞属于"初始种子SEED未指定,导致系统使用默认的内置初始SEED进行密钥序列生成,而这个使用默认初始SEED生成的密钥序列是攻击者可预测的"漏洞,类似的漏洞有

1. PHP的的rand()函数在没有显式调用srand()设置初始SEED的情况下,PHP将使用内置的默认SEED进行随机数生成,导致可预测漏洞
2. JAVA JDK 1.6之前的伪随机生成函数可预测漏洞

要避免这种漏洞的出现,我们可以从2个方面去思考

1. 使用良好的编程规范,对和密钥生成相关的随机数都必须在生产之前显式地进行种子SEED赋值
2. 在代码库底层就实现"安全伪随机数生成函数",即允许直接调用伪随机数生成函数,但是函数在底层自动实现了初始种子SEED的随机重置,PHP的mt_srand()就是一个很好的例子

Relevant Link:

http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-9293

 
2. CVE-2014-9294: non-cryptographic random number generator with weak seed used by ntp-keygen to generate symmetric keys

0x1: 触发条件

1. Prior to ntp-4.2.7p230

0x2: 漏洞源代码分析

\ntp-4.2.6p5\util\ntp-keygen.c
0x3: 漏洞的攻击场景

Prior to ntp-4.2.7p230 ntp-keygen used a weak seed to prepare a random number generator that was of good quality back in the late 1990s. The random numbers produced was then used to generate symmetric keys

0x4: 修复方案

Upgrade to 4.2.7p230

0x5: 攻防思考

Relevant Link:

http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-9294


3. CVE-2014-9295: Buffer overflow in crypto_recv()、Buffer overflow in ctl_putdata()、Buffer overflow in configure()

0x1: 触发条件
0x2: 漏洞源代码分析
0x3: 漏洞的攻击场景
0x4: 修复方案
0x5: 攻防思考


4. CVE-2014-9296: receive(): missing return on error

0x1: 触发条件
0x2: 漏洞源代码分析
0x3: 漏洞的攻击场景
0x4: 修复方案
0x5: 攻防思考

 

Copyright (c) 2014 LittleHann All rights reserved 

posted @ 2015-04-08 14:14  郑瀚Andrew  阅读(245)  评论(0编辑  收藏  举报