articles icon indicating copy to clipboard operation
articles copied to clipboard

openssl CVE-2016-0799分析

Open xinali opened this issue 5 years ago • 0 comments

openssl CVE-2016-0799分析

环境准备

git clone https://github.com/openssl/openssl

漏洞分析

利用github直接搜索

1555943154416

可以看到存在解决这个问题的commit,进入

1555943313776

commit做了很完善的说明,那就根据commit说明来具体看一下为什么会出现这个问题,切换到其父commit

git checkout 069c3c0908dfa8418753d0c25890a9d4fb67178d

首先出现问题的最主要的函数是这个

static void
doapr_outch(char **sbuffer,
            char **buffer, size_t *currlen, size_t *maxlen, int c)
{
    /* If we haven't at least one buffer, someone has doe a big booboo */
    assert(*sbuffer != NULL || buffer != NULL);

    /* |currlen| must always be <= |*maxlen| */
    assert(*currlen <= *maxlen);

    if (buffer && *currlen == *maxlen) {
        *maxlen += 1024;
        if (*buffer == NULL) {
            *buffer = OPENSSL_malloc(*maxlen);
            if (*buffer == NULL) {
                /* Panic! Can't really do anything sensible. Just return */
                return;
            }
            if (*currlen > 0) {
                assert(*sbuffer != NULL);
                memcpy(*buffer, *sbuffer, *currlen);
            }
            *sbuffer = NULL;
        } else {
            *buffer = OPENSSL_realloc(*buffer, *maxlen);
            if (!*buffer) {
                /* Panic! Can't really do anything sensible. Just return */
                return;
            }
        }
    }

    if (*currlen < *maxlen) {
        if (*sbuffer)
            (*sbuffer)[(*currlen)++] = (char)c;
        else
            (*buffer)[(*currlen)++] = (char)c;
    }
    return;
}

这个函数可能会出现如下问题

1. 没有错误处理,导致错误
2. size_t溢出,导致错误

而且根据这里

 if (*currlen < *maxlen) {
        if (*sbuffer)
            (*sbuffer)[(*currlen)++] = (char)c;
        else
            (*buffer)[(*currlen)++] = (char)c;
    }

可以基本推测,该函数肯定是会被循环调用的。

考虑这么一种情况在

条件 结果
第一次buffer && *currlen == *maxlen执行后 *sbuffer=NULL
第二次buffer && *currlen == *maxlen执行后 如果relloc分配失败,*buffer=NULL

再次循环来到这里

if (*currlen < *maxlen) {
        if (*sbuffer)
            (*sbuffer)[(*currlen)++] = (char)c;
        else
            (*buffer)[(*currlen)++] = (char)c;
    }

*sbuffer==NULL,进入

(*buffer)[(*currlen)++] = (char)c;

*buffer==NULL,而currlen不可控,可直接导致内存被改写

总结

  1. 分配失败,尽量直接处理
  2. 考虑整数溢出的问题

参考

OpenSSL CVE-2016-0799: heap corruption via BIO_printf

xinali avatar Apr 23 '19 14:04 xinali