PolarSSL 未初始化内存导致远程命令执行

杀戮 (杂役) | 2015-01-20 17:00

0x00 简介

原文: https://www.certifiedsecure.com/polarssl-advisory/

相关报道:http://threatpost.com/potential-code-execution-flaw-haunts-polarssl-library/110505

PolarSSL 源码:https://github.com/polarssl/polarssl/

今天早些时候PolarSSL被爆出远程命令执行,嗯,应该是今天,PolarSSL是一个开源的ssl代码库,被相当多的开源项目使用,具体可以在以下这个网址看见,之后同学们就会觉得,卧槽是个大洞。

https://polarssl.org/kb/generic/projects-using-polarssl

该漏洞的利用可以通过使用特殊构造的 X.509 证书,当PolarSSL将证书进行解析时漏洞被触发。博主的意思似乎是 可以构造一个恶意服务器,或者一个恶意客户端,然后去玩坏别人,我个人倒是觉得他可能已经实践过了。

0x01 版本影响

PolarSSL >= PolarSSL 1.0

0x02 漏洞原因

漏洞代码 https://github.com/polarssl/polarssl/blob/master/library/asn1parse.c 244行 到 292 行

# asn1_get_sequence_of 解析 ASN1 ,  就当成解析 x.509证书就好了, ASN1是证书数据结构的一种形式。
int asn1_get_sequence_of( unsigned char **p,
                          const unsigned char *end,
                          asn1_sequence *cur,
                          int tag)
{
    int ret;
    size_t len;
    asn1_buf *buf;

    /* Get main sequence tag */
    if( ( ret = asn1_get_tag( p, end, &len,
            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
        return( ret );

    if( *p + len != end )
        return( POLARSSL_ERR_ASN1_LENGTH_MISMATCH );

    while( *p < end )
    {
        buf = &(cur->buf);
        buf->tag = **p;

        if( ( ret = asn1_get_tag( p, end, &buf->len, tag ) ) != 0 )
            return( ret );

        buf->p = *p;
        *p += buf->len;

        #分配和指定下一个指针的时候没有进行 零初始化(就是都设置成0),就添加入cur。
        if( *p < end )
        {
            cur->next = (asn1_sequence *) polarssl_malloc(
                 sizeof( asn1_sequence ) );

            if( cur->next == NULL )
                return( POLARSSL_ERR_ASN1_MALLOC_FAILED );

         #memset( cur->next, 0, sizeof( asn1_sequence ) );   这行是补丁,把cur->next设置成0

            cur = cur->next;
        }
    }

    /* Set final sequence entry's next pointer to NULL */
    cur->next = NULL;

    if( *p != end )
        return( POLARSSL_ERR_ASN1_LENGTH_MISMATCH );

    return( 0 );
}

因为没有进行零初始化,下次迭代的时候下面的代码会被触发

# asn1_get_tag获取tag和tag的长度,赋值给ret,如果不为0,将其返回。
if( ( ret = asn1_get_tag( p, end, &buf->len, tag ) ) != 0 )
     return( ret );

就是说链表的 最后一个 指针"NEXT" 从不进行初始化。

下面就是最后的处理代码:

漏洞代码: https://github.com/polarssl/polarssl/blob/master/library/x509_crt.c 2039行->2046行

seq_cur = cert_cur->ext_key_usage.next;
# 迭代链表,似乎是因为最后一个next未进行初始化导致内存可控。
while( seq_cur != NULL )
{
      seq_prv = seq_cur;
      seq_cur = seq_cur->next;
      polarssl_zeroize( seq_prv, sizeof( x509_sequence ) );
      polarssl_free( seq_prv );
}

牛逼哒哒的博主最后提出了两种利用方式,为经初始化的内容可以通过操纵堆分配进行控制,反过来说可以清除任意内存地址,或者在任意内存地址上触发free()。

关于利用的技巧可以参考下面两篇博客

[1]: The poisoned NUL byte, 2014 edition LINK (嘛,project zero最近真是无处不在)

[2]: Understanding the heap by breaking it LINK

[原文地址]