连某宝都中招的Heartbleed bug究竟是个什么东西?简单地说就是攻击者可以读最多64KB内存的内容。
读了这64KB能干嘛?用报这个bug的人的话来说:
Without using any privileged information or credentials we were able steal from ourselves the secret keys used for our X.509 certificates, user names and passwords, instant messages, emails and business critical documents and communication.
那么读取64KB内存和获取这么多关键信息究竟有什么关系呢?
The bug
先来看看patch里面的ssl/d1_both.c
:
1 2 3 4 5 6 7 |
|
可以看到,heartbeat里有一个 SSLv3 record的指针,这个record
的代码如下:
1 2 3 4 5 6 7 8 9 10 11 |
|
可以看到,每个record
有它的type
、length
和data
,规规矩矩。
回到dtls1_process_heartbeat
:
1 2 3 4 |
|
可以看到SSLv3 record
的第一个byte就是放这个heartbeat
的type
。 宏n2s
则是从p
里面取两个byte放到payload里面,被用来作为payload的长度。 注意这里并没有检查SSLv3 record
实际的长度。
接下来在这个函数里面干了下面这些事情:
1 2 3 4 5 6 7 8 9 |
|
可以看到,用户要多少程序就分配多少,最多可以分配到65535+1+2+16
,指针bp被用来操作这块内存。然后:
1 2 3 4 |
|
宏s2n
把n2s
做的操作恢复出来:先拿16个bit的值放到2个byte里面,也就是原来请求的payload的长度。然后把pl
里面放的payload(请求者提交的data)拷贝到新分配的bp
里面。
看起来是很平常的操作,只不过没有认真的检查用户输入而已,但问题也就在这里了。
Where is the bug
如果用户并没有正在提交声称的那么多个bytes的payload,那么memcpy就会读到同一个process里面SSLv3 record附近的内存内容。
这附近有哪些内容呢?
首先要明白在linux上,内存的动态分配主要是通过sbrk 或者是 mmap。如果内存是通过sbrk分配的,它会使用heap-grows-up
规则,泄露出来的东西不会那么多(但是如果是同时并发请求还是有东西会漏)。
在这里,pl
因为malloc里面的mmap_threshhold多半是sbrk分配的,但是,那些关键的用户数据,则多半是通过mmap分配内存。于是这些数据就会被攻击者用pl
拿到。如果再考虑并发请求,就…
The fix
所以,整个patch里面最主要的fix就是: * 检查是否有长度为0的虚假heartbeat * 检查record的真实长度
代码如下:
1 2 3 4 5 6 7 8 |
|
So?
这个bug大概算是影响这么剧烈的bug里面最好明白的一个,所以居然我也看明白了。感受:
- 为了可扩展性引入了复杂度,经常都会带来恶梦
- 用户的输入,无论如何都不能相信,一定要check
- C语言的确是大牛小牛都会踩到坑啊