心脏滴血漏洞检测
2014年4月7日,心脏一个叫“心脏滴血”的滴血漏洞被公之于众。那天晚上,漏洞我正对着服务器日志排查一个奇怪的检测连接异常,突然看到群里有人甩出一条链接,心脏说OpenSSL出大事了。滴血点进去一看,漏洞CVE-2014-0160,检测心跳扩展模块里有个缓冲区过读,心脏攻击者能直接从服务器内存里读走64KB数据。滴血64KB不大,漏洞但反复读,检测就能把私钥、心脏会话凭证、滴血用户密码一点点拼出来。漏洞我当时就骂了一句——这玩意儿藏了两年多,居然没人发现。 心脏滴血的核心问题出在TLS心跳机制上。正常流程是客户端发一个心跳包,里面带一段数据和一个长度字段,服务器收到后把这段数据原样返回,证明连接还活着。但OpenSSL的实现里, 检测这个漏洞,最直接的办法是发一个畸形心跳包,看服务器返回的数据长度是否异常。我用Python写过一个不到20行的脚本,连上443端口,构造一个 实际排查中,我发现很多运维人员搞混了“检测”和“利用”。检测只需要确认漏洞存在,不需要真的把私钥读出来。有人用 修复方案没什么好说的,升级到OpenSSL 1.0.1g或更高版本。但升级之后必须做一件事:吊销并重新签发所有SSL证书,同时让所有用户重置密码。因为漏洞存在期间,私钥和会话Cookie可能已经被读走了。我认识一个管理员,升级完就以为万事大吉,结果三个月后被人用旧私钥解密了流量。心脏滴血最阴的地方就在这里——它不留痕迹。服务器日志里看不到异常,内存读取不会触发任何告警,你甚至不知道数据已经被偷了。 现在再回头看这个漏洞,它暴露的不只是代码问题。OpenSSL项目当时只有几个全职维护者,却支撑着半个互联网的加密通信。心脏滴血之后,社区才开始认真给开源基础设施捐钱。我后来养成一个习惯:每次部署新服务,先用memcpy的长度参数直接用了客户端声明的长度,却没检查这个长度是否超过实际数据长度。你发一个长度为1字节的心跳包,却声明长度是65535,服务器就会从内存里紧挨着这1字节的地方往后多读65534字节,打包返回给你。内存里有什么?可能是之前处理过的请求残留,可能是私钥片段,也可能是别的用户刚提交的表单数据。Heartbeat请求,把payload_length设成16384,实际只发1字节。如果服务器返回的数据包长度明显大于1,基本就能确认存在漏洞。这个检测过程不会对服务器造成损害,只是读内存,不写。但要注意,有些IDS会把这个行为标记为攻击,内网扫描前最好打个招呼。nmap的ssl-heartbleed脚本扫全网,结果触发了一堆告警。更稳妥的方式是先查OpenSSL版本。受影响的版本是1.0.1到1.0.1f,以及1.0.2-beta到1.0.2-beta1。但版本号可以伪装,最可靠的还是发心跳包实测。我见过一个案例,某台服务器版本显示1.0.1e,但实际打了补丁,检测脚本却误报。后来发现是发行版自己 backport 了修复,版本号没变。所以版本号只能作为参考,不能作为唯一依据。openssl version -a确认版本,再跑一遍心跳检测脚本。花不了两分钟,但能睡个安稳觉。
-
上一篇
-
下一篇
- 最近发表
- 随机阅读
- 搜索
-
- 友情链接
-