标签归档:openssl

OpenSSL 安全漏洞 CVE-2015-1793

OpenSSL 1.0.2d 和 OpenSSL 1.0.1p 发布,修复了一个安全问题(CVE-2015-1793)。安全级别:高影响的版本:OpenSSL 1.0.2c, 1.0.2b, 1.0.1n 和 1.0.1o。
详见描述:
2015.07.09, Version 0.10.40 (Maintenance)

openssl: upgrade to 1.0.1p (CVE-2015-1793)
V8: back-port JitCodeEvent patch from upstream (Ben Noordhuis)
win,msi: create npm folder in AppData directory (Steven Rockarts)

openssl heartbeat问题

openssl 官方网站4月7日的公布:有研究人员发现OpenSSL 1.0.1和1.0.2-beta版本中存在安全漏洞(编号为CVE-2014-0160),可能暴露密钥和私密通信,应该尽快修补,方法是:

升级到最新版本OpenSSL 1.0.1g
无法立即升级的用户可以以-DOPENSSL_NO_HEARTBEATS开关重新编译OpenSSL
1.0.2-beta版本的漏洞将在beta2版本修复
更老版本的OpenSSL(1.0.0和0.9.8等)反而不受影响

这个漏洞是由安全公司Codenomicon的研究人员和Google安全小组的Neel Mehta相互独立地发现的。漏洞出在OpenSSL对TLS的心跳扩展(RFC6520)的实现代码中,由于漏了一处边界检查,而可能在每次心跳中暴露客户端与服务器通信中的64K内存,这并不是设计错误。

Hacker News网友drv在阅读了漏洞代码后指出,这是一个低级错误。他解释说:

TLS心跳由一个请求包组成,其中包括有效载荷(payload),通信的另一方将读取这个包并发送一个响应,其中包含同样的载荷。在处理心跳请求的代码中,载荷大小是从攻击者可能控制的包中读取的:
openssl的漏洞的修复地址

可以看到漏洞从ssl/d1_both.c:开始修复

这是一条指向SSLv3记录中的数据的指针,结构体SSL3_RECORD的定义如下:
结构体SSL3_RECORD不是SSLv3记录的实际存储格式。一条SSLv3记录所遵循的存储格式如下

每条SSLv3的记录由type(类型),length和pointer to the record data(指向记录数据的指针)*data.

SSLv3记录的第一个字节表明了心跳包的类型,n2s从指针p指向的数组中提取前2个字节,并把它保存在payload变量中,实际上是心跳包载荷的长度length.这里没有检查SSLv3的实际长度。变量pl则是指向访问者实际提供的心跳包数据。
接着:

这段程序分配一段有访问者指定大小的内存区域,这段内存区域最大为65535+1+2+16个字节((2^16)-1,65535)
变量bp则指向了这段内存区域。
然后响应包是这样构造的:

s2n与n2s的功能相反,s2n读入一个16bit的值,然后将它存成双字节值,s2n会将与请求的心跳包载荷长度相同的值存入变量payload。然后程序从pl处开始复制payload个字节到新分配bp数组中,pl指向了用户提供的心跳包数据,然后,晨曦将所以的数据发回给用户。

这样一来,用户可以控制变量payload,以达到控制pl。
如果用户并没有在心跳包中提供足够多的数据,会导致什么问题呢。如果pl指向的数据实际长度只有一个字节,那么memcpy会把这条SSLv3记录之后的数据,无论这些数据是什么,都会被复制出来。
很明显,SSLv3记录附近有不少东西的。
当然,你也没办法读取其它进程的数据,所以“重要的商业文档”必须位于当前进程的内存区域中、小于64KB,并且刚好位于指针pl指向的内存块附近
修复代码中最重要的一部分如下:

这段代码干了两件事情:首先第一行语句抛弃了长度为0的心跳包,然后第二步检查确保了心跳包足够长。就这么简单。
顺便了解一下
我们可以通过在和ssl建立hello之后,发送一个短字节的心跳。我们建立一个hello的通信
客户问候消息(client hello)的结构如下:

client_version 客户端希望在此次对话中使用的SSL协议的版本。这应该是被客户
端所支持的最新的版本(最高值)。对于本文所描述的SSL协议,版
本号应该是3.0。(关于背景兼容信息请见附录E)。
random 一个客户端生成的随机结构。
session_id 客户端在此次连接中想使用的对话标识符(ID)。如果没有可用的
session—ID或者客户端想要生成新的加密参数,这个值应该为空。
cipher_suites 这是一个由客户端支持的,由客户端按其自身的偏爱而选定的加密套
接字的列表(列表的第一项是其最喜爱的),如果session_id 域非
空(暗示重新开始一已有的对话),则此向量必须至少包含来自已有
对话的cipher_suite。加密套接字的值的定义见附录A.6。
compression_methods 这是一个由客户端支持的压缩算法的列表,他根据客户端自身的偏
爱而选定的(列表的第一项是其最喜爱的),如果session_id 域非
空(暗示重新开始一已有的对话),则此向量必须至少包含一个来自
已有对话的compression_methods的参数。所有实现均必须支持
CompressionMethod.null。

继发送client hello消息之后,客户端等候一个服务器问候消息(server hello message)。除了hello消息外,由服务器返回的任何其他握手消息,均被视为致命错误(fatal error)。
发送的hello消息如下:

16 :代表records contains some handshake message data(建立握手信息) SSLv3
03 02 :TLS 1.0通常被标示为SSL 3.1,TLS 1.1为SSL 3.2,TLS 1.2为SSL 3.3。所以03 01表示SSL使用的版本:SSL 3.1AKA TLS 1.0,03 02对应SSL3.2
00 dc:2 bytes长度,代表消息长度
01:代表请求client请求
00 00 d8:代表clienthello的消息长度

可以用以下这个公式表示:
0×16 0×03 X Y Z 0×01 A B C
X #可能是0,1,2,3
Y Z #是消息报文长度
A B C #是客户端hello的消息长度。这个hello message开始于一个4个字节的报头,但未包含在这个长度里,应该是独自的记录。
所以你可以得到 A = 0; 256*X+Y = 256*B +C +4 也就是X*2^8 +y
上面的长度则是00*256+dc =220; 256*0+d8 + 4 =216+4 =220;后面的信息则是random+session_id+cipher_suites+compression_methods

16 03 02 00 dc #TLS 头部信息
01 00 00 d8 #握手信息
03 02 #[客户端hello区域]:主:03 从:02
53 43 5b 90 #[客户端hello区域] 时间4字节,2014年4月8日 上午10:14:40
00 #[客户端hello区域] 会话ID长度 0;
00 66 #[客户端hello区域] 加密套件长度102字节
01 #[客户端hello区域] 压缩支持长度1,length (1)
00 #[客户端hello区域]压缩支持,不压缩,no compression (0)
00 49#[客户端hello区域]压缩方法列表长度,73字节

同样的心跳信息如下:
18 03 02 00 03
01 40 00
18 #心跳类型
03 02 #TLS版本号
00 03 #心跳报文长度
01 #客户端请求
40 00 #代表payload 长度,2^14 =16384;

drv评述说:

很难相信OpenSSL的代码居然没有对字节流的处理做抽象,如果包用(指针,长度)对来表示,用简单的封装函数复制,就能避免这个漏洞。用C语言的时候,写这种问题代码太容易了,但API设计仔细一点,就会大大增加犯错的难度。

受影响的版本主要有:
OpenSSL 1.0.1f (受影响)
OpenSSL 1.0.2-beta (受影响)
OpenSSL 1.0.1g (不受影响)
OpenSSL 1.0.0 branch (不受影响)
OpenSSL 0.9.8 branch (不受影响)

建议进行版本更新,更新后重启服务,通过lsof -n | grep ssl | grep DEL列出需要重新启动服务,然后将列出的服务做重启。
建议重新生成ssl key,避免原先的key已被窃取

openssl 生成证书的报错处理

1 生成证书报错为:
Error:Serial number 01 has already been issued,check the database/serial_file for corruption the matching entry has the fallowing details;
这个错误主要是服务器上产生多个证书,需要修改生成证书的序列号。
查看这些信息存放目录,在文件openssl.cnf文件中
vim /etc/pki/tls/openssl.cnf
[ CA_default ]
dir = /etc/pki/CA

在这个目录下:serial内容为00 需要修改当前的数字,使用16进制数字 如 echo “0E” > serial

2 生成证书错误为:
filed to update database
TXT_DB error number 2
该错误解决方法有2种:1在ca目录下,将index.text.addr 中的 unique_subject = yes 修改为 unique_subject = no
2 是删除 index.txt 然后创建一个新的index.txt

编译支持证书openssl库的问题

编译支持证书openssl库的时候,出现DSO linker问题

检查一下是否支持该选项

如果支持的话,可以在ld.so.conf,添加/lib64 ,或者使用ldconfig